summaryrefslogtreecommitdiff
path: root/rtl/gfx/gfx_scanout.sv
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2023-11-17 14:18:29 -0600
committerAlejandro Soto <alejandro@34project.org>2023-11-17 15:46:12 -0600
commit7275f342f2b8d97ae02e0e51011442f063660b5d (patch)
tree068070bb7cbcd6b4084fd9235b78c62494c60827 /rtl/gfx/gfx_scanout.sv
parentb11e2758446ac82328a8c410d38b80174dc3a1ed (diff)
rtl/gfx; rewrite scanout
Diffstat (limited to 'rtl/gfx/gfx_scanout.sv')
-rw-r--r--rtl/gfx/gfx_scanout.sv210
1 files changed, 80 insertions, 130 deletions
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