333 lines
10 KiB
Verilog
333 lines
10 KiB
Verilog
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;
|
|
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)
|
|
);
|
|
|
|
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)) + 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_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
|
|
|
|
// 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;
|
|
scroll_q <= 1'b0;
|
|
bottom_of_screen_q <= 1'b0;
|
|
end else begin
|
|
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
|
|
end
|
|
|
|
endmodule
|