summaryrefslogtreecommitdiff
path: root/rtl
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2023-10-29 15:35:42 -0600
committerAlejandro Soto <alejandro@34project.org>2023-10-29 16:12:33 -0600
commitadabbf5f30729092a64fa1059bbc7d7b09d6b24e (patch)
tree4a4db581d233bcfda18d5e8f2e5606365d52852c /rtl
parent98d493f9c80f356cdbc2669150d772e451c3b80e (diff)
rtl/gfx: implement double-buffered scanout
Diffstat (limited to 'rtl')
-rw-r--r--rtl/gfx/gfx.sv45
-rw-r--r--rtl/gfx/gfx_defs.sv23
-rw-r--r--rtl/gfx/gfx_mask_sram.sv31
-rw-r--r--rtl/gfx/gfx_masks.sv53
-rw-r--r--rtl/gfx/gfx_scanout.sv173
-rw-r--r--rtl/top/test_fb.sv8
6 files changed, 331 insertions, 2 deletions
diff --git a/rtl/gfx/gfx.sv b/rtl/gfx/gfx.sv
index bae65e3..7749c50 100644
--- a/rtl/gfx/gfx.sv
+++ b/rtl/gfx/gfx.sv
@@ -17,7 +17,13 @@ module gfx
output logic[25:0] mem_address,
output logic mem_read,
mem_write,
- output logic[15:0] mem_writedata
+ output logic[15:0] mem_writedata,
+
+ input logic scan_ready,
+ output logic scan_valid,
+ scan_endofpacket,
+ scan_startofpacket,
+ output rgb30 scan_data
);
fp readdata, writedata;
@@ -60,6 +66,43 @@ module gfx
.*
);
+ logic frag_mask, scan_mask;
+
+ gfx_masks masks
+ (
+ .frag_mask_set(0),
+ .frag_mask_write(0),
+ .frag_mask_read_addr(),
+ .frag_mask_write_addr(),
+ .*
+ );
+
+ logic swap_buffers;
+ rgb24 clear_color;
+
+ assign swap_buffers = 0;
+ assign clear_color.r = 255;
+ assign clear_color.g = 0;
+ assign clear_color.b = 0;
+
+ linear_coord scan_mask_addr;
+
+ logic scanout_read_tmp;
+
+ gfx_scanout scanout
+ (
+ .mask(scan_mask),
+ .mask_addr(scan_mask_addr),
+
+ .fb_read(scanout_read_tmp),
+ .fb_address(),
+ .fb_readdata(),
+ .fb_waitrequest(0),
+ .fb_readdatavalid(scanout_read_tmp),
+
+ .*
+ );
+
logic[63:0] cnt_cycles, cnt_trans, snp_cycles, snp_trans;
logic[24:0] cnt_addr;
logic[31:0] cnt_done, cnt_start;
diff --git a/rtl/gfx/gfx_defs.sv b/rtl/gfx/gfx_defs.sv
index b1f8bb8..01b7116 100644
--- a/rtl/gfx/gfx_defs.sv
+++ b/rtl/gfx/gfx_defs.sv
@@ -20,4 +20,27 @@ typedef logic[1:0] index4;
`define INDEX4_MIN 2'b00
`define INDEX4_MAX 2'b11
+typedef logic[9:0] y_coord;
+typedef logic[8:0] x_coord;
+typedef logic[18:0] linear_coord;
+typedef logic[19:0] half_coord;
+
+`define GFX_X_RES 640
+`define GFX_Y_RES 480
+`define GFX_LINEAR_RES (`GFX_X_RES * `GFX_Y_RES)
+
+typedef struct packed
+{
+ logic[7:0] r, g, b;
+} rgb24;
+
+typedef struct packed
+{
+ logic[9:0] r, g, b;
+} rgb30;
+
+`define GFX_MASK_SRAM_STAGES 3
+`define GFX_MASK_STAGES (1 + `GFX_MASK_SRAM_STAGES + 1)
+`define GFX_SCAN_STAGES 3 // Ajustable
+
`endif
diff --git a/rtl/gfx/gfx_mask_sram.sv b/rtl/gfx/gfx_mask_sram.sv
new file mode 100644
index 0000000..730ee12
--- /dev/null
+++ b/rtl/gfx/gfx_mask_sram.sv
@@ -0,0 +1,31 @@
+`include "gfx/gfx_defs.sv"
+
+module gfx_mask_sram
+(
+ input logic clk,
+
+ input logic set,
+ write,
+ input linear_coord write_addr,
+ read_addr,
+ output logic mask
+);
+
+ logic mem[`GFX_LINEAR_RES];
+ logic mask_hold, write_hold, set_hold;
+ linear_coord read_addr_hold, write_addr_hold;
+
+ always_ff @(posedge clk) begin
+ mask <= mask_hold;
+ mask_hold <= mem[read_addr_hold];
+ read_addr_hold <= read_addr;
+
+ set_hold <= set;
+ write_hold <= write;
+ write_addr_hold <= write_addr;
+
+ if (write_hold)
+ mem[write_addr_hold] <= set_hold;
+ end
+
+endmodule
diff --git a/rtl/gfx/gfx_masks.sv b/rtl/gfx/gfx_masks.sv
new file mode 100644
index 0000000..86d1b78
--- /dev/null
+++ b/rtl/gfx/gfx_masks.sv
@@ -0,0 +1,53 @@
+`include "gfx/gfx_defs.sv"
+
+module gfx_masks
+(
+ input logic clk,
+
+ input logic swap_buffers,
+
+ input linear_coord scan_mask_addr,
+ output logic scan_mask,
+
+ input logic frag_mask_write,
+ frag_mask_set,
+ input linear_coord frag_mask_read_addr,
+ frag_mask_write_addr,
+ output logic frag_mask
+);
+
+ logic mask_a, mask_b, frag_write_hold, frag_set_hold;
+ linear_coord scan_addr_hold, frag_write_addr_hold, frag_read_addr_hold;
+
+ gfx_mask_sram sram_a
+ (
+ .set(frag_set_hold),
+ .mask(mask_a),
+ .write(swap_buffers && frag_write_hold),
+ .read_addr(swap_buffers ? frag_read_addr_hold : scan_addr_hold),
+ .write_addr(frag_write_addr_hold),
+ .*
+ );
+
+ gfx_mask_sram sram_b
+ (
+ .set(frag_set_hold),
+ .mask(mask_b),
+ .write(!swap_buffers && frag_write_hold),
+ .read_addr(swap_buffers ? scan_addr_hold : frag_read_addr_hold),
+ .write_addr(frag_write_addr_hold),
+ .*
+ );
+
+ always_ff @(posedge clk) begin
+ scan_mask <= swap_buffers ? mask_b : mask_a;
+ scan_addr_hold <= scan_mask_addr;
+
+ frag_mask <= swap_buffers ? mask_a : mask_b;
+ frag_set_hold <= frag_mask_set;
+ frag_write_hold <= frag_mask_write;
+ frag_read_addr_hold <= frag_mask_read_addr;
+ frag_write_addr_hold <= frag_mask_write_addr;
+ end
+
+endmodule
diff --git a/rtl/gfx/gfx_scanout.sv b/rtl/gfx/gfx_scanout.sv
new file mode 100644
index 0000000..7d2346b
--- /dev/null
+++ b/rtl/gfx/gfx_scanout.sv
@@ -0,0 +1,173 @@
+`include "gfx/gfx_defs.sv"
+
+module gfx_scanout
+(
+ input logic clk,
+ rst_n,
+
+ input rgb24 clear_color,
+
+ input logic mask,
+ output linear_coord mask_addr,
+
+ input logic fb_waitrequest,
+ fb_readdatavalid,
+ input logic[15:0] fb_readdata,
+ output logic fb_read,
+ output half_coord fb_address,
+
+ input logic scan_ready,
+ output logic scan_valid,
+ scan_endofpacket,
+ scan_startofpacket,
+ output rgb30 scan_data
+);
+
+ 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 foreground, foreground_valid, partial, put_fb_valid, put_src_valid,
+ queued_dec, queued_inc, read_half, read_valid, request_flush;
+
+ rgb24 fb_pipes[`GFX_SCAN_STAGES + 1], scan_pixel;
+ half_coord commit_pos, next_pos, read_pos, request_pos[`GFX_MASK_STAGES - 1:0];
+ logic[15:0] half;
+ linear_coord scan_pos, last_pos;
+
+ 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;
+
+ assign queued_inc = !request_flush && read_valid && read_half && mask;
+ assign queued_dec = fb_ready[`GFX_SCAN_STAGES - 1] && fb_valid[`GFX_SCAN_STAGES - 1];
+
+ genvar i;
+ generate
+ for (i = 0; i < `GFX_SCAN_STAGES; ++i) begin: stages
+ 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]),
+ .*
+ );
+
+ 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
+
+ always_ff @(posedge clk or negedge rst_n)
+ if (!rst_n) begin
+ queued <= 0;
+
+ read_pos <= 0;
+ scan_pos <= 0;
+ commit_pos <= 0;
+
+ fb_read <= 0;
+ partial <= 0;
+
+ put_fb_valid <= 0;
+ put_src_valid <= 0;
+ request_valid[0] <= 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;
+
+ partial <= partial ^ fb_readdatavalid;
+
+ put_fb_valid <= partial && fb_readdatavalid;
+ request_valid[0] <= !request_flush;
+
+ read_pos <= next_pos + 1;
+ if (next_pos == {last_pos, 1'b1})
+ read_pos <= 0;
+
+ if (!fb_waitrequest)
+ fb_read <= 0;
+
+ if (src_ready[0])
+ put_src_valid <= 0;
+
+ if (!request_flush) begin
+ fb_read <= read_valid && mask;
+ put_src_valid <= read_valid && read_half;
+
+ if (read_valid)
+ commit_pos <= request_pos[`GFX_MASK_STAGES - 1];
+ end
+ end
+
+ always_ff @(posedge clk) begin
+ request_pos[0] <= read_pos;
+
+ if (!request_flush) begin
+ fb_address <= request_pos[`GFX_MASK_STAGES - 1];
+ src_pipes[0] <= mask;
+ end
+
+ if (fb_readdatavalid) begin
+ if (partial)
+ fb_pipes[0] <= {fb_readdata[7:0], half};
+ else
+ half <= fb_readdata;
+ end
+ end
+
+endmodule
diff --git a/rtl/top/test_fb.sv b/rtl/top/test_fb.sv
index d305d68..f784342 100644
--- a/rtl/top/test_fb.sv
+++ b/rtl/top/test_fb.sv
@@ -15,7 +15,13 @@ module test_fb
output logic[25:0] mem_address,
output logic mem_read,
mem_write,
- output logic[15:0] mem_writedata
+ output logic[15:0] mem_writedata,
+
+ input logic scan_ready,
+ output logic scan_valid,
+ scan_endofpacket,
+ scan_startofpacket,
+ output logic[29:0] scan_data
);
gfx dut