diff options
Diffstat (limited to 'rtl')
| -rw-r--r-- | rtl/gfx/gfx.sv | 17 | ||||
| -rw-r--r-- | rtl/gfx/gfx_defs.sv | 16 | ||||
| -rw-r--r-- | rtl/gfx/gfx_sp.sv | 33 | ||||
| -rw-r--r-- | rtl/gfx/gfx_sp_fetch.sv | 226 | ||||
| -rw-r--r-- | rtl/gfx/gfx_sp_widener.sv | 63 |
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 |
