From bd9a0f03d81544ff93dfe6900d839d3e944421b2 Mon Sep 17 00:00:00 2001 From: Dreaded_X Date: Thu, 16 Apr 2020 22:11:41 +0200 Subject: [PATCH] Implemented scrolling when text reaches bottom of screen --- HDMI.alp | 3 +- constraint/hdmi2.ucf | 8 ++ constraint/z80.ucf | 20 ++++ source/mojo_top.v | 225 ++++++++++++++++++++++++++----------------- 4 files changed, 169 insertions(+), 87 deletions(-) create mode 100644 constraint/hdmi2.ucf create mode 100644 constraint/z80.ucf diff --git a/HDMI.alp b/HDMI.alp index 668f553..681dfbe 100644 --- a/HDMI.alp +++ b/HDMI.alp @@ -17,7 +17,8 @@ cclk_detector.luc tmds_encoder.luc mojo.ucf - hdmi.ucf + hdmi2.ucf + z80.ucf ..\clk_wiz_v3_6.v diff --git a/constraint/hdmi2.ucf b/constraint/hdmi2.ucf new file mode 100644 index 0000000..2cdfb86 --- /dev/null +++ b/constraint/hdmi2.ucf @@ -0,0 +1,8 @@ +NET "hdmi1_tmds(3)" LOC = "P144" |IOSTANDARD = TMDS_33 | CLOCK_DEDICATED_ROUTE = FALSE ; # Clock +NET "hdmi1_tmdsb(3)" LOC = "P143" |IOSTANDARD = TMDS_33 | CLOCK_DEDICATED_ROUTE = FALSE ; +NET "hdmi1_tmds(2)" LOC = "P138" |IOSTANDARD = TMDS_33 ; # Red +NET "hdmi1_tmdsb(2)" LOC = "P137" |IOSTANDARD = TMDS_33 ; +NET "hdmi1_tmds(1)" LOC = "P140" |IOSTANDARD = TMDS_33 ; # Green +NET "hdmi1_tmdsb(1)" LOC = "P139" |IOSTANDARD = TMDS_33 ; +NET "hdmi1_tmds(0)" LOC = "P142" |IOSTANDARD = TMDS_33 ; # Blue +NET "hdmi1_tmdsb(0)" LOC = "P141" |IOSTANDARD = TMDS_33 ; \ No newline at end of file diff --git a/constraint/z80.ucf b/constraint/z80.ucf new file mode 100644 index 0000000..b2632e0 --- /dev/null +++ b/constraint/z80.ucf @@ -0,0 +1,20 @@ +NET "z80_clk" LOC = P23 | IOSTANDARD = LVTTL; +NET "z80_data(2)" LOC = P114 | IOSTANDARD = LVTTL; +NET "z80_data(3)" LOC = P115 | IOSTANDARD = LVTTL; +NET "z80_data(1)" LOC = P116 | IOSTANDARD = LVTTL; +NET "z80_data(0)" LOC = P117 | IOSTANDARD = LVTTL; +NET "z80_data(4)" LOC = P118 | IOSTANDARD = LVTTL; +NET "z80_data(5)" LOC = P119 | IOSTANDARD = LVTTL; +NET "z80_data(6)" LOC = P120 | IOSTANDARD = LVTTL; +NET "z80_data(7)" LOC = P121 | IOSTANDARD = LVTTL; +// NET "z80_address(0)" LOC = P9 | IOSTANDARD = LVTTL; +// NET "z80_address(1)" LOC = P10 | IOSTANDARD = LVTTL; +// NET "z80_address(2)" LOC = P11 | IOSTANDARD = LVTTL; +// NET "z80_address(3)" LOC = P12 | IOSTANDARD = LVTTL; +// NET "z80_address(4)" LOC = P13 | IOSTANDARD = LVTTL; +// NET "z80_address(5)" LOC = P14 | IOSTANDARD = LVTTL; +// NET "z80_address(6)" LOC = P15 | IOSTANDARD = LVTTL; +// NET "z80_address(7)" LOC = P16 | IOSTANDARD = LVTTL; +NET "z80_ioreq" LOC = P24 | IOSTANDARD = LVTTL; +NET "z80_wr" LOC = P21 | IOSTANDARD = LVTTL; +NET "z80_m1" LOC = P22 | IOSTANDARD = LVTTL; diff --git a/source/mojo_top.v b/source/mojo_top.v index 72b22dc..c91e1df 100644 --- a/source/mojo_top.v +++ b/source/mojo_top.v @@ -19,8 +19,14 @@ module mojo_top( output avr_rx, // AVR Rx => FPGA Tx input avr_rx_busy, // AVR Rx buffer full output[3:0] hdmi1_tmds, - output[3:0] hdmi1_tmdsb - ); + output[3:0] hdmi1_tmdsb, + input z80_clk, + input[7:0] z80_data, + // input[7:0] z80_address, + input z80_ioreq, + input z80_wr, + input z80_m1 + ); wire rst = ~rst_n; // make reset active high @@ -36,7 +42,7 @@ module mojo_top( .CLK_IN1(clk), .CLK_OUT1(hdmi_clk) ); - + localparam SCALE = 2; localparam WIDTH = 1280; localparam HEIGHT = 720; @@ -47,7 +53,7 @@ module mojo_top( // @todo 1080p30 does not work for some reason (already extended number of bits) hdmi_encoder #(.Y_RES(HEIGHT), .X_RES(WIDTH), .Y_FRAME(HEIGHT+30), .X_FRAME(WIDTH+387)) hdmi( - // hdmi_encoder #(.Y_RES(HEIGHT), .X_RES(WIDTH), .Y_FRAME(HEIGHT+45), .X_FRAME(WIDTH+303)) hdmi( + // hdmi_encoder #(.Y_RES(HEIGHT), .X_RES(WIDTH), .Y_FRAME(HEIGHT+45), .X_FRAME(WIDTH+303)) hdmi( .clk(hdmi_clk), .rst(rst), .tmds(hdmi1_tmds), @@ -61,7 +67,7 @@ module mojo_top( wire [29:0] char_data [94:0]; - assign char_data[0] = 30'h00000000; // + assign char_data[0] = 30'h00000000; // assign char_data[1] = 30'h1CE7380E; // ! assign char_data[2] = 30'h14A00000; // " assign char_data[3] = 30'hAFABEA; // # @@ -158,83 +164,91 @@ module mojo_top( assign char_data[94] = 30'hAA0000; // ~ reg[13:0] char_index_q, char_index_d; - + reg[10:0] charx; reg[9:0] chary; - + reg[7:0] tx_data; reg new_tx_data; wire tx_busy; wire[7:0] rx_data; wire new_rx_data; - + reg[5:0] char_color; + reg char_attribute; + assign led[7:0] = rx_data; - + avr_interface #(.CLK_FREQ(75000000)) vr_interface ( - .clk(hdmi_clk), - .rst(rst), - .cclk(cclk), - .spi_miso(spi_miso), - .spi_mosi(spi_mose), - .spi_sck(spi_sck), - .spi_ss(spi_ss), - .spi_channel(spi_channel), - .tx(avr_rx), - .rx(avr_tx), - .channel(4'd15), - .new_sample(), - .sample(), - .sample_channel(), - .tx_data(tx_data), - .new_tx_data(new_tx_data), - .tx_busy(tx_busy), - .tx_block(avr_rx_busy), - .rx_data(rx_data), - .new_rx_data(new_rx_data) + .clk(hdmi_clk), + .rst(rst), + .cclk(cclk), + .spi_miso(spi_miso), + .spi_mosi(spi_mose), + .spi_sck(spi_sck), + .spi_ss(spi_ss), + .spi_channel(spi_channel), + .tx(avr_rx), + .rx(avr_tx), + .channel(4'd15), + .new_sample(), + .sample(), + .sample_channel(), + .tx_data(tx_data), + .new_tx_data(new_tx_data), + .tx_busy(tx_busy), + .tx_block(avr_rx_busy), + .rx_data(rx_data), + .new_rx_data(new_rx_data) ); - + reg [13:0] addr_q, addr_d; + reg [6:0] scroll_q, scroll_d; reg[7:0] write_data; reg write_enable; wire[7:0] sram_read_data; sram #(.SIZE(8), .DEPTH(CHAR_HMAX*CHAR_VMAX)) sram( - .clk(hdmi_clk), - .read_address(char_index_q), - .write_address(addr_q), - .read_data(sram_read_data), - .write_data(write_data), - .write_en(write_enable) + .clk(hdmi_clk), + .read_address(char_index_q), + .write_address(addr_q), + .read_data(sram_read_data), + .write_data(write_data), + .write_en(write_enable) ); - + always @(*) begin - // @todo For some reason we need a -1 here, otherwise it looks weird with - // SCALE = 1 - // Need to figure that out, something to do with wrap around - charx = (hdmix >> (SCALE-1)) % 8; - chary = (hdmiy >> (SCALE-1)) % 8; - - char_index_d = ((hdmix >> (SCALE+2)) + CHAR_HMAX*(hdmiy >> (SCALE+2))); - - if (char_index_d[6] == 1) begin - hdmired = 8'h55 * char_index_d[1:0]; - hdmigreen = 8'h55 * char_index_d[3:2]; - hdmiblue = 8'h55 * char_index_d[5:4]; - end else begin - hdmired = 1'b0; - hdmigreen = 1'b0; - hdmiblue = 1'b0; - end - + // @todo For some reason we need a -1 here, otherwise it looks weird with + // SCALE = 1 + // Need to figure that out, something to do with wrap around + charx = (hdmix >> (SCALE-1)) % 8; + chary = (hdmiy >> (SCALE-1)) % 8; + + char_index_d = ((hdmix >> (SCALE+2)) + CHAR_HMAX*(hdmiy >> (SCALE+2)) + CHAR_HMAX*scroll_q) % (CHAR_HMAX*CHAR_VMAX); + + //char_color = char_index_d[5:0]; + char_color = 6'b111111; + //char_attribute = char_index_d[6]; + char_attribute = 1'b0; + + if (char_attribute == 1) begin + hdmired = 8'h55 * char_color[1:0]; + hdmigreen = 8'h55 * char_color[3:2]; + hdmiblue = 8'h55 * char_color[5:4]; + end else begin + hdmired = 1'b0; + hdmigreen = 1'b0; + hdmiblue = 1'b0; + end + if (charx > 0 && charx < 6 && chary > 0 && chary < 7 && char_data[sram_read_data][29 - (charx - 1) - 5*(chary - 1)] == 1) begin - if (char_index_d[6] == 1) begin - hdmired = 1'b0; - hdmigreen = 1'b0; - hdmiblue = 1'b0; - end else begin - hdmired = 8'h55 * char_index_d[1:0]; - hdmigreen = 8'h55 * char_index_d[3:2]; - hdmiblue = 8'h55 * char_index_d[5:4]; - end + if (char_attribute == 1) begin + hdmired = 1'b0; + hdmigreen = 1'b0; + hdmiblue = 1'b0; + end else begin + hdmired = 8'h55 * char_color[1:0]; + hdmigreen = 8'h55 * char_color[3:2]; + hdmiblue = 8'h55 * char_color[5:4]; + end end frame_d = frame_q; @@ -242,35 +256,74 @@ module mojo_top( if (hdmix == WIDTH-1 && hdmiy == HEIGHT-1) begin frame_d = frame_q + 1'b1; end - - new_tx_data = 1'b0; - write_enable = 1'b0; - write_data = 1'b0; - addr_d = addr_q; - if (new_rx_data) begin - new_tx_data = 1'b1; - tx_data = rx_data; - - if (rx_data == "\r") begin - end else if (rx_data == "\n") begin - addr_d = addr_q - (addr_q % CHAR_HMAX) + CHAR_HMAX; - end else if (rx_data == 8) begin - addr_d = addr_q - 1'b1; - end else begin - write_enable = 1'b1; - write_data = rx_data - 32; - addr_d = addr_q + 1'b1; - end - end + + // new_tx_data = 1'b0; + // write_enable = 1'b0; + // write_data = 1'b0; + // addr_d = addr_q; + // if (new_rx_data) begin + // new_tx_data = 1'b1; + // tx_data = rx_data; + // + // if (rx_data == "\r") begin + // end else if (rx_data == "\n") begin + // addr_d = addr_q - (addr_q % CHAR_HMAX) + CHAR_HMAX; + // end else if (rx_data == 8) begin + // addr_d = addr_q - 1'b1; + // end else begin + // write_enable = 1'b1; + // write_data = rx_data - 32; + // addr_d = addr_q + 1'b1; + // end + // end end + + reg bottom_of_screen_q, bottom_of_screen_d; + always @(posedge z80_clk) begin + write_enable = 1'b0; + write_data = 1'b0; + addr_d = addr_q; + scroll_d = scroll_q; + bottom_of_screen_d = bottom_of_screen_q; + + // if (z80_ioreq != 1 && z80_m1 != 0 && z80_address[7:0] == 8'h10) begin + if (z80_ioreq != 1 && z80_m1 != 0 && z80_wr != 1) begin + if (z80_data == "\r") begin + addr_d = addr_q - (addr_q % CHAR_HMAX); + end else if (z80_data == "\n") begin + addr_d = addr_q + CHAR_HMAX; + end else begin + write_enable = 1'b1; + write_data = z80_data - 32; + addr_d = addr_q + 1'b1; + end + + if (bottom_of_screen_d == 1 && addr_d >= CHAR_HMAX*scroll_q) begin + scroll_d = (scroll_q + 1'b1) % CHAR_VMAX; + end + + if (addr_d >= CHAR_HMAX*CHAR_VMAX) begin + bottom_of_screen_d = 1'b1; + addr_d = addr_d - CHAR_HMAX*CHAR_VMAX; + end + + end + end + always @(posedge hdmi_clk) begin if (rst) begin frame_q <= 1'b0; char_index_q <= 1'b0; - addr_q <= 1'b0; + addr_q <= 1'b0; + scroll_q <= 1'b0; + bottom_of_screen_q <= 1'b0; end else begin - addr_q <= addr_d; + if (z80_ioreq == 1) begin + addr_q <= addr_d; + scroll_q <= scroll_d; + bottom_of_screen_q <= bottom_of_screen_d; + end frame_q <= frame_d; char_index_q <= char_index_d; end