summaryrefslogtreecommitdiff
path: root/rtl/gfx
diff options
context:
space:
mode:
authorAlejandro Soto <alejandro@34project.org>2023-11-19 17:16:58 -0600
committerAlejandro Soto <alejandro@34project.org>2023-11-20 16:46:28 -0600
commit33794ca29db5670bc140686ae6e6d3b7832ad406 (patch)
treec9d66a2aea3d7c725b9b088896e74c6eed751d71 /rtl/gfx
parent6658a8b5c179682866c89c891b493d05d13a50be (diff)
rtl/gfx: implement SP fetch
Diffstat (limited to '')
-rw-r--r--rtl/gfx/gfx.sv17
-rw-r--r--rtl/gfx/gfx_defs.sv16
-rw-r--r--rtl/gfx/gfx_sp.sv33
-rw-r--r--rtl/gfx/gfx_sp_fetch.sv226
-rw-r--r--rtl/gfx/gfx_sp_widener.sv63
5 files changed, 352 insertions, 3 deletions
diff --git a/rtl/gfx/gfx.sv b/rtl/gfx/gfx.sv
index 9169665..5fa3f35 100644
--- a/rtl/gfx/gfx.sv
+++ b/rtl/gfx/gfx.sv
@@ -26,14 +26,23 @@ module gfx
output rgb30 scan_data
);
- logic enable_clear, start_clear, swap_buffers;
+ logic enable_clear, program_start, start_clear, swap_buffers;
rgb24 clear_color;
+ cmd_word program_header_base, program_header_size;
gfx_cmd cmd
(
.*
);
+ logic fetch_read;
+ vram_addr fetch_address;
+
+ gfx_sp sp
+ (
+ .*
+ );
+
logic frag_mask, scan_mask;
gfx_masks masks
@@ -115,8 +124,10 @@ module gfx
.*
);
- logic fb_readdatavalid, fb_waitrequest, rop_waitrequest;
- vram_word fb_readdata;
+ logic fetch_readdatavalid, fb_readdatavalid,
+ fetch_waitrequest, fb_waitrequest, rop_waitrequest;
+
+ vram_word fetch_readdata, fb_readdata;
gfx_mem mem
(
diff --git a/rtl/gfx/gfx_defs.sv b/rtl/gfx/gfx_defs.sv
index 34fef4d..0aa4055 100644
--- a/rtl/gfx/gfx_defs.sv
+++ b/rtl/gfx/gfx_defs.sv
@@ -168,7 +168,23 @@ typedef logic[`GFX_MEM_DATA_BITS - 1:0] vram_word;
typedef logic[`GFX_MEM_ADDR_BITS - 1:0] vram_byte_addr;
typedef logic[`GFX_MEM_WORD_ADDR_BITS - 1:0] vram_addr;
+`define GFX_INSN_BITS 32
+`define GFX_INSN_ADDR_BITS (`GFX_MEM_WORD_ADDR_BITS - $clog2(`GFX_INSN_BITS / `GFX_MEM_DATA_BITS))
+`define GFX_INSN_SUBWORD_BITS (`GFX_MEM_ADDR_BITS - `GFX_INSN_ADDR_BITS)
+
+typedef logic[`GFX_INSN_BITS - 1:0] insn_word;
+typedef logic[`GFX_INSN_ADDR_BITS - 1:0] vram_insn_addr;
+
typedef logic[5:0] cmd_addr;
typedef logic[31:0] cmd_word;
+typedef struct packed
+{
+ logic[$bits(cmd_word) - $bits(vram_insn_addr) - `GFX_INSN_SUBWORD_BITS - 1:0] pad;
+ vram_insn_addr addr;
+ logic[`GFX_INSN_SUBWORD_BITS - 1:0] sub;
+} cmd_insn_ptr;
+
+`define GFX_FETCH_FIFO_DEPTH 8
+
`endif
diff --git a/rtl/gfx/gfx_sp.sv b/rtl/gfx/gfx_sp.sv
new file mode 100644
index 0000000..b0e36aa
--- /dev/null
+++ b/rtl/gfx/gfx_sp.sv
@@ -0,0 +1,33 @@
+`include "gfx/gfx_defs.sv"
+
+module gfx_sp
+(
+ input logic clk,
+ rst_n,
+
+ input logic fetch_waitrequest,
+ fetch_readdatavalid,
+ input vram_word fetch_readdata,
+ output vram_addr fetch_address,
+ output logic fetch_read,
+
+ input logic program_start,
+ input cmd_word program_header_base,
+ program_header_size
+);
+
+ logic batch_start, clear_lanes, running;
+ cmd_word batch_length;
+ insn_word insn;
+ vram_insn_addr batch_base;
+
+ gfx_sp_fetch fetch
+ (
+ .ready(1),
+ .valid(),
+ .*
+ );
+
+ logic batch_end;
+
+endmodule
diff --git a/rtl/gfx/gfx_sp_fetch.sv b/rtl/gfx/gfx_sp_fetch.sv
new file mode 100644
index 0000000..986862b
--- /dev/null
+++ b/rtl/gfx/gfx_sp_fetch.sv
@@ -0,0 +1,226 @@
+`include "gfx/gfx_defs.sv"
+
+module gfx_sp_fetch
+(
+ input logic clk,
+ rst_n,
+
+ input logic fetch_waitrequest,
+ fetch_readdatavalid,
+ input vram_word fetch_readdata,
+ output vram_addr fetch_address,
+ output logic fetch_read,
+
+ input logic program_start,
+ input cmd_insn_ptr program_header_base,
+ input cmd_word program_header_size,
+ output logic running,
+
+ input logic batch_end,
+ output vram_insn_addr batch_base,
+ output logic batch_start,
+ output cmd_word batch_length,
+
+ input logic ready,
+ output logic valid,
+ output insn_word insn,
+ output logic clear_lanes
+);
+
+ localparam ENTRY_SIZE = 4;
+
+ logic break_loop, entry_end, fifo_down, fifo_up, fifo_put, header_continue,
+ insn_read, insn_readdatavalid, insn_waitrequest;
+
+ cmd_word header_count;
+ insn_word code_length, code_read_ptr, code_fetch_ptr, insn_readdata, entry_data[ENTRY_SIZE];
+ vram_insn_addr code_base, insn_address, header_ptr;
+ logic[$clog2(ENTRY_SIZE - 1):0] entry_fetch_count, entry_read_count;
+ logic[$clog2(`GFX_FETCH_FIFO_DEPTH + 1) - 1:0] fifo_pending;
+
+ enum int unsigned
+ {
+ IDLE,
+ HEADER,
+ LOOP,
+ FLUSH
+ } state;
+
+ struct packed
+ {
+ insn_word insn;
+ logic clear_lanes;
+ } fifo_in, fifo_out;
+
+ assign insn = fifo_out.insn;
+ assign clear_lanes = fifo_out.clear_lanes;
+
+ assign entry_end = entry_read_count == ENTRY_SIZE - 1;
+ assign header_continue = header_count != 0;
+ assign break_loop = batch_end && (!insn_read || !insn_waitrequest);
+
+ function vram_insn_addr base_from_word(insn_word in);
+ base_from_word = in[$bits(in) - 1:$bits(in) - $bits(vram_insn_addr)];
+ endfunction
+
+ assign code_base = base_from_word(entry_data[0]);
+ assign batch_base = base_from_word(entry_data[2]);
+ assign code_length = entry_data[1];
+ assign batch_length = entry_data[3];
+
+ assign fifo_up = ready && valid;
+ assign fifo_down = insn_read && !insn_waitrequest;
+
+ gfx_sp_widener #(.WIDTH($bits(vram_insn_addr))) insn_bus
+ (
+ .wide_read(insn_read),
+ .wide_address(insn_address),
+ .wide_readdata(insn_readdata),
+ .wide_waitrequest(insn_waitrequest),
+ .wide_readdatavalid(insn_readdatavalid),
+ .word_read(fetch_read),
+ .word_address(fetch_address),
+ .word_readdata(fetch_readdata),
+ .word_waitrequest(fetch_waitrequest),
+ .word_readdatavalid(fetch_readdatavalid),
+ .*
+ );
+
+ gfx_fifo #(.WIDTH($bits(fifo_in)), .DEPTH(`GFX_FETCH_FIFO_DEPTH)) insn_fifo
+ (
+ .in(fifo_in),
+ .out(fifo_out),
+ .in_ready(),
+ .in_valid(fifo_put),
+ .out_ready(ready),
+ .out_valid(valid),
+ .*
+ );
+
+ always_ff @(posedge clk or negedge rst_n)
+ if (!rst_n) begin
+ state <= IDLE;
+ running <= 0;
+ fifo_put <= 0;
+ insn_read <= 0;
+ batch_start <= 0;
+ fifo_pending <= 0;
+ end else begin
+ unique case (state)
+ IDLE:
+ if (program_start) begin
+ state <= HEADER;
+ running <= 1;
+ insn_read <= 1;
+ end
+
+ HEADER: begin
+ if (insn_read && !insn_waitrequest)
+ insn_read <= entry_fetch_count == ENTRY_SIZE - 1;
+
+ if (insn_readdatavalid && entry_end) begin
+ state <= LOOP;
+ insn_read <= 1;
+ batch_start <= 1;
+ end
+ end
+
+ LOOP: begin
+ fifo_put <= 0;
+ batch_start <= 0;
+
+ if (!insn_read || !insn_waitrequest)
+ insn_read <= fifo_pending < `GFX_FETCH_FIFO_DEPTH - 1;
+
+ if (break_loop) begin
+ state <= FLUSH;
+ insn_read <= 0;
+ end
+
+ if (insn_readdatavalid)
+ fifo_put <= 1;
+ end
+
+ FLUSH: begin
+ fifo_put <= 0;
+
+ if (fifo_pending == 0) begin
+ state <= header_continue ? HEADER : IDLE;
+ running <= header_continue;
+ insn_read <= header_continue;
+ end
+ end
+ endcase
+
+ if (fifo_up && !fifo_down)
+ fifo_pending <= fifo_pending - 1;
+ else if (!fifo_up && fifo_down)
+ fifo_pending <= fifo_pending + 1;
+ end
+
+ always_ff @(posedge clk)
+ unique case (state)
+ IDLE:
+ if (program_start) begin
+ header_ptr <= program_header_base.addr;
+ header_count <= program_header_size;
+ insn_address <= program_header_base.addr;
+
+ entry_read_count <= 0;
+ entry_fetch_count <= 0;
+ end
+
+ HEADER: begin
+ code_read_ptr <= 0;
+ code_fetch_ptr <= 0;
+
+ if (!insn_waitrequest) begin
+ insn_address <= insn_address + 1;
+ entry_fetch_count <= entry_fetch_count + 1;
+ end
+
+ if (insn_read && !insn_waitrequest)
+ header_ptr <= header_ptr + 1;
+
+ if (insn_readdatavalid) begin
+ entry_read_count <= entry_read_count + 1;
+
+ for (integer i = 0; i < ENTRY_SIZE - 1; ++i)
+ entry_data[i] <= entry_data[i + 1];
+
+ entry_data[ENTRY_SIZE - 1] <= insn_readdata;
+
+ if (entry_end)
+ insn_address <= base_from_word(entry_data[1]);
+ end
+ end
+
+ LOOP: begin
+ if (insn_read && !insn_waitrequest) begin
+ insn_address <= insn_address + 1;
+ code_fetch_ptr <= code_fetch_ptr + 1;
+
+ if (code_fetch_ptr == code_length) begin
+ insn_address <= code_base;
+ code_fetch_ptr <= 0;
+ end
+ end
+
+ if (insn_readdatavalid) begin
+ fifo_in.insn <= insn_readdata;
+ fifo_in.clear_lanes <= code_read_ptr == 0;
+
+ code_read_ptr <= code_read_ptr + 1;
+ if (code_read_ptr == code_length)
+ code_read_ptr <= 0;
+ end
+ end
+
+ FLUSH:
+ if (fifo_pending == 0) begin
+ header_count <= header_count - 1;
+ insn_address <= header_ptr;
+ end
+ endcase
+
+endmodule
diff --git a/rtl/gfx/gfx_sp_widener.sv b/rtl/gfx/gfx_sp_widener.sv
new file mode 100644
index 0000000..92101ca
--- /dev/null
+++ b/rtl/gfx/gfx_sp_widener.sv
@@ -0,0 +1,63 @@
+`include "gfx/gfx_defs.sv"
+
+module gfx_sp_widener
+#(parameter WIDTH=0) // Quartus no soporta 'parameter type'
+(
+ input logic clk,
+ rst_n,
+
+ input logic word_waitrequest,
+ word_readdatavalid,
+ input vram_word word_readdata,
+ output vram_addr word_address,
+ output logic word_read,
+
+ input logic wide_read,
+ input logic[WIDTH - 1:0] wide_address,
+ output logic wide_waitrequest,
+ wide_readdatavalid,
+
+ output logic[DATA_WIDTH - 1:0] wide_readdata
+);
+
+ // Este módulo existe para fingir que la DE1-SoC tiene un bus de SDRAM más ancho
+
+ localparam WIDE_BITS = $bits(vram_addr) - WIDTH,
+ WIDE_SIZE = 1 << WIDE_BITS,
+ DATA_WIDTH = $bits(vram_word) << WIDE_BITS;
+
+ vram_word shift_in[WIDE_SIZE];
+ logic[WIDE_BITS - 1:0] address_count, read_count;
+
+ assign word_read = wide_read;
+ assign word_address = {wide_address, address_count};
+ assign wide_waitrequest = word_waitrequest || !(&address_count);
+
+ always_comb
+ for (integer i = 0; i < WIDE_SIZE; ++i)
+ wide_readdata[$bits(vram_word) * i +: $bits(vram_word)] = shift_in[i];
+
+ always_ff @(posedge clk or negedge rst_n)
+ if (!rst_n) begin
+ read_count <= 0;
+ address_count <= 0;
+ wide_readdatavalid <= 0;
+ end else begin
+ if (word_read && !word_waitrequest)
+ address_count <= address_count + 1;
+
+ if (word_readdatavalid)
+ read_count <= read_count + 1;
+
+ wide_readdatavalid <= word_readdatavalid && &read_count;
+ end
+
+ always_ff @(posedge clk)
+ if (word_readdatavalid) begin
+ for (integer i = 0; i < WIDE_SIZE - 1; ++i)
+ shift_in[i] <= shift_in[i + 1];
+
+ shift_in[WIDE_SIZE - 1] <= word_readdata;
+ end
+
+endmodule