summaryrefslogtreecommitdiff
path: root/rtl/legacy_gfx/gfx_scanout.sv
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2024-05-05 17:34:22 -0600
committerAlejandro Soto <alejandro@34project.org>2024-05-05 17:38:27 -0600
commit081a8a3ba8bfe036f31da53f9c041a2caa30fce2 (patch)
tree7d712b67d3dc1ad3d37041562774ba3c4e5a7f49 /rtl/legacy_gfx/gfx_scanout.sv
parente5b64ea353678baabd16d245fcfaa3384e1acf8f (diff)
rtl/legacy_gfx: rename gfx -> legacy_gfx
Diffstat (limited to 'rtl/legacy_gfx/gfx_scanout.sv')
-rw-r--r--rtl/legacy_gfx/gfx_scanout.sv138
1 files changed, 138 insertions, 0 deletions
diff --git a/rtl/legacy_gfx/gfx_scanout.sv b/rtl/legacy_gfx/gfx_scanout.sv
new file mode 100644
index 0000000..a43d14c
--- /dev/null
+++ b/rtl/legacy_gfx/gfx_scanout.sv
@@ -0,0 +1,138 @@
+`include "gfx/gfx_defs.sv"
+
+module gfx_scanout
+(
+ input logic clk,
+ rst_n,
+
+ input logic enable_clear,
+ input rgb24 clear_color,
+ input vram_addr scan_base,
+
+ input logic mask,
+ output linear_coord mask_addr,
+
+ input logic fb_waitrequest,
+ fb_readdatavalid,
+ input vram_word fb_readdata,
+ output logic fb_read,
+ output vram_addr fb_address,
+
+ input logic scan_ready,
+ output logic scan_valid,
+ scan_endofpacket,
+ scan_startofpacket,
+ output rgb30 scan_data,
+
+ output logic vsync
+);
+
+ 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, next_vsync, start_vsync, wait_vsync;
+
+ vram_word fb_fifo_out;
+ half_coord commit_addr, mask_in_addr, mask_out_addr, mask_hold_addr, max_addr;
+
+ 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 fb_ready = !fb_read || !fb_waitrequest;
+ assign next_vsync = commit && start_vsync;
+ assign start_vsync = mask_hold_addr == max_addr;
+ assign effective_mask = mask || !enable_clear;
+
+ gfx_flush_flow #(.STAGES(`GFX_MASK_STAGES)) mask_flow
+ (
+ .in_valid(!wait_vsync),
+ .out_ready(fb_ready && mask_fifo_ready && !next_vsync),
+ .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(vram_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
+ put <= 0;
+ fb_read <= 0;
+ wait_vsync <= 0;
+ commit_addr <= 0;
+ mask_in_addr <= 0;
+ end else begin
+ mask_in_addr <= mask_in_addr + 1;
+
+ if (flush || wait_vsync)
+ mask_in_addr <= commit_addr;
+
+ if (commit) begin
+ wait_vsync <= start_vsync;
+ commit_addr <= start_vsync ? 0 : mask_out_addr;
+ end
+
+ if (fb_ready)
+ fb_read <= mask_fifo_ready && pop && !next_vsync && effective_mask;
+
+ if (mask_fifo_ready)
+ put <= fb_ready && pop && !next_vsync;
+
+ if (vsync)
+ wait_vsync <= 0;
+ end
+
+ always_ff @(posedge clk) begin
+ mask_hold_addr <= mask_out_addr;
+
+ if (fb_ready)
+ fb_address <= scan_base + {5'd0, mask_out_addr};
+
+ if (mask_fifo_ready)
+ put_mask <= effective_mask;
+ end
+
+endmodule