738 lines
19 KiB
Systemverilog
738 lines
19 KiB
Systemverilog
`timescale 1ns/100ps
|
|
`default_nettype none
|
|
|
|
/* Yosys do not support SPRAM and MAC inferring */
|
|
`define USE_SPRAM_PRIMITIVE
|
|
`define USE_MAC_PRIMITIVE
|
|
|
|
module lcd_top #(parameter SPI_CLK_PERIOD = 6)
|
|
(input logic clock,
|
|
input logic reset,
|
|
|
|
output logic lcd_spi_csn_o,
|
|
output logic lcd_spi_clk_o,
|
|
output logic lcd_spi_dat_o,
|
|
output logic lcd_spi_dcn_o,
|
|
|
|
input logic redraw_i,
|
|
output logic done_o,
|
|
|
|
input logic [7:0] x_i,
|
|
input logic [8:0] y_i,
|
|
input logic [15:0] color_i,
|
|
output logic [15:0] color_o,
|
|
input logic req_i,
|
|
output logic ack_o,
|
|
input logic wr_i);
|
|
|
|
/* Display size */
|
|
localparam DISPLAY_MEM_SIZE = 320 * 240 * 2; // 2 byte per pixel
|
|
localparam DISPLAY_MEM_CW = $clog2(DISPLAY_MEM_SIZE);
|
|
|
|
/* Display x/y address width */
|
|
localparam DISPLAY_XCW = 8,
|
|
DISPLAY_YCW = 9;
|
|
|
|
/* Screen size and origin */
|
|
localparam XSIZE = 240,
|
|
YSIZE = 272,
|
|
XORIG = 0,
|
|
YORIG = 24;
|
|
|
|
localparam FBSIZE = XSIZE * YSIZE;
|
|
localparam FBCW = $clog2(FBSIZE);
|
|
|
|
/* Drawing block size */
|
|
localparam BLOCK_XS = 16, // must be power of 2
|
|
BLOCK_YS = 16; // must be power of 2
|
|
|
|
localparam GRID_XS = XSIZE / BLOCK_XS,
|
|
GRID_YS = YSIZE / BLOCK_YS;
|
|
|
|
localparam BLOCK_XS_CW = $clog2(BLOCK_XS);
|
|
localparam BLOCK_YS_CW = $clog2(BLOCK_YS);
|
|
|
|
localparam GRID_XS_CW = $clog2(GRID_XS);
|
|
localparam GRID_YS_CW = $clog2(GRID_YS);
|
|
|
|
localparam DFLAG_SIZE = GRID_XS * GRID_YS;
|
|
localparam DFLAG_CW = $clog2(DFLAG_SIZE);
|
|
|
|
localparam BLOCK_SIZE = BLOCK_XS * BLOCK_YS;
|
|
localparam BLOCK_CW = $clog2(BLOCK_SIZE);
|
|
|
|
/* --------- Drawing flags memory --------- */
|
|
logic dflag[DFLAG_SIZE];
|
|
logic dflag_wdata;
|
|
logic dflag_rdata;
|
|
logic [DFLAG_CW-1:0] dflag_waddr;
|
|
logic [DFLAG_CW-1:0] dflag_raddr;
|
|
logic [DFLAG_CW-1:0] dflag_int_addr; // for screen refresher
|
|
logic [DFLAG_CW-1:0] dflag_ext_addr; // for external master
|
|
logic dflag_wr;
|
|
logic dflag_set;
|
|
logic dflag_clr;
|
|
|
|
assign dflag_wr = dflag_set | dflag_clr;
|
|
assign dflag_waddr = dflag_clr ? dflag_int_addr : dflag_ext_addr;
|
|
assign dflag_raddr = dflag_int_addr;
|
|
assign dflag_wdata = dflag_set;
|
|
|
|
/* Infer as sysMEM Block RAM */
|
|
always_ff @ (posedge clock) begin
|
|
if (dflag_wr)
|
|
dflag[dflag_waddr] <= dflag_wdata;
|
|
|
|
dflag_rdata <= dflag[dflag_raddr];
|
|
end
|
|
|
|
/* --------- Frame buffer RAM (one-port block RAM)--------- */
|
|
logic [FBCW-1:0] fbaddr;
|
|
logic [15:0] fb_rdata;
|
|
logic [15:0] fb_wdata;
|
|
logic fbwrite;
|
|
|
|
`ifdef USE_SPRAM_PRIMITIVE
|
|
ice40_spram spram_i
|
|
(.clock(clock),
|
|
.addr(fbaddr),
|
|
.data_i(fb_wdata),
|
|
.data_o(fb_rdata),
|
|
.wr(fbwrite));
|
|
`else
|
|
logic [15:0] fbram[FBSIZE];
|
|
|
|
always_ff @ (posedge clock)
|
|
if (fbwrite) begin
|
|
fbram[fbaddr] <= fb_wdata;
|
|
fb_rdata <= 'x;
|
|
end
|
|
else
|
|
fb_rdata <= fbram[fbaddr];
|
|
`endif
|
|
|
|
/* --------- Framebuffer arbiter --------- */
|
|
logic [FBCW-1:0] fba_int; // Frame buffer address from refresher
|
|
logic [FBCW-1:0] fba_ext; // Frame buffer address from client
|
|
|
|
logic fb_busy_int;
|
|
logic fb_busy_ext;
|
|
logic fb_clear;
|
|
|
|
assign fbaddr = fb_busy_int ? fba_int : fba_ext;
|
|
assign color_o = fb_rdata;
|
|
assign fb_wdata = fb_clear ? '0 : color_i;
|
|
|
|
enum int unsigned {
|
|
FBST_CLEAR = 0,
|
|
FBST_CLEAR_NEXT,
|
|
FBST_WAIT,
|
|
FBST_ADDR,
|
|
FBST_READ,
|
|
FBST_DONE
|
|
} fbst;
|
|
|
|
logic [FBCW-1:0] ymult;
|
|
logic [DFLAG_CW-1:0] fmult;
|
|
|
|
`ifdef USE_MAC_PRIMITIVE
|
|
wire [31:0] ymac_o;
|
|
wire [31:0] fmac_o;
|
|
|
|
ice40_mac16x16 ymac_i
|
|
(.clock, .reset,
|
|
.a(16'(y_i)),
|
|
.b(16'(XSIZE)),
|
|
.s(32'b0),
|
|
.sub(1'b0),
|
|
.y(ymac_o));
|
|
|
|
ice40_mac16x16 fmac_i
|
|
(.clock, .reset,
|
|
.a(16'(y_i) >> BLOCK_YS_CW),
|
|
.b(16'(GRID_XS)),
|
|
.s(32'b0),
|
|
.sub(1'b0),
|
|
.y(fmac_o));
|
|
|
|
assign ymult = ymac_o[FBCW-1:0];
|
|
assign fmult = fmac_o[DFLAG_CW-1:0];
|
|
`endif
|
|
|
|
always_ff @ (posedge clock, posedge reset)
|
|
if (reset) begin
|
|
fbst <= FBST_CLEAR;
|
|
ack_o <= 1'b0;
|
|
fbwrite <= 1'b0;
|
|
fb_busy_ext <= 1'b0;
|
|
dflag_set <= 1'b0;
|
|
end
|
|
else
|
|
case (fbst)
|
|
/* Clear frame buffer RAM */
|
|
FBST_CLEAR: begin
|
|
fba_ext <= '0;
|
|
fbwrite <= 1'b1;
|
|
fb_busy_ext <= 1'b1;
|
|
fb_clear <= 1'b1;
|
|
fbst <= FBST_CLEAR_NEXT;
|
|
end
|
|
|
|
FBST_CLEAR_NEXT:
|
|
if (fba_ext == (FBSIZE-1)) begin
|
|
fbwrite <= 1'b0;
|
|
fb_busy_ext <= 1'b0;
|
|
fb_clear <= 1'b0;
|
|
fbst <= FBST_WAIT;
|
|
end
|
|
else
|
|
fba_ext <= fba_ext + 1'b1;
|
|
|
|
/* Main loop */
|
|
FBST_WAIT:
|
|
if (req_i && !fb_busy_int)
|
|
if (x_i >= XSIZE || y_i >= YSIZE) begin
|
|
ack_o <= 1'b1;
|
|
fbst <= FBST_READ;
|
|
end
|
|
else begin
|
|
|
|
`ifndef USE_MAC_PRIMITIVE
|
|
ymult <= y_i * XSIZE;
|
|
fmult <= GRID_YS_CW'(y_i >> BLOCK_YS_CW) * GRID_XS;
|
|
`endif
|
|
fb_busy_ext <= 1'b1;
|
|
fbst <= FBST_ADDR;
|
|
end
|
|
|
|
FBST_ADDR:
|
|
if (fb_busy_int) begin
|
|
fbst <= FBST_WAIT;
|
|
fb_busy_ext <= 1'b0;
|
|
end
|
|
else begin
|
|
fba_ext <= ymult + FBCW'(x_i);
|
|
dflag_ext_addr <= fmult + DFLAG_CW'(x_i >> BLOCK_XS_CW);
|
|
|
|
if (wr_i) begin
|
|
ack_o <= 1'b1;
|
|
fbwrite <= 1'b1;
|
|
dflag_set <= 1'b1;
|
|
fbst <= FBST_DONE;
|
|
end
|
|
else
|
|
fbst <= FBST_READ;
|
|
end
|
|
|
|
FBST_READ: begin
|
|
ack_o <= 1'b1;
|
|
fbst <= FBST_DONE;
|
|
end
|
|
|
|
FBST_DONE: begin
|
|
fbwrite <= 1'b0;
|
|
dflag_set <= 1'b0;
|
|
ack_o <= 1'b0;
|
|
fb_busy_ext <= 1'b0;
|
|
fbst <= FBST_WAIT;
|
|
end
|
|
endcase
|
|
|
|
/* --------- Read initialization commands from file --------- */
|
|
localparam INIT_FILE = "lcd_init.rom";
|
|
localparam INIT_ROM_SIZE = 64;
|
|
localparam INIT_DATA_SIZE = 61;
|
|
localparam INIT_ROM_CW = $clog2(INIT_ROM_SIZE);
|
|
|
|
logic [8:0] init_rom [INIT_ROM_SIZE];
|
|
logic [INIT_ROM_CW-1:0] init_addr;
|
|
logic [8:0] init_data;
|
|
|
|
initial $readmemh(INIT_FILE, init_rom, 0, INIT_DATA_SIZE-1);
|
|
|
|
/* Block RAM as ROM */
|
|
always_ff @ (posedge clock)
|
|
init_data <= init_rom[init_addr];
|
|
|
|
/* --------- SPI master --------- */
|
|
logic [7:0] spi_data;
|
|
logic spi_push;
|
|
logic spi_done;
|
|
|
|
lcd_spi #(.DATA_WIDTH(8),
|
|
.SPI_CLK_PERIOD(SPI_CLK_PERIOD),
|
|
.PUSH_ON_DONE(1)) spim_i
|
|
(.clock, .reset,
|
|
.data_i(spi_data),
|
|
.push_i(spi_push),
|
|
.done_o(spi_done),
|
|
.spi_clk_o(lcd_spi_clk_o),
|
|
.spi_dat_o(lcd_spi_dat_o));
|
|
|
|
/* --------- Main FSM --------- */
|
|
`ifdef TESTBENCH
|
|
localparam INIT_DELAY = 250;
|
|
`else
|
|
// localparam INIT_DELAY = 7500000;
|
|
localparam INIT_DELAY = 250;
|
|
`endif
|
|
|
|
enum int unsigned {
|
|
ST_PREINIT_DELAY = 0, // 0
|
|
ST_INIT_PUSH_SPI,
|
|
ST_INIT_WAIT_SPI,
|
|
ST_INIT_WAIT_LAST,
|
|
ST_POSTINIT_DELAY,
|
|
ST_DISPLAY_ON,
|
|
ST_DISPLAY_ONW,
|
|
ST_SCRCLR_CMD,
|
|
ST_SCRCLR,
|
|
ST_SCRCLR_LAST,
|
|
ST_START_REDRAW, // 10
|
|
ST_READ_FLAG,
|
|
ST_CHECK_FLAG,
|
|
ST_CLEAR_FLAG,
|
|
ST_CADDR_CMD,
|
|
ST_CADDR_0,
|
|
ST_CADDR_1,
|
|
ST_CADDR_2,
|
|
ST_CADDR_3,
|
|
ST_PADDR_CMD,
|
|
ST_PADDR_0, // 20
|
|
ST_PADDR_1,
|
|
ST_PADDR_2,
|
|
ST_PADDR_3,
|
|
ST_WRITE_CMD,
|
|
ST_WRITE_CMDW,
|
|
ST_FB_READ,
|
|
ST_STORE_PIXEL,
|
|
ST_WRITE_PIXEL_H,
|
|
ST_WRITE_PIXEL_L,
|
|
ST_NEXT_PIXEL, // 30
|
|
ST_NEXT_BLOCK
|
|
} state, next;
|
|
|
|
always_ff @(posedge clock, posedge reset)
|
|
if (reset) state <= ST_PREINIT_DELAY;
|
|
else state <= next;
|
|
|
|
/* Pre/post init delay counter */
|
|
localparam INIT_DELAY_CW = $clog2(INIT_DELAY);
|
|
logic [INIT_DELAY_CW-1:0] delay_cntr;
|
|
logic delay_cntr_incr;
|
|
|
|
always_ff @(posedge clock)
|
|
delay_cntr <= (~reset && delay_cntr_incr) ?
|
|
delay_cntr + 1'b1 : '0;
|
|
|
|
/* Initialization ROM address */
|
|
logic init_addr_rst;
|
|
logic init_addr_incr;
|
|
|
|
always_ff @ (posedge clock)
|
|
if (reset || init_addr_rst)
|
|
init_addr <= '0;
|
|
else
|
|
if (init_addr_incr)
|
|
init_addr <= init_addr + 1'b1;
|
|
|
|
/* LCD chipselect */
|
|
logic spi_disable;
|
|
|
|
always_ff @ (posedge clock)
|
|
if (reset || spi_disable)
|
|
lcd_spi_csn_o <= 1'b1;
|
|
else if (spi_push)
|
|
lcd_spi_csn_o <= 1'b0;
|
|
|
|
/* LCD data/command */
|
|
logic spi_do_cmd;
|
|
logic spi_do_data;
|
|
|
|
always_ff @ (posedge clock)
|
|
// if (spi_do_cmd)
|
|
// lcd_spi_dcn_o <= 1'b0;
|
|
// else if (spi_do_data)
|
|
// lcd_spi_dcn_o <= 1'b1;
|
|
if (spi_do_cmd != spi_do_data)
|
|
lcd_spi_dcn_o <= spi_do_data;
|
|
|
|
/* Redraw block coordinates */
|
|
logic [GRID_XS_CW-1:0] bx;
|
|
logic [DISPLAY_XCW-1:0] borigx;
|
|
logic [DISPLAY_YCW-1:0] borigy;
|
|
logic [DISPLAY_XCW-1:0] borigx_e;
|
|
logic [DISPLAY_YCW-1:0] borigy_e;
|
|
|
|
assign borigx_e = borigx + BLOCK_XS - 1;
|
|
assign borigy_e = borigy + BLOCK_YS - 1;
|
|
|
|
logic [FBCW-1:0] fbr_orig;
|
|
|
|
logic reset_redraw;
|
|
logic next_block;
|
|
logic is_last_blk;
|
|
|
|
always_ff @ (posedge clock)
|
|
if (reset_redraw) begin
|
|
dflag_int_addr <= '0;
|
|
bx <= '0;
|
|
borigx <= XORIG;
|
|
borigy <= YORIG;
|
|
fbr_orig <= '0;
|
|
is_last_blk <= 1'b0;
|
|
end
|
|
else
|
|
if (next_block) begin
|
|
dflag_int_addr <= dflag_int_addr + 1'b1;
|
|
is_last_blk <= (dflag_int_addr == DFLAG_CW'(DFLAG_SIZE-1)) ? 1'b1 : 1'b0;
|
|
|
|
if (bx == GRID_XS_CW'(GRID_XS - 1))
|
|
begin
|
|
bx <= '0;
|
|
borigx <= XORIG;
|
|
borigy <= borigy + BLOCK_YS;
|
|
fbr_orig <= fbr_orig + BLOCK_XS + ((BLOCK_YS - 1) * XSIZE);
|
|
end
|
|
else
|
|
begin
|
|
bx <= bx + 1'b1;
|
|
borigx <= borigx + BLOCK_XS;
|
|
fbr_orig <= fbr_orig + BLOCK_XS;
|
|
end
|
|
end
|
|
|
|
/* Framebuffer handling */
|
|
logic [BLOCK_XS_CW-1:0] px;
|
|
logic [BLOCK_CW-1:0] pi;
|
|
logic [15:0] pixel;
|
|
|
|
logic start_write;
|
|
logic read_pixel;
|
|
logic next_pixel;
|
|
|
|
always_ff @ (posedge clock)
|
|
if (read_pixel)
|
|
pixel <= fb_rdata;
|
|
|
|
always_ff @ (posedge clock)
|
|
if (start_write) begin
|
|
fba_int <= fbr_orig;
|
|
px <= '0;
|
|
pi <= '0;
|
|
end
|
|
else
|
|
if (next_pixel) begin
|
|
pi <= pi + 1'b1;
|
|
|
|
if (px == BLOCK_XS_CW'(BLOCK_XS-1))
|
|
begin
|
|
fba_int <= fba_int + XSIZE - BLOCK_XS + 1'b1;
|
|
px <= '0;
|
|
end
|
|
else
|
|
begin
|
|
fba_int <= fba_int + 1'b1;
|
|
px <= px + 1'b1;
|
|
end
|
|
end
|
|
|
|
/* Column/page addresses map */
|
|
logic [15:0] caddr_b, caddr_e;
|
|
logic [15:0] paddr_b, paddr_e;
|
|
|
|
assign caddr_b = { (16-DISPLAY_XCW)'('0), borigx };
|
|
assign caddr_e = { (16-DISPLAY_XCW)'('0), borigx_e };
|
|
assign paddr_b = { (16-DISPLAY_YCW)'('0), borigy };
|
|
assign paddr_e = { (16-DISPLAY_YCW)'('0), borigy_e };
|
|
|
|
/* Clear screen pixel counter */
|
|
logic [DISPLAY_MEM_CW-1:0] scrclr_pcntr;
|
|
logic scrclr_incr;
|
|
|
|
always_ff @ (posedge clock)
|
|
if (reset || init_addr_rst)
|
|
scrclr_pcntr <= '0;
|
|
else
|
|
if (scrclr_incr)
|
|
scrclr_pcntr <= scrclr_pcntr + 1'b1;
|
|
|
|
/* FSM combinational block */
|
|
always @(*) begin
|
|
next = state;
|
|
|
|
/* FSM outputs default value */
|
|
delay_cntr_incr = 1'b0;
|
|
init_addr_rst = 1'b0;
|
|
init_addr_incr = 1'b0;
|
|
scrclr_incr = 1'b0;
|
|
spi_push = 1'b0;
|
|
spi_data = '0;
|
|
spi_disable = 1'b0;
|
|
spi_do_cmd = 1'b0;
|
|
spi_do_data = 1'b0;
|
|
reset_redraw = 1'b0;
|
|
dflag_clr = 1'b0;
|
|
next_block = 1'b0;
|
|
start_write = 1'b0;
|
|
next_pixel = 1'b0;
|
|
read_pixel = 1'b0;
|
|
fb_busy_int = 1'b0;
|
|
done_o = 1'b0;
|
|
|
|
case (state)
|
|
ST_PREINIT_DELAY: begin
|
|
delay_cntr_incr = 1'b1;
|
|
init_addr_rst = 1'b1;
|
|
|
|
if (delay_cntr == INIT_DELAY)
|
|
next = ST_INIT_PUSH_SPI;
|
|
end
|
|
|
|
ST_INIT_PUSH_SPI: begin
|
|
init_addr_incr = 1'b1;
|
|
spi_data = init_data[7:0];
|
|
spi_push = 1'b1;
|
|
|
|
{spi_do_cmd, spi_do_data}
|
|
= init_data[8] ? 2'b01 : 2'b10;
|
|
|
|
if (init_addr == (INIT_DATA_SIZE-1))
|
|
next = ST_INIT_WAIT_LAST;
|
|
else
|
|
next = ST_INIT_WAIT_SPI;
|
|
end
|
|
|
|
ST_INIT_WAIT_SPI:
|
|
if (spi_done)
|
|
next = ST_INIT_PUSH_SPI;
|
|
|
|
ST_INIT_WAIT_LAST:
|
|
if (spi_done)
|
|
next = ST_POSTINIT_DELAY;
|
|
|
|
ST_POSTINIT_DELAY: begin
|
|
spi_disable = 1'b1;
|
|
delay_cntr_incr = 1'b1;
|
|
|
|
if (delay_cntr == INIT_DELAY)
|
|
next = ST_DISPLAY_ON;
|
|
end
|
|
|
|
ST_DISPLAY_ON: begin
|
|
spi_data = 8'h29;
|
|
spi_do_cmd = 1'b1;
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_DISPLAY_ONW;
|
|
end
|
|
|
|
ST_DISPLAY_ONW:
|
|
if (spi_done) begin
|
|
spi_disable = 1'b1;
|
|
next = ST_SCRCLR_CMD;
|
|
end
|
|
|
|
ST_SCRCLR_CMD: begin
|
|
spi_data = 8'h2c;
|
|
spi_do_cmd = 1'b1;
|
|
spi_push = 1'b1;
|
|
next = ST_SCRCLR;
|
|
end
|
|
|
|
ST_SCRCLR:
|
|
if (spi_done) begin
|
|
spi_data = 8'h00; //8'h32;
|
|
spi_do_data = 1'b1;
|
|
spi_push = 1'b1;
|
|
scrclr_incr = 1'b1;
|
|
|
|
if (scrclr_pcntr ==
|
|
`ifdef TESTBENCH
|
|
`ifdef VERILATOR
|
|
(DISPLAY_MEM_SIZE - 1)
|
|
`else
|
|
200
|
|
`endif
|
|
`else
|
|
(DISPLAY_MEM_SIZE - 1)
|
|
`endif
|
|
)
|
|
next = ST_SCRCLR_LAST;
|
|
end
|
|
|
|
ST_SCRCLR_LAST:
|
|
if (spi_done)
|
|
next = ST_START_REDRAW;
|
|
|
|
ST_START_REDRAW:
|
|
if (redraw_i) begin
|
|
spi_disable = 1'b1;
|
|
reset_redraw = 1'b1;
|
|
next = ST_READ_FLAG;
|
|
end
|
|
|
|
ST_READ_FLAG:
|
|
if (is_last_blk) begin
|
|
done_o = 1'b1;
|
|
next = ST_START_REDRAW;
|
|
end
|
|
else
|
|
next = ST_CHECK_FLAG;
|
|
|
|
ST_CHECK_FLAG:
|
|
if (dflag_rdata == 1'b1)
|
|
next = ST_CLEAR_FLAG;
|
|
else
|
|
begin
|
|
next_block = 1'b1;
|
|
next = ST_READ_FLAG;
|
|
end
|
|
|
|
ST_CLEAR_FLAG: begin
|
|
dflag_clr = 1'b1;
|
|
next = ST_CADDR_CMD;
|
|
end
|
|
|
|
ST_CADDR_CMD: begin
|
|
spi_data = 8'h2a;
|
|
spi_do_cmd = 1'b1;
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_CADDR_0;
|
|
end
|
|
|
|
ST_CADDR_0:
|
|
if (spi_done) begin
|
|
spi_data = caddr_b[15:8];
|
|
spi_do_data = 1'b1;
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_CADDR_1;
|
|
end
|
|
|
|
ST_CADDR_1:
|
|
if (spi_done) begin
|
|
spi_data = caddr_b[7:0];
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_CADDR_2;
|
|
end
|
|
|
|
ST_CADDR_2:
|
|
if (spi_done) begin
|
|
spi_data = caddr_e[15:8];
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_CADDR_3;
|
|
end
|
|
|
|
ST_CADDR_3:
|
|
if (spi_done) begin
|
|
spi_data = caddr_e[7:0];
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_PADDR_CMD;
|
|
end
|
|
|
|
ST_PADDR_CMD:
|
|
if (spi_done) begin
|
|
spi_data = 8'h2b;
|
|
spi_do_cmd = 1'b1;
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_PADDR_0;
|
|
end
|
|
|
|
ST_PADDR_0:
|
|
if (spi_done) begin
|
|
spi_data = paddr_b[15:8];
|
|
spi_do_data = 1'b1;
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_PADDR_1;
|
|
end
|
|
|
|
ST_PADDR_1:
|
|
if (spi_done) begin
|
|
spi_data = paddr_b[7:0];
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_PADDR_2;
|
|
end
|
|
|
|
ST_PADDR_2:
|
|
if (spi_done) begin
|
|
spi_data = paddr_e[15:8];
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_PADDR_3;
|
|
end
|
|
|
|
ST_PADDR_3:
|
|
if (spi_done) begin
|
|
spi_data = paddr_e[7:0];
|
|
spi_push = 1'b1;
|
|
|
|
next = ST_WRITE_CMD;
|
|
end
|
|
|
|
ST_WRITE_CMD:
|
|
if (spi_done) begin
|
|
spi_data = 8'h2c;
|
|
spi_do_cmd = 1'b1;
|
|
spi_push = 1'b1;
|
|
start_write = 1'b1;
|
|
next = ST_WRITE_CMDW;
|
|
end
|
|
|
|
ST_WRITE_CMDW:
|
|
if (spi_done)
|
|
next = ST_FB_READ;
|
|
|
|
ST_FB_READ:
|
|
if (!fb_busy_ext) begin
|
|
fb_busy_int = 1'b1;
|
|
next = ST_STORE_PIXEL;
|
|
end
|
|
|
|
ST_STORE_PIXEL: begin
|
|
fb_busy_int = 1'b1;
|
|
read_pixel = 1'b1;
|
|
next = ST_WRITE_PIXEL_H;
|
|
end
|
|
|
|
ST_WRITE_PIXEL_H: begin
|
|
spi_data = pixel[15:8];
|
|
spi_do_data = 1'b1;
|
|
spi_push = 1'b1;
|
|
next = ST_WRITE_PIXEL_L;
|
|
end
|
|
|
|
ST_WRITE_PIXEL_L:
|
|
if (spi_done) begin
|
|
spi_data = pixel[7:0];
|
|
spi_push = 1'b1;
|
|
next = ST_NEXT_PIXEL;
|
|
end
|
|
|
|
ST_NEXT_PIXEL:
|
|
if (spi_done) begin
|
|
next_pixel = 1'b1;
|
|
|
|
if (pi == (BLOCK_SIZE - 1))
|
|
next = ST_NEXT_BLOCK;
|
|
else
|
|
next = ST_FB_READ;
|
|
end
|
|
|
|
ST_NEXT_BLOCK: begin
|
|
spi_disable = 1'b1;
|
|
next_block = 1'b1;
|
|
next = ST_READ_FLAG;
|
|
end
|
|
endcase
|
|
end
|
|
|
|
endmodule // lcd_top
|