From 6ea12e71f1ea517b070dad777200294d0aa1a2cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aitor=20G=C3=B3mez?= Date: Sun, 12 Mar 2023 17:33:42 +0100 Subject: [PATCH] Hercules CRTC updated to UM6845R Thank you @gyurco for the idea and the tips for implementation. --- rtl/video/crtc6845.v | 287 ------------------------------------------- rtl/video/hgc.v | 47 +++---- rtl/video/video.qip | 1 - 3 files changed, 26 insertions(+), 309 deletions(-) delete mode 100644 rtl/video/crtc6845.v diff --git a/rtl/video/crtc6845.v b/rtl/video/crtc6845.v deleted file mode 100644 index 6ace511..0000000 --- a/rtl/video/crtc6845.v +++ /dev/null @@ -1,287 +0,0 @@ -// Graphics Gremlin -// -// Copyright (c) 2021 Eric Schlaepfer -// This work is licensed under the Creative Commons Attribution-ShareAlike 4.0 -// International License. To view a copy of this license, visit -// http://creativecommons.org/licenses/by-sa/4.0/ or send a letter to Creative -// Commons, PO Box 1866, Mountain View, CA 94042, USA. -// -`default_nettype wire -module crtc6845( - input clk, - input divclk, - - // ISA bus - input cs, - input a0, - input write, - input read, - input[7:0] bus, - output reg [7:0] bus_out, - - input lock, - output std_hsyncwidth, - - // Video control signals - output hsync, - output vsync, - output hblank, - output vblank, - output vblank_border, - output display_enable, - output cursor, - output [13:0] mem_addr, - output [4:0] row_addr, - output line_reset); - - parameter H_TOTAL = 0; - parameter H_DISP = 0; - parameter H_SYNCPOS = 0; - parameter H_SYNCWIDTH = 0; - parameter V_TOTAL = 0; - parameter V_TOTALADJ = 0; - parameter V_DISP = 0; - parameter V_SYNCPOS = 0; - parameter V_MAXSCAN = 0; - parameter C_START = 0; - parameter C_END = 0; - - reg[4:0] cur_addr; - - // Address register - always @ (posedge clk) begin - if (~a0 & write & cs) begin - cur_addr <= bus[4:0]; - end - end - - // Register file - always @ (posedge clk) begin - if (a0 & write & cs & (~lock | (cur_addr > 5'd9))) begin - case (cur_addr) - 5'd0: h_total <= bus; - 5'd1: h_disp <= bus; - 5'd2: h_syncpos <= bus; - 5'd3: h_syncwidth <= bus[3:0]; - 5'd4: v_total <= bus[6:0]; - 5'd5: v_totaladj <= bus[4:0]; - 5'd6: v_disp <= bus[6:0]; - 5'd7: v_syncpos <= bus[6:0]; - // Register 8 not implemented - 5'd9: v_maxscan <= bus[4:0]; - 5'd10: c_start <= bus[6:0]; - 5'd11: c_end <= bus[4:0]; - 5'd12: start_a_1[13:8] <= bus[5:0]; - 5'd13: start_a_1[7:0] <= bus; - 5'd14: cursor_a[13:8] <= bus[5:0]; - 5'd15: cursor_a[7:0] <= bus; - default: ; - endcase - end - end - // TODO: Add light pen register (optional) - always @ (*) - begin - case (cur_addr) - 5'd0: bus_out <= h_total; - 5'd1: bus_out <= h_disp; - 5'd2: bus_out <= h_syncpos; - 5'd3: bus_out <= h_syncwidth; - 5'd4: bus_out <= v_total; - 5'd5: bus_out <= v_totaladj; - 5'd6: bus_out <= v_disp; - 5'd7: bus_out <= v_syncpos; - 5'd8: bus_out <= 8'h00; - 5'd9: bus_out <= v_maxscan; - 5'd10: bus_out <= c_start; - 5'd11: bus_out <= c_end; - 5'd12: bus_out <= {2'b00, start_a[13:8]}; - 5'd13: bus_out <= start_a[7:0]; - 5'd14: bus_out <= {2'b00, cursor_a[13:8]}; - 5'd15: bus_out <= cursor_a[7:0]; - 5'd16: bus_out <= 8'h00; // Light pen regs - 5'd17: bus_out <= 8'h00; - default: bus_out <= 8'h00; - endcase; - end - -// TODO: parameterize these defaults - reg [7:0] h_total = H_TOTAL; //R0 97 - reg [7:0] h_disp = H_DISP; //R1 80 - reg [7:0] h_syncpos = H_SYNCPOS; //R2 82 - reg [3:0] h_syncwidth = H_SYNCWIDTH; //R3 15 - - reg [6:0] v_total = V_TOTAL; //R4 25 - reg [4:0] v_totaladj = V_TOTALADJ; //R5 6 - reg [6:0] v_disp = V_DISP; //R6 25 - reg [6:0] v_syncpos = V_SYNCPOS; //R7 25 - reg [4:0] v_maxscan = V_MAXSCAN; //R9 13 - - reg [6:0] c_start = C_START; //R10 11 - reg [4:0] c_end = C_END; //R11 12 - - reg [13:0] start_a = 14'd0; //R13/R14 - reg [13:0] start_a_1 = 14'd0; //R13/R14 - - reg [13:0] cursor_a = 14'd92; //R14/R15 - - // Counters - reg [7:0] h_count = 8'd0; - reg [3:0] h_synccount = 4'd1; // Must start at 1 - reg [4:0] v_scancount = 5'd0; - reg [6:0] v_rowcount = 7'd0; - reg [3:0] v_synccount = 4'd0; - reg [4:0] cursor_counter = 5'd0; // Cursor blink - - - wire [4:0] next_v_scancount; - wire [13:0] ma = 14'd0; - reg [13:0] ma_rst = 14'd0; // Column reset of memory address - - reg [1:0] vs_del; - reg vs = 1'b0; - reg hs = 1'b0; - reg hdisp = 1'b1; - reg vdisp = 1'b1; - reg vdisp_border = 1'b1; - reg [12:0] hdisp_del; - - wire cur_on; - wire blink; - - wire h_end; - wire v_end; - - assign std_hsyncwidth = (h_syncwidth == 4'hA); - - assign vsync = vs; - assign hsync = hs; - assign display_enable = hdisp & vdisp; - assign hblank = ~hdisp; - assign vblank = ~vdisp; - assign vblank_border = ~vdisp_border; - - assign row_addr = v_scancount; - - assign h_end = (h_count == h_total); - - assign line_reset = h_end; - - // Horizontal counter - always @ (posedge clk) - begin - if (divclk) begin - if (h_count == h_total) begin - h_count <= 8'd0; - hdisp <= 1'b1; - end else begin - h_count <= h_count + 1'b1; - // Blanking - if (h_count + 1 == h_disp) begin - hdisp <= 1'b0; - end - // Sync output - if (h_count + 1 == h_syncpos) begin - hs <= 1'b1; - end - end - end - - // Horizontal sync timer - if (divclk & hs) begin - if (h_synccount == h_syncwidth) begin - h_synccount <= 4'b1; - hs <= 1'b0; - end else begin - h_synccount <= h_synccount + 4'b1; - end - end - end - - - assign v_end = (v_rowcount == v_total) & - (v_scancount == v_maxscan + v_totaladj); - - // Vertical counter - always @ (posedge clk) - begin - if (divclk & (h_count == h_total)) begin // was h_syncpos - - vs_del <= {vs_del[0], vs}; - - // Handle vertical border blanking - if ((v_rowcount + 1 == v_syncpos) && (v_scancount + 1 == v_maxscan)) - vdisp_border <= 1'b0; - - if (v_rowcount != v_total) begin - // Vertical count event - if (v_scancount != v_maxscan) begin - v_scancount <= v_scancount + 1'b1; - end else begin - v_scancount <= 0; - v_rowcount <= v_rowcount + 1'b1; - - // Handle vertical pulse - if (v_rowcount + 1 == v_syncpos) begin - vs <= 1'b1; - end - - // Handle blanking - if (v_rowcount + 1 == v_disp) begin - vdisp <= 1'b0; - end - end - end else begin - // Pad with vertical adjust - - if (v_scancount != v_maxscan + v_totaladj) begin - v_scancount <= v_scancount + 1'b1; - - end else begin - - v_scancount <= 0; - v_rowcount <= 0; - vdisp <= 1'b1; - cursor_counter <= cursor_counter + 1'b1; - start_a <= start_a_1; - end - end - - // Vertical sync pulse is fixed at 16 scan line times - // Vsync pulse turns off after 16 lines - if (vs) begin - if (v_synccount == 4'd15) begin - v_synccount <= 4'd0; - vs <= 0; - end else begin - v_synccount <= v_synccount + 1'b1; - end - end - else if (vs_del == 2'b10) vdisp_border <= 1'b1; - - end - end - - // Cursor - assign cur_on = (v_scancount >= c_start[4:0]) & - (v_scancount <= c_end[4:0]); - assign blink = (c_start[6:5] == 2'b00) | - (c_start[5] ? cursor_counter[4] : cursor_counter[3]); - assign cursor = (cursor_a == mem_addr) & cur_on & - blink & (c_start[6:5] != 2'b01) & display_enable; - - // Memory address generator - assign mem_addr = start_a + ma_rst + {6'b000000, h_count}; - always @ (posedge clk) - begin - if (divclk & (v_end | h_end)) begin - if (v_end) begin - ma_rst <= 14'd0; - end else begin - if (v_scancount == v_maxscan) begin - ma_rst <= ma_rst + {6'b000000, h_disp}; - end - end - end - end -endmodule diff --git a/rtl/video/hgc.v b/rtl/video/hgc.v index 8e638e4..4582928 100644 --- a/rtl/video/hgc.v +++ b/rtl/video/hgc.v @@ -168,28 +168,33 @@ module hgc( end end - // CRT controller (MC6845 compatible) - crtc6845 crtc ( - .clk(clk), - .divclk(crtc_clk), - .cs(crtc_cs), - .a0(bus_a[0]), - .write(~bus_iow_synced_l), - .read(~bus_ior_synced_l), - .bus(bus_d), - .bus_out(bus_out_crtc), -// .lock(HGC_70HZ == 1), - .lock(1'b0), - .hsync(hsync_int), - .vsync(vsync_l), - .hblank(hblank), - .vblank(vblank), - .display_enable(display_enable), - .cursor(cursor), - .mem_addr(crtc_addr), - .row_addr(row_addr) - ); + UM6845R crtc ( + .CLOCK(clk), + .CLKEN(crtc_clk), + // .nCLKEN(), + .nRESET(1'b1), + .CRTC_TYPE(1'b1), + + .ENABLE(1'b1), + .nCS(~crtc_cs), + .R_nW(bus_iow_synced_l), + .RS(bus_a[0]), + .DI(bus_d), + .DO(bus_out_crtc), + + .hblank(hblank), + .vblank(vblank), + + .VSYNC(vsync_l), + .HSYNC(hsync_int), + .DE(display_enable), + // .FIELD(), + .CURSOR(cursor), + + .MA(crtc_addr), + .RA(row_addr) + ); // if (HGC_70HZ) begin defparam crtc.H_TOTAL = 8'd99; diff --git a/rtl/video/video.qip b/rtl/video/video.qip index 0450708..24c69f3 100644 --- a/rtl/video/video.qip +++ b/rtl/video/video.qip @@ -5,7 +5,6 @@ set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hgc_att set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) hgc.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) vram.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) UM6845R.v ] -set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) crtc6845.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) cga_vram.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) cga_vgaport.v ] set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) cga_sequencer.v ]