diff options
| author | Alejandro Soto <alejandro@34project.org> | 2024-03-15 21:57:34 -0600 |
|---|---|---|
| committer | Alejandro Soto <alejandro@34project.org> | 2024-03-15 21:57:34 -0600 |
| commit | f1270a246570eacc093c836337dc55546aabd399 (patch) | |
| tree | a76af6972b4aeff883bea74045ee1a2bf947bdac | |
| parent | eb49b6d871825eaea4e93d47a4368df368b7101a (diff) | |
platform/wavelet3d: implement rasterizer
Diffstat (limited to '')
| -rw-r--r-- | platform/wavelet3d/gfx_ctz.sv | 18 | ||||
| -rw-r--r-- | platform/wavelet3d/gfx_pipes.sv | 24 | ||||
| -rw-r--r-- | platform/wavelet3d/gfx_pkg.sv | 109 | ||||
| -rw-r--r-- | platform/wavelet3d/gfx_pkts.sv | 29 | ||||
| -rw-r--r-- | platform/wavelet3d/gfx_raster.sv | 895 | ||||
| -rw-r--r-- | platform/wavelet3d/gfx_top.sv | 31 |
6 files changed, 1103 insertions, 3 deletions
diff --git a/platform/wavelet3d/gfx_ctz.sv b/platform/wavelet3d/gfx_ctz.sv new file mode 100644 index 0000000..2713f8a --- /dev/null +++ b/platform/wavelet3d/gfx_ctz.sv @@ -0,0 +1,18 @@ +// Count trailing zeros (ctz), clz al revés +module gfx_ctz +#(int WIDTH = 0) +( + input logic clk, + + input logic[WIDTH - 1:0] value, + output logic[$clog2(WIDTH):0] ctz +); + + gfx_clz #(WIDTH) clz + ( + .clk, + .value({<<{value}}), + .clz(ctz) + ); + +endmodule diff --git a/platform/wavelet3d/gfx_pipes.sv b/platform/wavelet3d/gfx_pipes.sv new file mode 100644 index 0000000..2fa875a --- /dev/null +++ b/platform/wavelet3d/gfx_pipes.sv @@ -0,0 +1,24 @@ +module gfx_pipes +#(int WIDTH=0, int DEPTH=0) +( + input logic clk, + + input logic[WIDTH - 1:0] in, + input logic stall, + + output logic[WIDTH - 1:0] out +); + + logic[WIDTH - 1:0] pipes[DEPTH]; + + assign out = pipes[DEPTH - 1]; + + always_ff @(posedge clk) + if (~stall) begin + pipes[0] <= in; + + for (integer i = 1; i < DEPTH; ++i) + pipes[i] <= pipes[i - 1]; + end + +endmodule diff --git a/platform/wavelet3d/gfx_pkg.sv b/platform/wavelet3d/gfx_pkg.sv index 53bb8cd..3c4b747 100644 --- a/platform/wavelet3d/gfx_pkg.sv +++ b/platform/wavelet3d/gfx_pkg.sv @@ -1,7 +1,5 @@ package gfx; - localparam int SHADER_LANES = 4; - typedef logic[31:0] word; localparam int SUBWORD_BITS = $clog2($bits(word)) - $clog2($bits(byte)); @@ -240,6 +238,113 @@ package gfx; fixed_frac frac; } fixed; + typedef struct packed + { + fixed x, + y; + } fixed_xy; + + typedef struct packed + { + fixed a, + b, + c; + } vtx_fixed; + + typedef struct packed + { + fixed_xy a, + b, + c; + } vtx_xy; + + localparam int RASTER_BITS = 2; + localparam int RASTER_SUB_BITS = 4; + localparam int RASTER_SIZE = 1 << RASTER_BITS; + localparam int RASTER_COARSE_FRAGS = RASTER_SIZE * RASTER_SIZE; + + typedef logic[RASTER_BITS - 1:0] raster_index; + + // Caso RASTER_BITS = 2: -> 4,4,4,4 -> 8,8-> 16 + localparam int RASTER_OUT_CLZ_DEPTH = 3; + + // Asume RASTER_BITS == 2, hay que ajustarlo si cambia + typedef struct packed + { + // Esto ahorra muchos flops + // + // offsets[0] = inc * 0 = 0 + // offsets[1] = inc * 1 = raster2_times1 + // offsets[2] = inc * 2 = raster2_times1 << 1 + // offsets[3] = inc * 3 = raster2_times3 + fixed raster2_times1, + raster2_times3; + } raster_offsets; + + function fixed raster_idx(raster_offsets offsets, raster_index idx); + unique case (idx) + RASTER_BITS'(0): + return '0; + + RASTER_BITS'(1): + return offsets.raster2_times1; + + RASTER_BITS'(2): + return offsets.raster2_times1 << 1; + + RASTER_BITS'(3): + return offsets.raster2_times3; + endcase + endfunction + + function raster_offsets make_raster_offsets(fixed inc); + make_raster_offsets.raster2_times1 = inc; + make_raster_offsets.raster2_times3 = inc + (inc << 1); + endfunction + + typedef struct packed + { + raster_offsets x, + y; + } raster_offsets_xy; + + typedef struct packed + { + logic[RASTER_SUB_BITS - 1:0] num; + logic[$bits(fixed_frac) - RASTER_SUB_BITS - 1:0] prec; + } raster_sub; + + localparam int RASTER_COARSE_DIM_BITS = $bits(fixed) - $bits(raster_index) - $bits(raster_sub); + + typedef logic signed[RASTER_COARSE_DIM_BITS - 1:0] raster_coarse_dim; + + typedef struct packed + { + raster_coarse_dim x, + y; + } raster_coarse_xy; + + typedef struct packed signed + { + raster_coarse_dim coarse; + raster_index fine; + raster_sub sub; + } raster_prec; + + typedef struct packed + { + raster_prec x, + y; + } raster_prec_xy; + + // Definir el número de lanes a partir de las dimensiones del + // rasterizer es una decisión crucial, el diseño entero depende de esto + + localparam int SHADER_LANES = RASTER_COARSE_FRAGS; + + typedef logic[RASTER_SIZE - 1:0] lane_no; + typedef logic[SHADER_LANES - 1:0] lane_mask; + localparam int FIXED_MULADD_DEPTH = 5; localparam int FIXED_DOTADD_DEPTH = 2 * FIXED_MULADD_DEPTH; diff --git a/platform/wavelet3d/gfx_pkts.sv b/platform/wavelet3d/gfx_pkts.sv new file mode 100644 index 0000000..41399ce --- /dev/null +++ b/platform/wavelet3d/gfx_pkts.sv @@ -0,0 +1,29 @@ +interface gfx_pkts +#(parameter int WIDTH = $bits(gfx::word)); + + import gfx::*; + + logic tlast; + logic tready; + logic tvalid; + logic[WIDTH - 1:0] tdata; + + modport tx + ( + input tready, + + output tdata, + tlast, + tvalid + ); + + modport rx + ( + input tdata, + tlast, + tvalid, + + output tready + ); + +endinterface diff --git a/platform/wavelet3d/gfx_raster.sv b/platform/wavelet3d/gfx_raster.sv new file mode 100644 index 0000000..5d17625 --- /dev/null +++ b/platform/wavelet3d/gfx_raster.sv @@ -0,0 +1,895 @@ +module gfx_raster +( + input logic clk, + rst_n, + + gfx_pkts.rx geometry, + + gfx_pkts.tx coverage +); + + import gfx::*; + + gfx_raster_bounds setup_bounds + ( + .clk, + .rst_n, + + .geometry, + + .edges_ref(bounds_edges_ref), + .edges_vtx(bounds_edges_vtx), + .edges_span(bounds_edges_span), + .edges_ready(bounds_edges_ready), + .edges_valid(bounds_edges_valid), + .edges_geom_id(bounds_edges_geom_id) + ); + + word bounds_edges_geom_id; + logic bounds_edges_ready, bounds_edges_valid; + vtx_xy bounds_edges_vtx; + fixed_xy bounds_edges_ref; + raster_prec_xy bounds_edges_span; + + gfx_raster_edges setup_edges + ( + .clk, + .rst_n, + + .bounds_ref(bounds_edges_ref), + .bounds_vtx(bounds_edges_vtx), + .bounds_span(bounds_edges_span), + .bounds_ready(bounds_edges_ready), + .bounds_valid(bounds_edges_valid), + .bounds_geom_id(bounds_edges_geom_id), + + .coarse_ref(edges_coarse_ref), + .coarse_base(edges_coarse_base), + .coarse_span(edges_coarse_span), + .coarse_ready(edges_coarse_ready), + .coarse_valid(edges_coarse_valid), + .coarse_geom_id(edges_coarse_geom_id), + .coarse_offsets(edges_coarse_offsets) + ); + + word edges_coarse_geom_id; + fixed edges_coarse_base; + logic edges_coarse_ready, edges_coarse_valid; + fixed_xy edges_coarse_ref; + raster_prec_xy edges_coarse_span; + raster_offsets_xy edges_coarse_offsets; + + gfx_raster_coarse coarse + ( + .clk, + .rst_n, + + .edges_ref(edges_coarse_ref), + .edges_base(edges_coarse_base), + .edges_span(edges_coarse_span), + .edges_ready(edges_coarse_ready), + .edges_valid(edges_coarse_valid), + .edges_geom_id(edges_coarse_geom_id), + .edges_offsets(edges_coarse_offsets), + + .fine_ref(coarse_fine_ref), + .fine_ready(coarse_fine_ready), + .fine_valid(coarse_fine_valid), + .fine_corner(coarse_fine_corner), + .fine_geom_id(coarse_fine_geom_id), + .fine_offsets(coarse_fine_offsets) + ); + + word coarse_fine_geom_id; + fixed coarse_fine_corner; + logic coarse_fine_ready, coarse_fine_valid; + fixed_xy coarse_fine_ref; + raster_offsets_xy coarse_fine_offsets; + + gfx_raster_fine fine + ( + .clk, + .rst_n, + + .coarse_ref(coarse_fine_ref), + .coarse_ready(coarse_fine_ready), + .coarse_valid(coarse_fine_valid), + .coarse_corner(coarse_fine_corner), + .coarse_geom_id(coarse_fine_geom_id), + .coarse_offsets(coarse_fine_offsets), + + .coverage + ); + +endmodule + +module gfx_raster_bounds +( + input logic clk, + rst_n, + + gfx_pkts.rx geometry, + + input logic edges_ready, + output logic edges_valid, + output gfx::word edges_geom_id, + output gfx::fixed_xy edges_ref, + output gfx::raster_prec_xy edges_span, + output gfx::vtx_xy edges_vtx +); + + import gfx::*; + + enum int unsigned + { + IN_GEOM_ID, + IN_DIM_X, + IN_DIM_Y + } in_state; + + enum int unsigned + { + VTX_A, + VTX_B, + VTX_C + } vtx_state; + + logic a_lt_b, a_lt_c, b_lt_c, edges_handshake, geom_complete, geom_last, + geom_recv, in_vtx, next_dim, new_vtx; + + logic end_new_dim, end_valid, vtx_valid, lt_new_dim, lt_valid, minmax_new_dim, minmax_valid; + + fixed geom_data; + vtx_fixed dim_vtx, dim_vtx_x, dim_vtx_y; + raster_prec max, min; + + assign geom_recv = geometry.tready & geometry.tvalid; + assign edges_handshake = edges_valid & edges_ready; + + assign edges_vtx.a.x = dim_vtx_x.a; + assign edges_vtx.a.y = dim_vtx_y.a; + assign edges_vtx.b.x = dim_vtx_x.b; + assign edges_vtx.b.y = dim_vtx_y.b; + assign edges_vtx.c.x = dim_vtx_x.c; + assign edges_vtx.c.y = dim_vtx_y.c; + + assign geometry.tready = edges_handshake | ~geom_complete; + + always_comb begin + unique case (vtx_state) + VTX_C: next_dim = geom_recv; + default: next_dim = 0; + endcase + + unique case (in_state) + IN_DIM_Y: geom_last = next_dim; + default: geom_last = 0; + endcase + end + + always_ff @(posedge clk or negedge rst_n) + if (~rst_n) begin + in_state <= IN_GEOM_ID; + vtx_state <= VTX_A; + + in_vtx <= 0; + new_vtx <= 0; + geom_complete <= 0; + + lt_valid <= 0; + end_valid <= 0; + vtx_valid <= 0; + edges_valid <= 0; + minmax_valid <= 0; + + lt_new_dim <= 0; + end_new_dim <= 0; + minmax_new_dim <= 0; + + edges_geom_id <= 'x; + end else begin + end_valid <= 0; + vtx_valid <= end_valid; + lt_valid <= vtx_valid; + minmax_valid <= lt_valid; + + if (~edges_valid | edges_ready) + edges_valid <= minmax_valid; + + geom_complete <= (geom_complete | geom_last) & ~edges_handshake; + + unique case (in_state) + IN_GEOM_ID: + if (geom_recv) begin + in_state <= IN_DIM_X; + + in_vtx <= 1; + edges_geom_id <= geometry.tdata; + end + + IN_DIM_X: + if (next_dim) + in_state <= IN_DIM_Y; + + IN_DIM_Y: + if (next_dim) begin + in_state <= IN_GEOM_ID; + + in_vtx <= 0; + end_valid <= 1; + end + endcase + + new_vtx <= 0; + + lt_new_dim <= 0; + minmax_new_dim <= lt_new_dim; + end_new_dim <= minmax_new_dim; + + unique case (vtx_state) + VTX_A: begin + if (in_vtx & geom_recv) begin + new_vtx <= 1; + vtx_state <= VTX_B; + end + + if (new_vtx) begin + dim_vtx.c <= geom_data; + lt_new_dim <= 1; + end + end + + VTX_B: begin + if (geom_recv) begin + new_vtx <= 1; + vtx_state <= VTX_C; + end + + if (new_vtx) + dim_vtx.a <= geom_data; + end + + VTX_C: begin + if (geom_recv) begin + new_vtx <= 1; + vtx_state <= VTX_A; + end + + if (new_vtx) + dim_vtx.b <= geom_data; + end + endcase + + if (in_state == IN_DIM_Y & next_dim) + assert(geometry.tlast); + end + + always_ff @(posedge clk) begin + geom_data <= geometry.tdata; + + a_lt_b <= $signed(dim_vtx.a) < $signed(dim_vtx.b); + a_lt_c <= $signed(dim_vtx.a) < $signed(dim_vtx.c); + b_lt_c <= $signed(dim_vtx.b) < $signed(dim_vtx.c); + + // Realmente no son 'x' o 'y' hasta cuando edges_valid = 1 + if (lt_new_dim) begin + dim_vtx_y <= dim_vtx; + dim_vtx_x <= dim_vtx_y; + end + + if (a_lt_b) begin + min <= a_lt_c ? dim_vtx_y.a : dim_vtx_y.c; + max <= b_lt_c ? dim_vtx_y.c : dim_vtx_y.b; + end else begin + min <= b_lt_c ? dim_vtx_y.b : dim_vtx_y.c; + max <= a_lt_c ? dim_vtx_y.c : dim_vtx_y.a; + end + + {min.fine, min.sub} <= '0; + {max.fine, max.sub} <= '0; + + edges_ref.y <= min; + edges_span.y <= max - min; + + if (end_new_dim) begin + edges_ref.x <= edges_ref.y; + edges_span.x <= edges_span.y; + end + end + +endmodule + +module gfx_raster_edges +( + input logic clk, + rst_n, + + input logic bounds_valid, + input gfx::word bounds_geom_id, + input gfx::fixed_xy bounds_ref, + input gfx::raster_prec_xy bounds_span, + input gfx::vtx_xy bounds_vtx, + output logic bounds_ready, + + input logic coarse_ready, + output logic coarse_valid, + output gfx::word coarse_geom_id, + output gfx::fixed_xy coarse_ref, + output gfx::raster_prec_xy coarse_span, + output gfx::fixed coarse_base, + output gfx::raster_offsets_xy coarse_offsets +); + + import gfx::*; + + logic coarse_handshake, coarse_stall, offsets_flow; + fixed_xy delta, inc, p, q; + + // - 3 porque empieza antes que offsets y porque coarse valid va al final + logic[FIXED_DOTADD_DEPTH - 3:0] dotadd_valid; + + enum int unsigned + { + EDGE_AB, + EDGE_BC, + EDGE_CA + } state; + + assign coarse_stall = coarse_valid & ~coarse_ready; + assign coarse_handshake = coarse_valid & coarse_ready; + + gfx_fixed_dotadd edge_base + ( + .clk, + .c(0), + .q(coarse_base), + .a0(delta.x), + .b0(inc.x), + .a1(delta.y), + .b1(inc.y), + .stall(coarse_stall) + ); + + always_ff @(posedge clk or negedge rst_n) + if (~rst_n) begin + state <= EDGE_AB; + + p <= 'x; + q <= 'x; + coarse_ref <= 'x; + coarse_geom_id <= 'x; + + bounds_ready <= 0; + coarse_valid <= 0; + offsets_flow <= 1; + + for (int i = 0; i < $bits(dotadd_valid) - 1; ++i) + dotadd_valid[i] <= 0; + end else begin + dotadd_valid[0] <= 0; + for (int i = 1; i < $bits(dotadd_valid); ++i) + dotadd_valid[i] <= dotadd_valid[i - 1]; + + if (~coarse_stall) + coarse_valid <= dotadd_valid[$bits(dotadd_valid) - 1]; + + bounds_ready <= 0; + + unique case (state) + EDGE_AB: begin + if (bounds_valid) + state <= EDGE_BC; + + coarse_ref <= bounds_ref; + coarse_span <= bounds_span; + coarse_geom_id <= bounds_geom_id; + + p <= bounds_vtx.a; + q <= bounds_vtx.b; + end + + EDGE_BC: begin + state <= EDGE_CA; + bounds_ready <= 1; + + p <= bounds_vtx.b; + q <= bounds_vtx.c; + end + + EDGE_CA: begin + p <= bounds_vtx.c; + q <= bounds_vtx.a; + + // Esto ocurre justamente en un momento en que ab, bc, ca + // quedan todos en sus lugares correctos en la pipeline + if (offsets_flow) begin + offsets_flow <= 0; + dotadd_valid[0] <= 1; + end else begin + offsets_flow <= coarse_handshake; + + if (coarse_handshake) + state <= EDGE_AB; + end + end + endcase + end + + always_ff @(posedge clk) begin + //TODO: top-left rule + delta.x <= coarse_ref.x - q.x; + delta.y <= coarse_ref.y - q.y; + + if (offsets_flow) begin + inc.x <= p.y - q.y; + inc.y <= q.x - p.x; + + coarse_offsets.x <= make_raster_offsets(inc.x); + coarse_offsets.y <= make_raster_offsets(inc.y); + end + end + +endmodule + +module gfx_raster_coarse +( + input logic clk, + rst_n, + + input logic edges_valid, + input gfx::word edges_geom_id, + input gfx::fixed_xy edges_ref, + input gfx::raster_prec_xy edges_span, + input gfx::fixed edges_base, + input gfx::raster_offsets_xy edges_offsets, + output logic edges_ready, + + input logic fine_ready, + output logic fine_valid, + output gfx::word fine_geom_id, + output gfx::fixed_xy fine_ref, + output gfx::fixed fine_corner, + output gfx::raster_offsets_xy fine_offsets +); + + import gfx::*; + + enum int unsigned + { + SETUP, + TEST_AB, + TEST_BC, + TEST_CA, + OUT + } state; + + struct + { + fixed cur, + next, + prev; + } corner, edge_fn, vertical; + + struct + { + raster_offsets_xy cur, + next, + prev; + } offsets; + + fixed edge_test, reference_x, vertical_inc; + logic edges_recv, end_x, end_y, mask, mask_reset, new_geom, test_flow, out_flow; + fixed_xy max_offset, min_offset, test_offset; + raster_coarse_xy stride; + raster_coarse_dim width; + raster_offsets_xy next_offsets; + + function fixed coarse_offset(raster_offsets offsets); + return raster_idx(offsets, RASTER_BITS'(1)) << RASTER_BITS; + endfunction + + assign end_x = stride.x == '0; + assign end_y = stride.y == '0; + + assign edge_test = edge_fn.cur + test_offset.x + test_offset.y; + assign vertical_inc = vertical.cur + coarse_offset(offsets.cur.y); + + assign fine_corner = corner.cur; + assign fine_offsets = offsets.cur; // Vuelve a cur luego de 3 ciclos + + assign min_offset.x = raster_idx(next_offsets.x, RASTER_BITS'(0)); + assign min_offset.y = raster_idx(next_offsets.y, RASTER_BITS'(0)); + assign max_offset.x = raster_idx(next_offsets.x, RASTER_BITS'(RASTER_SIZE - 1)); + assign max_offset.y = raster_idx(next_offsets.y, RASTER_BITS'(RASTER_SIZE - 1)); + assign next_offsets = edges_recv ? edges_offsets : offsets.next; + + always_comb begin + unique case (state) + SETUP: new_geom = 1; + default: new_geom = 0; + endcase + + unique case (state) + TEST_AB: mask_reset = 1; + default: mask_reset = 0; + endcase + + unique case (state) + TEST_BC: edges_ready = 1; + default: edges_ready = 0; + endcase + + unique case (state) + SETUP, TEST_AB, TEST_BC: + edges_recv = 1; + + default: + edges_recv = 0; + endcase + + unique case (state) + OUT: fine_valid = mask; + default: fine_valid = 0; + endcase + + unique case (state) + OUT: begin + out_flow = ~mask | fine_ready; + test_flow = 0; + end + + default: begin + out_flow = 0; + test_flow = 1; + end + endcase + end + + always_ff @(posedge clk or negedge rst_n) + if (~rst_n) + state <= SETUP; + else + unique case (state) + SETUP: + if (edges_valid) + state <= TEST_AB; + + TEST_AB: + state <= TEST_BC; + + TEST_BC: + state <= TEST_CA; + + TEST_CA: + state <= OUT; + + OUT: + if (out_flow) + state <= end_x & end_y ? SETUP : TEST_AB; + endcase + + always_ff @(posedge clk) begin + if (new_geom) begin + width <= edges_span.x.coarse; + stride.x <= edges_span.x.coarse; + stride.y <= edges_span.y.coarse; + reference_x <= edges_ref.x; + + fine_ref <= edges_ref; + fine_geom_id <= edges_geom_id; + end + + if (out_flow) begin + stride.x <= stride.x - 1; + fine_ref.x.fint <= fine_ref.x.fint + ($bits(fixed_int))'(RASTER_SIZE); + + if (end_x) begin + fine_ref.x <= reference_x; + fine_ref.y.fint <= fine_ref.y.fint + ($bits(fixed_int))'(RASTER_SIZE); + + stride.x <= width; + stride.y <= stride.y - 1; + end + end + + if (test_flow) begin + offsets.cur <= next_offsets; + offsets.next <= offsets.prev; + offsets.prev <= offsets.cur; + + vertical.cur <= vertical.next; + vertical.next <= vertical.prev; + vertical.prev <= vertical.cur; + + edge_fn.cur <= edge_fn.next; + edge_fn.next <= edge_fn.prev; + edge_fn.prev <= edge_fn.cur + coarse_offset(offsets.cur.x); + + if (end_x) begin + edge_fn.prev <= vertical_inc; + vertical.prev <= vertical_inc; + end + + corner.cur <= corner.next; + corner.next <= corner.prev; + corner.prev <= edge_fn.cur; + + if (coarse_offset(next_offsets.x) >= 'sd0) + test_offset.x <= max_offset.x; + else + test_offset.x <= min_offset.x; + + if (coarse_offset(next_offsets.y) >= 'sd0) + test_offset.y <= max_offset.y; + else + test_offset.y <= min_offset.y; + + mask <= (mask | mask_reset) & (edge_test >= 0); + end + + if (edges_recv) begin + edge_fn.cur <= edges_base; + vertical.cur <= edges_base; + end + end + +endmodule + +module gfx_raster_fine +( + input logic clk, + rst_n, + + input logic coarse_valid, + input gfx::word coarse_geom_id, + input gfx::fixed_xy coarse_ref, + input gfx::fixed coarse_corner, + input gfx::raster_offsets_xy coarse_offsets, + output logic coarse_ready, + + gfx_pkts.tx coverage +); + + import gfx::*; + + enum int unsigned + { + IN_C, + IN_A, + IN_B, + IN_MASK + } in_state; + + enum int unsigned + { + OUT_ACCEPT, + OUT_GEOM_ID, + OUT_POS, + OUT_MASK, + OUT_BARY_C, + OUT_BARY_A, + OUT_BARY_B + } out_state; + + struct + { + fixed cur, + next, + prev; + } corner; + + struct + { + raster_offsets_xy cur, + next, + prev; + } offsets; + + logic begin_bary, hold_block, in_valid, mask_in_clean, + mask_in_reset, new_block, out_last; + + word geom_id; + fixed bary_coord; + lane_no lane, lane_ctz, lane_hold; + fixed_xy block_ref; + lane_mask mask_in, mask, mask_ctz; + raster_index lane_x, lane_y; + logic[$bits(lane_ctz):0] ctz_count; + + function shword ref_half(raster_prec dim); + return dim.coarse[$bits(shword) - 1:0]; + endfunction + + assign lane_ctz = ctz_count[$bits(lane_ctz) - 1:0]; + assign in_valid = mask_in_clean & |mask_in; + assign out_last = ~|mask; + assign {lane_y, lane_x} = lane; + + // **IMPORTANTE**: Esto va a fallar a partir de RASTER_BITS >= 3, + // ya que la fsm asume que ctz termina en 3 ciclos o menos + + gfx_ctz #(RASTER_COARSE_FRAGS) ctz + ( + .clk, + .value(mask_ctz), + .ctz(ctz_count) + ); + + always_comb begin + unique case (out_state) + OUT_ACCEPT: new_block = 1; + default: new_block = 0; + endcase + + unique case (out_state) + OUT_ACCEPT: mask_ctz = mask_in; + default: mask_ctz = mask; + endcase + + unique case (out_state) + OUT_ACCEPT: coverage.tvalid = 0; + default: coverage.tvalid = 1; + endcase + + unique case (out_state) + OUT_MASK: begin_bary = coverage.tvalid; + default: begin_bary = 0; + endcase + + unique case (out_state) + OUT_BARY_B: coverage.tlast = out_last; + default: coverage.tlast = 0; + endcase + + unique case (out_state) + OUT_GEOM_ID: + coverage.tdata = geom_id; + + OUT_POS: + coverage.tdata = {ref_half(coarse_ref.y), ref_half(block_ref.x)}; + + OUT_MASK: + coverage.tdata = {{($bits(word) - $bits(mask)){1'b0}}, mask}; + + OUT_BARY_C, OUT_BARY_A, OUT_BARY_B: + coverage.tdata = bary_coord; + + default: + coverage.tdata = 'x; + endcase + + unique case (out_state) + OUT_MASK: + lane = lane_ctz; + + default: + lane = lane_hold; + endcase + + unique case (in_state) + IN_C: coarse_ready = new_block; + default: coarse_ready = 0; + endcase + + unique case (in_state) + IN_C: hold_block = new_block; + IN_A: hold_block = 1; + IN_B: hold_block = 1; + IN_MASK: hold_block = 0; + endcase + + unique case (in_state) + IN_C: mask_in_reset = 1; + default: mask_in_reset = 0; + endcase + + unique case (in_state) + IN_MASK: mask_in_clean = 1; + default: mask_in_clean = 0; + endcase + end + + always_ff @(posedge clk or negedge rst_n) + if (~rst_n) begin + in_state <= IN_C; + out_state <= OUT_ACCEPT; + end else begin + unique case (in_state) + IN_C: + if (coarse_valid & new_block) + in_state <= IN_A; + + IN_A: + in_state <= IN_B; + + IN_B: + in_state <= IN_MASK; + + IN_MASK: + in_state <= IN_C; + endcase + + unique case (out_state) + OUT_ACCEPT: + if (in_valid) + out_state <= OUT_GEOM_ID; + + OUT_GEOM_ID: + if (coverage.tready) + out_state <= OUT_POS; + + OUT_POS: + if (coverage.tready) + out_state <= OUT_MASK; + + OUT_MASK: + if (coverage.tready) + out_state <= OUT_BARY_C; + + OUT_BARY_C: + if (coverage.tready) + out_state <= OUT_BARY_A; + + OUT_BARY_A: + if (coverage.tready) + out_state <= OUT_BARY_B; + + OUT_BARY_B: + if (coverage.tready) + out_state <= out_last ? OUT_ACCEPT : OUT_BARY_C; + endcase + end + + always_ff @(posedge clk) begin + // Prueba paralela de signos, esto hace el heavy lifting de fine raster + // Nótese que muchos sumadores serán eliminados en síntesis + for (int i = 0; i < RASTER_SIZE; ++i) + for (int j = 0; j < RASTER_SIZE; ++j) + mask_in[i * RASTER_SIZE + j] <= + (mask_in[i * RASTER_SIZE + j] | mask_in_reset) + & (coarse_corner + + raster_idx(coarse_offsets.y, RASTER_BITS'(i)) + + raster_idx(coarse_offsets.x, RASTER_BITS'(j)) + >= 'sd0); + + // Recalculamos las coordenadas baricéntricas de cada fragmento que + // no haya sido descartado. La razón de esto es evitar almacenar y + // luego multiplexar las coordenadas de un bloque entero (48 words). + if (coverage.tready) + bary_coord <= corner.next + + raster_idx(offsets.next.y, RASTER_BITS'(lane_y)) + + raster_idx(offsets.next.x, RASTER_BITS'(lane_x)); + + if (new_block & mask_in_reset) begin + geom_id <= coarse_geom_id; + block_ref <= coarse_ref; + end + + // new_block = 0 => coverage.tvalid = 1 + if (new_block | coverage.tready) begin + corner.cur <= corner.next; + corner.next <= corner.prev; + corner.prev <= corner.cur; + + offsets.cur <= offsets.next; + offsets.next <= offsets.prev; + offsets.prev <= offsets.cur; + end + + if (hold_block) begin + // Para prev en vez de cur para que los primeros valores queden en + // cur justamente al llegar a OUT_BARY_C + corner.prev <= coarse_corner; + offsets.prev <= coarse_offsets; + end + + if (new_block) + mask <= mask_in; + + if (begin_bary) begin + mask <= mask & (mask - 1); + lane_hold <= lane_ctz; + end + end + +endmodule diff --git a/platform/wavelet3d/gfx_top.sv b/platform/wavelet3d/gfx_top.sv index 77126b9..9f7e452 100644 --- a/platform/wavelet3d/gfx_top.sv +++ b/platform/wavelet3d/gfx_top.sv @@ -27,10 +27,31 @@ module gfx_top encode_enable, output logic out_valid, - output gfx::word q[gfx::SHADER_LANES] + output gfx::word q[gfx::SHADER_LANES], + + input gfx::word geom_tdata, + input logic geom_tlast, + geom_tvalid, + output logic geom_tready, + + input logic raster_tready, + output logic raster_tlast, + raster_tvalid, + output gfx::word raster_tdata ); gfx_axil sched_axi(); + gfx_pkts geometry(), coverage(); + + assign geometry.tdata = geom_tdata; + assign geometry.tlast = geom_tlast; + assign geometry.tvalid = geom_tvalid; + assign geom_tready = geometry.tready; + + assign raster_tdata = coverage.tdata; + assign raster_tlast = coverage.tlast; + assign raster_tvalid = coverage.tvalid; + assign coverage.tready = raster_tready; gfx_fpint fpint ( @@ -45,4 +66,12 @@ module gfx_top .axim(sched_axi.m) ); + gfx_raster raster + ( + .clk, + .rst_n, + .geometry(coverage.rx), + .coverage(coverage.tx) + ); + endmodule |
