diff options
| author | Alejandro Soto <alejandro@34project.org> | 2023-11-17 14:18:29 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2023-11-17 15:46:12 -0600 |
| commit | 7275f342f2b8d97ae02e0e51011442f063660b5d (patch) | |
| tree | 068070bb7cbcd6b4084fd9235b78c62494c60827 | |
| parent | b11e2758446ac82328a8c410d38b80174dc3a1ed (diff) | |
rtl/gfx; rewrite scanout
| -rw-r--r-- | gfx_hw.tcl | 2 | ||||
| -rw-r--r-- | rtl/gfx/gfx_defs.sv | 6 | ||||
| -rw-r--r-- | rtl/gfx/gfx_flush_flow.sv | 45 | ||||
| -rw-r--r-- | rtl/gfx/gfx_scanout.sv | 210 | ||||
| -rw-r--r-- | rtl/gfx/gfx_scanout_dac.sv | 116 |
5 files changed, 247 insertions, 132 deletions
@@ -51,6 +51,7 @@ add_fileset_file gfx_defs.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_defs.sv add_fileset_file gfx_fold.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_fold.sv add_fileset_file gfx_mat_mat.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_mat_mat.sv add_fileset_file gfx_mat_vec.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_mat_vec.sv +add_fileset_file gfx_flush_flow.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_flush_flow.sv add_fileset_file gfx_pipeline_flow.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_pipeline_flow.sv add_fileset_file gfx_fold_flow.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_fold_flow.sv add_fileset_file gfx_skid_flow.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_skid_flow.sv @@ -59,6 +60,7 @@ add_fileset_file gfx_pipes.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_pipes.sv add_fileset_file gfx_dot.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_dot.sv add_fileset_file gfx_transpose.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_transpose.sv add_fileset_file gfx_scanout.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_scanout.sv +add_fileset_file gfx_scanout_dac.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_scanout_dac.sv add_fileset_file gfx_masks.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_masks.sv add_fileset_file gfx_mask_sram.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_mask_sram.sv add_fileset_file gfx_setup.sv SYSTEM_VERILOG PATH rtl/gfx/gfx_setup.sv diff --git a/rtl/gfx/gfx_defs.sv b/rtl/gfx/gfx_defs.sv index 2211c52..dc5f5c4 100644 --- a/rtl/gfx/gfx_defs.sv +++ b/rtl/gfx/gfx_defs.sv @@ -41,6 +41,7 @@ typedef logic[19:0] half_coord; `define COLOR_CHANNELS 4 typedef logic[7:0] color8; +typedef logic[9:0] color10; typedef struct packed { @@ -49,7 +50,7 @@ typedef struct packed typedef struct packed { - logic[9:0] r, g, b; + color10 r, g, b; } rgb30; typedef struct packed @@ -92,7 +93,8 @@ typedef logic[8:0] coarse_dim; `define GFX_MASK_SRAM_STAGES 3 `define GFX_MASK_STAGES (1 + `GFX_MASK_SRAM_STAGES + 1) -`define GFX_SCAN_STAGES 3 // Ajustable + +`define GFX_SCANOUT_FIFO_DEPTH 16 // Ajustable `define GFX_SETUP_BOUNDS_STAGES 3 `define GFX_SETUP_EDGE_STAGES (1 + `FIXED_FMA_DOT_STAGES) diff --git a/rtl/gfx/gfx_flush_flow.sv b/rtl/gfx/gfx_flush_flow.sv new file mode 100644 index 0000000..a0e43d7 --- /dev/null +++ b/rtl/gfx/gfx_flush_flow.sv @@ -0,0 +1,45 @@ +module gfx_flush_flow +#(parameter STAGES=0) +( + input logic clk, + rst_n, + + input logic in_valid, + out_ready, + + output logic out_valid, + commit, + flush +); + + logic was_valid, was_ready; + logic[STAGES - 1:0] valid; + + assign flush = was_valid && !was_ready; + assign commit = was_valid && was_ready; + assign out_valid = valid[STAGES - 1] && !flush; + + always_ff @(posedge clk or negedge rst_n) + if (!rst_n) begin + was_ready <= 0; + was_valid <= 0; + + for (integer i = 0; i < STAGES; ++i) + valid[i] <= 0; + end else begin + was_ready <= out_ready; + was_valid <= out_valid; + + if (!flush) + valid[0] <= in_valid; + else + valid[0] <= 0; + + for (integer i = 1; i < STAGES; ++i) + if (!flush) + valid[i] <= valid[i - 1]; + else + valid[i] <= 0; + end + +endmodule diff --git a/rtl/gfx/gfx_scanout.sv b/rtl/gfx/gfx_scanout.sv index b315e44..074a75a 100644 --- a/rtl/gfx/gfx_scanout.sv +++ b/rtl/gfx/gfx_scanout.sv @@ -26,155 +26,105 @@ module gfx_scanout output logic vsync ); - logic[`GFX_SCAN_STAGES:0] fb_ready, fb_valid, src_ready, src_valid, src_pipes; - logic[`GFX_SCAN_STAGES - 1:0] fb_stalls, src_stalls; - logic[`GFX_MASK_STAGES - 1:0] request_valid; - logic[$clog2(`GFX_SCAN_STAGES) - 1:0] queued; + logic commit, effective_mask, flush, mask_fifo_out, dac_ready, + fb_ready, mask_fifo_ready, fb_fifo_valid, mask_fifo_valid, pop, put, put_mask; - logic effective_mask, foreground, foreground_valid, partial, put_fb_valid, put_src_valid, - queued_dec, queued_inc, read_half, read_valid, request_flush; + mem_word fb_fifo_out; + half_coord mask_in_addr, mask_hold_addr, mask_out_addr, max_addr, commit_addr; - rgb24 fb_pipes[`GFX_SCAN_STAGES + 1], scan_pixel; - mem_word half; - half_coord commit_pos, next_pos, read_pos, request_pos[`GFX_MASK_STAGES - 1:0]; - linear_coord scan_pos, last_pos; + assign mask_addr = mask_in_addr[$bits(mask_in_addr) - 1:$bits(mask_in_addr) - $bits(mask_addr)]; + assign max_addr[0] = 1; + assign max_addr[$bits(max_addr) - 1:1] = `GFX_X_RES * `GFX_Y_RES - 1; - assign last_pos = `GFX_LINEAR_RES - 1; - assign scan_data.r = {scan_pixel.r, {2{scan_pixel.r[0]}}}; - assign scan_data.g = {scan_pixel.g, {2{scan_pixel.g[0]}}}; - assign scan_data.b = {scan_pixel.b, {2{scan_pixel.b[0]}}}; - - assign scan_pixel = foreground ? fb_pipes[`GFX_SCAN_STAGES] : clear_color; - assign scan_valid = foreground_valid && (!foreground || fb_valid[`GFX_SCAN_STAGES]); - assign scan_endofpacket = scan_pos == last_pos; - assign scan_startofpacket = scan_pos == 0; - - assign foreground = src_pipes[`GFX_SCAN_STAGES]; - assign foreground_valid = src_valid[`GFX_SCAN_STAGES]; - - // Soluciona Error-BLKANDNBLK en Verilator - assign fb_valid[0] = put_fb_valid; - assign src_valid[0] = put_src_valid; - - assign fb_ready[`GFX_SCAN_STAGES] = scan_ready && foreground_valid && foreground; - assign src_ready[`GFX_SCAN_STAGES] = scan_ready && scan_valid; - - assign next_pos = request_flush ? commit_pos : read_pos; - assign mask_addr = read_pos[$bits(read_pos) - 1:1]; - - assign read_half = request_pos[`GFX_MASK_STAGES - 1][0]; - assign read_valid = request_valid[`GFX_MASK_STAGES - 1]; - assign request_flush = (fb_read && fb_waitrequest) || (src_valid[0] && !src_ready[0]) || queued == `GFX_SCAN_STAGES || vsync; - - assign queued_inc = !request_flush && read_valid && read_half && effective_mask; - assign queued_dec = fb_ready[`GFX_SCAN_STAGES - 1] && fb_valid[`GFX_SCAN_STAGES - 1]; + assign fb_ready = !fb_read || !fb_waitrequest; assign effective_mask = mask || !enable_clear; - genvar i; - generate - for (i = 0; i < `GFX_SCAN_STAGES; ++i) begin: stages - gfx_pipeline_flow #(.STAGES(1)) fb_flow - ( - .stall(fb_stalls[i]), - .in_ready(fb_ready[i]), - .in_valid(fb_valid[i]), - .out_ready(fb_ready[i + 1]), - .out_valid(fb_valid[i + 1]), - .* - ); - - gfx_pipeline_flow #(.STAGES(1)) src_flow - ( - .stall(src_stalls[i]), - .in_ready(src_ready[i]), - .in_valid(src_valid[i]), - .out_ready(src_ready[i + 1]), - .out_valid(src_valid[i + 1]), - .* - ); - - always_ff @(posedge clk) begin - if (!fb_stalls[i]) - fb_pipes[i + 1] <= fb_pipes[i]; - - if (!src_stalls[i]) - src_pipes[i + 1] <= src_pipes[i]; - end - end - - for (i = 1; i < `GFX_MASK_STAGES; ++i) begin: request - always_ff @(posedge clk or negedge rst_n) - request_valid[i] <= !rst_n ? 0 : (request_valid[i - 1] && !request_flush); - - always_ff @(posedge clk) - request_pos[i] <= request_pos[i - 1]; - end - endgenerate + gfx_flush_flow #(.STAGES(`GFX_MASK_STAGES)) mask_flow + ( + .in_valid(1), + .out_ready(fb_ready && mask_fifo_ready), + .out_valid(pop), + .* + ); + + gfx_pipes #(.WIDTH($bits(mask_in_addr)), .DEPTH(`GFX_MASK_STAGES)) addr_pipes + ( + .in(mask_in_addr), + .out(mask_out_addr), + .stall(0), + .* + ); + + /* Estas FIFOs deben cumplir dos propiedades para garantizar correctitud: + * + * 1. mask_fifo.out_ready && mask_fifo.out_valid <=> scan.in_ready && scan.in_valid + * 2. fb_fifo.out_ready && fb_fifo.out_valid => scan.in_ready && scan.in_valid + * + * Nótese la asimetría (<=> vs =>), debido a mask_fifo.out + */ + + gfx_fifo #(.WIDTH($bits(effective_mask)), .DEPTH(`GFX_SCANOUT_FIFO_DEPTH)) mask_fifo + ( + .in(put_mask), + .out(mask_fifo_out), + .in_ready(mask_fifo_ready), + .in_valid(put), + .out_ready(dac_ready && (!mask_fifo_out || fb_fifo_valid)), + .out_valid(mask_fifo_valid), + .* + ); + + // 2x para evitar potencial overflow cuando fb_read=1 pero mask_fifo está llena + gfx_fifo #(.WIDTH($bits(mem_word)), .DEPTH(2 * `GFX_SCANOUT_FIFO_DEPTH)) fb_fifo + ( + .in(fb_readdata), + .out(fb_fifo_out), + .in_ready(), // readdatavalid no soporta backpressure + .in_valid(fb_readdatavalid), + .out_ready(dac_ready && mask_fifo_valid && mask_fifo_out), + .out_valid(fb_fifo_valid), + .* + ); + + gfx_scanout_dac dac + ( + .in_ready(dac_ready), + .in_valid(mask_fifo_valid && (!mask_fifo_out || fb_fifo_valid)), + .* + ); always_ff @(posedge clk or negedge rst_n) if (!rst_n) begin - vsync <= 0; - queued <= 0; - - read_pos <= 0; - scan_pos <= 0; - commit_pos <= 0; - + put <= 0; fb_read <= 0; - partial <= 0; - - put_fb_valid <= 0; - put_src_valid <= 0; - request_valid[0] <= 0; + commit_addr <= 0; + mask_in_addr <= 0; end else begin - if (queued_inc && !queued_dec) - queued <= queued + 1; - else if (!queued_inc && queued_dec) - queued <= queued - 1; - - if (scan_ready && scan_valid) - scan_pos <= scan_endofpacket ? 0 : scan_pos + 1; + mask_in_addr <= mask_in_addr + 1; + if (mask_in_addr == max_addr) + mask_in_addr <= 0; - partial <= partial ^ fb_readdatavalid; + if (flush) + mask_in_addr <= commit_addr; - put_fb_valid <= partial && fb_readdatavalid; - request_valid[0] <= !request_flush; + if (commit) + commit_addr <= mask_hold_addr; - read_pos <= next_pos + 1; - if (next_pos == {last_pos, 1'b1}) - read_pos <= 0; + if (fb_ready) + fb_read <= mask_fifo_ready && pop && effective_mask; - if (!fb_waitrequest) - fb_read <= 0; - - if (src_ready[0]) - put_src_valid <= 0; - - if (!request_flush) begin - fb_read <= read_valid && effective_mask; - put_src_valid <= read_valid && read_half; - - if (read_valid) - commit_pos <= request_pos[`GFX_MASK_STAGES - 1]; - end - - vsync <= !vsync && !request_flush && read_valid && request_pos[`GFX_MASK_STAGES - 1] == {last_pos, 1'b1}; + if (mask_fifo_ready) + put <= fb_ready && pop; end always_ff @(posedge clk) begin - request_pos[0] <= read_pos; + mask_hold_addr <= mask_out_addr; - if (!request_flush) begin - fb_address <= request_pos[`GFX_MASK_STAGES - 1]; - src_pipes[0] <= effective_mask; - end + if (fb_ready) + fb_address <= mask_out_addr; - if (fb_readdatavalid) begin - if (partial) - fb_pipes[0] <= {fb_readdata[7:0], half}; - else - half <= fb_readdata; - end + if (mask_fifo_ready) + put_mask <= effective_mask; end endmodule diff --git a/rtl/gfx/gfx_scanout_dac.sv b/rtl/gfx/gfx_scanout_dac.sv new file mode 100644 index 0000000..c8fe218 --- /dev/null +++ b/rtl/gfx/gfx_scanout_dac.sv @@ -0,0 +1,116 @@ +`include "gfx/gfx_defs.sv" + +module gfx_scanout_dac +( + input logic clk, + rst_n, + + input logic enable_clear, + input rgb24 clear_color, + + input logic mask_fifo_out, + input mem_word fb_fifo_out, + input logic in_valid, + output logic in_ready, + + input logic scan_ready, + output logic scan_valid, + scan_endofpacket, + scan_startofpacket, + output rgb30 scan_data, + + output logic vsync +); + + logic dac_valid, half, half_mask, stall, endofpacket, startofpacket; + rgb24 pixel; + rgb32 fifo_pixel; + mem_word msw, lsw; + half_coord next_addr; + linear_coord max_addr, pixel_addr; + + struct packed + { + logic endofpacket, + startofpacket; + rgb30 pixel; + } skid_in, skid_out; + + assign scan_data = skid_out.pixel; + assign scan_endofpacket = skid_out.endofpacket; + assign scan_startofpacket = skid_out.startofpacket; + + assign max_addr = `GFX_X_RES * `GFX_Y_RES - 1; + + function color10 dac_color(color8 in); + dac_color = {in, {2{in[0]}}}; + endfunction + + assign fifo_pixel = {msw, lsw}; + assign skid_in.pixel.r = dac_color(pixel.r); + assign skid_in.pixel.g = dac_color(pixel.g); + assign skid_in.pixel.b = dac_color(pixel.b); + assign skid_in.endofpacket = endofpacket; + assign skid_in.startofpacket = startofpacket; + + always_comb begin + // Descarta fifo_pixel.a + pixel.r = fifo_pixel.r; + pixel.g = fifo_pixel.g; + pixel.b = fifo_pixel.b; + + if (!half_mask) + pixel = clear_color; + end + + gfx_skid_flow flow + ( + .in_valid(dac_valid), + .out_ready(scan_ready), + .out_valid(scan_valid), + .* + ); + + gfx_skid_buf #(.WIDTH($bits(skid_in))) skid + ( + .in(skid_in), + .out(skid_out), + .* + ); + + always_ff @(posedge clk or negedge rst_n) + if (!rst_n) begin + half <= 0; + vsync <= 0; + dac_valid <= 0; + pixel_addr <= 0; + end else begin + vsync <= 0; + if (in_ready && dac_valid) begin + vsync <= scan_endofpacket; + dac_valid <= 0; + end + + if (in_ready && in_valid) begin + half <= !half; + dac_valid <= half; + + if (half) begin + pixel_addr <= pixel_addr + 1; + if (pixel_addr == max_addr) + pixel_addr <= 0; + end + end + end + + always_ff @(posedge clk) + if (in_ready && in_valid) begin + lsw <= msw; + msw <= fb_fifo_out; + half_mask <= mask_fifo_out; + + endofpacket <= pixel_addr == max_addr; + startofpacket <= pixel_addr == 0; + end + +endmodule |
