module mojo_top( // 50MHz clock input input clk, // Input from reset button (active low) input rst_n, // cclk input from AVR, high when AVR is ready input cclk, // Outputs to the 8 onboard LEDs output[7:0]led, // AVR SPI connections output spi_miso, input spi_ss, input spi_mosi, input spi_sck, // AVR ADC channel select output [3:0] spi_channel, // Serial connections input avr_tx, // AVR Tx => FPGA Rx 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, 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 wire hdmi_clk; reg[7:0] hdmired, hdmigreen, hdmiblue; wire[11:0] hdmix; wire[10:0] hdmiy; reg[7:0] frame_q, frame_d; clk_wiz_v3_6 clk_wiz( .CLK_IN1(clk), .CLK_OUT1(hdmi_clk) ); localparam SCALE = 2; localparam WIDTH = 1280; localparam HEIGHT = 720; // localparam WIDTH = 1920; // localparam HEIGHT = 1080; localparam CHAR_HMAX = WIDTH / (SCALE*8); localparam CHAR_VMAX = HEIGHT / (SCALE*8); // @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( .clk(hdmi_clk), .rst(rst), .tmds(hdmi1_tmds), .tmdsb(hdmi1_tmdsb), .x(hdmix), .y(hdmiy), .red(hdmired), .green(hdmigreen), .blue(hdmiblue) ); wire [29:0] char_data [94:0]; assign char_data[0] = 30'h00000000; // assign char_data[1] = 30'h1CE7380E; // ! assign char_data[2] = 30'h14A00000; // " assign char_data[3] = 30'hAFABEA; // # assign char_data[4] = 30'h8FA38BE; // $ assign char_data[5] = 30'h19D1173; // % assign char_data[6] = 30'h1905324D; // & assign char_data[7] = 30'h8400000; // ' assign char_data[8] = 30'hCC63186; // ( assign char_data[9] = 30'h186318CC; // ) assign char_data[10] = 30'h4ABAA4; // * assign char_data[11] = 30'h427C84; // + assign char_data[12] = 30'h0x8C; // , assign char_data[13] = 30'h3800; // - assign char_data[14] = 30'hC; // . assign char_data[15] = 30'hC663318; // / assign char_data[16] = 30'h3FBDEF7F; // 0 assign char_data[17] = 30'h3C6318DF; // 1 assign char_data[18] = 30'h3E3FE31F; // 2 assign char_data[19] = 30'h3E378C7F; // 3 assign char_data[20] = 30'h37BF8C63; // 4 assign char_data[21] = 30'h3F8F8C7F; // 5 assign char_data[22] = 30'h3F8FEF7F; // 6 assign char_data[23] = 30'h3E33318C; // 7 assign char_data[24] = 30'h3FBFEF7F; // 8 assign char_data[25] = 30'h3FBF8C7F; // 9 assign char_data[26] = 30'hC00180; // : assign char_data[27] = 30'hC00198; // ; assign char_data[28] = 30'h666186; // < assign char_data[29] = 30'h701C0; // = assign char_data[30] = 30'hC30CCC; // > assign char_data[31] = 30'h3C31B80C; // ? assign char_data[32] = 30'h1D1BDE0F; // @ assign char_data[33] = 30'h1DBDFF7B; // A assign char_data[34] = 30'h3DBF6F7E; // B assign char_data[35] = 30'h1DBC636E; // C assign char_data[36] = 30'h3DBDEF7E; // D assign char_data[37] = 30'h1F8F630F; // E assign char_data[38] = 30'h1F8F6318; // F assign char_data[39] = 30'h1F8C6F6F; // G assign char_data[40] = 30'h37BFEF7B; // H assign char_data[41] = 30'h3CC6319E; // I assign char_data[42] = 30'h3E6318DC; // J assign char_data[43] = 30'h37BE6F7B; // K assign char_data[44] = 30'h318C631F; // L assign char_data[45] = 30'h37FFEF7B; // M assign char_data[46] = 30'h3DBDEF7B; // N assign char_data[47] = 30'h1DBDEF6E; // O assign char_data[48] = 30'h3DBDFB18; // P assign char_data[49] = 30'h1DBDEFCF; // Q assign char_data[50] = 30'h3DBDF37B; // R assign char_data[51] = 30'h1F870C7E; // S assign char_data[52] = 30'h3EC6318C; // T assign char_data[53] = 30'h37BDEF6E; // U assign char_data[54] = 30'h37BDEDC4; // V assign char_data[55] = 30'h37BDFFFB; // W assign char_data[56] = 30'h37B26F7B; // X assign char_data[57] = 30'h37BF8C7E; // Y assign char_data[58] = 30'h3E33331F; // X assign char_data[59] = 30'h1CC6318E; // [ assign char_data[60] = 30'h18C31863; // \ assign char_data[61] = 30'h1C6318CE; // ] assign char_data[62] = 30'h8A00000; // ^ assign char_data[63] = 30'h1F; // _ assign char_data[64] = 30'h10400000; // ` assign char_data[65] = 30'h7EF7D; // a assign char_data[66] = 30'h318F6F7F; // b assign char_data[67] = 30'h7E30F; // c assign char_data[68] = 30'h637EF6F; // d assign char_data[69] = 30'h76F8F; // e assign char_data[70] = 30'hEC67D8C; // f assign char_data[71] = 30'h1FBDBC7E; // g assign char_data[72] = 30'h318F6F7B; // h assign char_data[73] = 30'h18063186; // i assign char_data[74] = 30'hC6318DC; // j assign char_data[75] = 30'h31BD735B; // k assign char_data[76] = 30'h18C63186; // l assign char_data[77] = 30'h57F7B; // m assign char_data[78] = 30'hF6F7B; // n assign char_data[79] = 30'h7EF7E; // o assign char_data[80] = 30'h3DBDFB18; // p assign char_data[81] = 30'h1FBDBC63; // q assign char_data[82] = 30'h76F18; // r assign char_data[83] = 30'h7F0FE; // s assign char_data[84] = 30'h18CF3186; // t assign char_data[85] = 30'hDEF6F; // u assign char_data[86] = 30'hDED44; // v assign char_data[87] = 30'hDEFEA; // w assign char_data[88] = 30'hDBB7B; // x assign char_data[89] = 30'h37BDBC6E; // y assign char_data[90] = 30'hF999F; // z assign char_data[91] = 30'h623086; // { assign char_data[92] = 30'h421084; // | assign char_data[93] = 30'h610C46; // } 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) ); reg [13:0] addr_q, addr_d, addr_t, addr_n, addr_r, addr_b; reg[7:0] write_data_q, write_data_d; reg[7:0] last_input_q, last_input_d; reg[16:0] bottom_q, bottom_d, bottom_t; reg[16:0] scroll_q, scroll_d, scroll_t; reg write_enable, write_enable_c_q, write_enable_c_d; 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-1), .read_data(sram_read_data), .write_data(write_data_q), .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)) + bottom_q*CHAR_HMAX*((scroll_q-1) % CHAR_VMAX)) % (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_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; if (hdmix == WIDTH-1 && hdmiy == HEIGHT-1) begin frame_d = frame_q + 1'b1; end // Disable write during IO request write_enable = z80_ioreq && write_enable_c_q; end always @(posedge z80_clk) begin write_data_d = write_data_q; write_enable_c_d = write_enable_c_q; addr_d = addr_q; // @todo Hook up address lines // 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 last_input_d = z80_data; if (z80_data == "\r") begin addr_d = addr_r; write_enable_c_d = 0; end else if (z80_data == "\n") begin addr_d = addr_n; write_enable_c_d = 0; end else if (z80_data == 8) begin write_data_d = 0; addr_d = addr_b; write_enable_c_d = 1; end else begin write_data_d = z80_data - 32; addr_d = addr_t; write_enable_c_d = 1; end bottom_d = bottom_t; scroll_d = scroll_t; end end // IO request starts always @(negedge z80_ioreq) begin addr_t = (addr_q + 1); addr_n = (addr_q + CHAR_HMAX); addr_r = (addr_q - (addr_q % CHAR_HMAX)) % (CHAR_HMAX*CHAR_VMAX); addr_b = addr_q; bottom_t = bottom_q; scroll_t = scroll_q; if ((addr_t >= (CHAR_HMAX*CHAR_VMAX)) || (addr_n >= (CHAR_HMAX*CHAR_VMAX)) || (addr_r >= (CHAR_HMAX*CHAR_VMAX))) begin bottom_t = 1; scroll_t = scroll_q + 1; end else if ((bottom_q == 1) && ((addr_t >= (scroll_q*CHAR_HMAX)) || (addr_n >= (scroll_q*CHAR_HMAX)) || (addr_r >= (scroll_q*CHAR_HMAX)))) begin scroll_t = scroll_q + 1; end scroll_t = scroll_t % CHAR_VMAX; if (last_input_q == 8) begin addr_t = addr_t - 1; addr_n = addr_n - 1; addr_b = addr_b - 1; end addr_t = addr_t % (CHAR_HMAX*CHAR_VMAX); addr_n = addr_n % (CHAR_HMAX*CHAR_VMAX); addr_r = addr_r % (CHAR_HMAX*CHAR_VMAX); addr_b = addr_b % (CHAR_HMAX*CHAR_VMAX); end always @(posedge hdmi_clk) begin if (rst) begin frame_q <= 1'b0; char_index_q <= 1'b0; addr_q <= 1'b0; bottom_q <= 0; scroll_q <= 1'b0; write_data_q <= 0; last_input_q <= 0; write_enable_c_q <= 0; end else begin frame_q <= frame_d; char_index_q <= char_index_d; addr_q <= addr_d; bottom_q <= bottom_d; scroll_q <= scroll_d; write_data_q <= write_data_d; last_input_q <= last_input_d; write_enable_c_q <= write_enable_c_d; end end endmodule