diff options
| author | Alejandro Soto <alejandro@34project.org> | 2023-10-29 15:35:42 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2023-10-29 16:12:33 -0600 |
| commit | adabbf5f30729092a64fa1059bbc7d7b09d6b24e (patch) | |
| tree | 4a4db581d233bcfda18d5e8f2e5606365d52852c /rtl | |
| parent | 98d493f9c80f356cdbc2669150d772e451c3b80e (diff) | |
rtl/gfx: implement double-buffered scanout
Diffstat (limited to 'rtl')
| -rw-r--r-- | rtl/gfx/gfx.sv | 45 | ||||
| -rw-r--r-- | rtl/gfx/gfx_defs.sv | 23 | ||||
| -rw-r--r-- | rtl/gfx/gfx_mask_sram.sv | 31 | ||||
| -rw-r--r-- | rtl/gfx/gfx_masks.sv | 53 | ||||
| -rw-r--r-- | rtl/gfx/gfx_scanout.sv | 173 | ||||
| -rw-r--r-- | rtl/top/test_fb.sv | 8 |
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 |
