`timescale 1ns/1ps // ============================================================ // MEASUREMENT-ONLY FORK of hardware/v3/rtl/packed_slot.v, NOT part of // the real synthesis target and NOT maintained going forward -- exists // ONLY to reproduce the pre-EXP-0083 per-tile req/wait/consume // activation-fetch sequencing (direct act_tile_fetch.v, no look-ahead // ping-pong buffer), so it can be A/B-measured against the current, // real, committed packed_slot.v (which wires ddr_prefetch_mgr.v) at // the NOW-CLOSED 32-bit/3225ps DDR3 config (EXP-0086) -- the ORIGINAL // EXP-0083 measurement was only ever taken at the OLD 16-bit/155MHz // config, so it's not a fair before/after comparison for today's real // hardware. Per this project's own fork-before-promote discipline: // this file is the throwaway "before" fork, `packed_slot.v` itself is // never edited for this measurement. // // Everything below is copied from the current real packed_slot.v // EXCEPT: ddr_prefetch_mgr.v is replaced with a direct // act_tile_fetch.v instance, and S_TILEREQ/S_TILEWAIT revert to the // simple one-shot-per-tile sequencing act_tile_fetch.v's own interface // expects (issue req, wait for its own valid pulse, consume, move on) // -- no job-level look-ahead, no depth-2 ping-pong overlap. // ============================================================ module packed_slot_noprefetch #( parameter DATA_WIDTH = 8, parameter P_IN = 8, parameter ACC_WIDTH = 32, parameter BURST_LEN = 8, parameter ADDR_WIDTH = 26, parameter LAYER_BYTES = 128, parameter BUFADDRW = $clog2(LAYER_BYTES) )( input wire clk, input wire rst, input wire job_start, input wire [ADDR_WIDTH-1:0] x_base_a, input wire [ADDR_WIDTH-1:0] x_base_b, input wire [ADDR_WIDTH-1:0] w_base, input wire [15:0] n_tiles, input wire [ADDR_WIDTH-1:0] result_addr_a, input wire [ADDR_WIDTH-1:0] result_addr_b, input wire [15:0] node_id_a, input wire [15:0] node_id_b, output reg job_done, output reg signed [DATA_WIDTH-1:0] result_data_a, output reg signed [DATA_WIDTH-1:0] result_data_b, output reg [15:0] result_node_id_a, output reg [15:0] result_node_id_b, output reg [ADDR_WIDTH-1:0] result_addr_a_out, output reg [ADDR_WIDTH-1:0] result_addr_b_out, output wire mem_active, input wire mem_grant, output wire ctrl_req, output wire ctrl_wr, output wire [ADDR_WIDTH-2:0] ctrl_addr, output wire [32*BURST_LEN-1:0] ctrl_wdata, output wire [4*BURST_LEN-1:0] ctrl_wmask, input wire [32*BURST_LEN-1:0] ctrl_rdata, input wire ctrl_ready, input wire ctrl_busy ); localparam S_IDLE = 4'd0, S_MEMWAIT = 4'd1, S_PREFETCH = 4'd2, S_SWAP = 4'd3, S_JOBSTART = 4'd4, S_TILEREQ = 4'd5, S_TILEWAIT = 4'd6, S_OPERAND = 4'd7, S_RESULT = 4'd8, S_DONE = 4'd9; reg [3:0] state; reg [ADDR_WIDTH-1:0] w_base_lat, x_base_a_lat, x_base_b_lat; reg [15:0] n_tiles_lat; reg [ADDR_WIDTH-1:0] result_addr_a_lat, result_addr_b_lat; reg [15:0] node_id_a_lat, node_id_b_lat; reg [15:0] tcnt; reg pf_start; wire pf_busy, pf_done; wire pf_fill_we; wire [BUFADDRW-1:0] pf_fill_addr; wire [DATA_WIDTH-1:0] pf_fill_data; wire pf_ctrl_req, pf_ctrl_wr; wire [ADDR_WIDTH-2:0] pf_ctrl_addr; wire [32*BURST_LEN-1:0] pf_ctrl_wdata; wire [4*BURST_LEN-1:0] pf_ctrl_wmask; layer_prefetch_ctrl #( .DATA_WIDTH(DATA_WIDTH), .LAYER_BYTES(LAYER_BYTES), .BURST_LEN(BURST_LEN), .ADDR_WIDTH(ADDR_WIDTH-1) ) u_pf ( .clk(clk), .rst(rst), .start(pf_start), .layer_base(w_base_lat[ADDR_WIDTH-2:0]), .busy(pf_busy), .done(pf_done), .fill_we(pf_fill_we), .fill_addr(pf_fill_addr), .fill_data(pf_fill_data), .ctrl_req(pf_ctrl_req), .ctrl_wr(pf_ctrl_wr), .ctrl_addr(pf_ctrl_addr), .ctrl_wdata(pf_ctrl_wdata), .ctrl_wmask(pf_ctrl_wmask), .ctrl_rdata(ctrl_rdata), .ctrl_ready(ctrl_ready), .ctrl_busy(ctrl_busy) ); // ---- pre-EXP-0083 baseline: direct act_tile_fetch.v, one req per // tile, no look-ahead ---- reg act_req; wire act_valid; wire signed [DATA_WIDTH*P_IN-1:0] act_data_a_w, act_data_b_w; wire act_mem_active; wire act_ctrl_req, act_ctrl_wr; wire [ADDR_WIDTH-2:0] act_ctrl_addr; wire [32*BURST_LEN-1:0] act_ctrl_wdata; wire [4*BURST_LEN-1:0] act_ctrl_wmask; act_tile_fetch #( .DATA_WIDTH(DATA_WIDTH), .P_IN(P_IN), .BURST_LEN(BURST_LEN), .ADDR_WIDTH(ADDR_WIDTH-1) ) u_act ( .clk(clk), .rst(rst), .req(act_req), .base_a(x_base_a_lat[ADDR_WIDTH-2:0]), .base_b(x_base_b_lat[ADDR_WIDTH-2:0]), .tcnt(tcnt), .valid(act_valid), .data_a(act_data_a_w), .data_b(act_data_b_w), .mem_active(act_mem_active), .mem_grant(mem_grant), .ctrl_req(act_ctrl_req), .ctrl_wr(act_ctrl_wr), .ctrl_addr(act_ctrl_addr), .ctrl_wdata(act_ctrl_wdata), .ctrl_wmask(act_ctrl_wmask), .ctrl_rdata(ctrl_rdata), .ctrl_ready(ctrl_ready), .ctrl_busy(ctrl_busy) ); assign ctrl_req = act_mem_active ? act_ctrl_req : pf_ctrl_req; assign ctrl_wr = act_mem_active ? act_ctrl_wr : pf_ctrl_wr; assign ctrl_addr = act_mem_active ? act_ctrl_addr : pf_ctrl_addr; assign ctrl_wdata = act_mem_active ? act_ctrl_wdata : pf_ctrl_wdata; assign ctrl_wmask = act_mem_active ? act_ctrl_wmask : pf_ctrl_wmask; assign mem_active = (state == S_MEMWAIT) || (state == S_PREFETCH) || act_mem_active; wire [BUFADDRW-1:0] lwb_rd_addr; wire [DATA_WIDTH-1:0] lwb_rd_data; reg consume_done; layer_weight_buffer #(.DATA_WIDTH(DATA_WIDTH), .LAYER_DEPTH(LAYER_BYTES)) u_lwb ( .clk(clk), .rst(rst), .fill_we(pf_fill_we), .fill_addr(pf_fill_addr), .fill_data(pf_fill_data), .fill_done(pf_done), .rd_addr(lwb_rd_addr), .rd_data(lwb_rd_data), .consume_done(consume_done), .active_sel(), .swapped() ); reg tile_req; reg [BUFADDRW-1:0] tile_base; reg tile_seen; reg act_seen; wire tile_valid; wire [DATA_WIDTH*P_IN-1:0] tile_data; weight_tile_gather #( .DATA_WIDTH(DATA_WIDTH), .P_IN(P_IN), .BUFADDRW(BUFADDRW) ) u_gather ( .clk(clk), .rst(rst), .tile_req(tile_req), .tile_base(tile_base), .tile_valid(tile_valid), .tile_data(tile_data), .rd_addr(lwb_rd_addr), .rd_data(lwb_rd_data) ); reg job_valid_np; wire job_ready_np; reg [1:0] job_activation; reg signed [DATA_WIDTH-1:0] job_bias; reg operand_valid; wire operand_ready; reg signed [DATA_WIDTH*P_IN-1:0] input_data_a_r, input_data_b_r; reg [DATA_WIDTH*P_IN-1:0] weight_data_r; reg tile_last; wire result_valid_np; reg result_ready; wire signed [DATA_WIDTH-1:0] result_data_a_np, result_data_b_np; wire [15:0] result_node_id_a_np, result_node_id_b_np; wire [3:0] np_state; wire np_error; neural_processor_packed #( .DATA_WIDTH(DATA_WIDTH), .P_IN(P_IN), .ACC_WIDTH(ACC_WIDTH) ) u_np ( .clk(clk), .rst(rst), .job_valid(job_valid_np), .job_ready(job_ready_np), .job_node_id_a(node_id_a_lat), .job_node_id_b(node_id_b_lat), .job_bias(job_bias), .job_activation(job_activation), .operand_valid(operand_valid), .operand_ready(operand_ready), .input_data_a(input_data_a_r), .input_data_b(input_data_b_r), .weight_data(weight_data_r), .tile_last(tile_last), .result_valid(result_valid_np), .result_ready(result_ready), .result_data_a(result_data_a_np), .result_data_b(result_data_b_np), .result_node_id_a(result_node_id_a_np), .result_node_id_b(result_node_id_b_np), .np_state(np_state), .np_error(np_error) ); localparam ACT_RELU = 2'd1; always @(posedge clk) begin if (rst) begin state <= S_IDLE; job_done <= 1'b0; pf_start <= 1'b0; consume_done <= 1'b0; tile_req <= 1'b0; act_req <= 1'b0; tile_seen <= 1'b0; act_seen <= 1'b0; job_valid_np <= 1'b0; operand_valid<= 1'b0; tile_last <= 1'b0; result_ready <= 1'b0; job_bias <= {DATA_WIDTH{1'b0}}; job_activation <= ACT_RELU; tcnt <= 16'd0; end else begin job_done <= 1'b0; pf_start <= 1'b0; consume_done <= 1'b0; tile_req <= 1'b0; act_req <= 1'b0; case (state) S_IDLE: begin if (job_start) begin w_base_lat <= w_base; x_base_a_lat <= x_base_a; x_base_b_lat <= x_base_b; n_tiles_lat <= n_tiles; result_addr_a_lat <= result_addr_a; result_addr_b_lat <= result_addr_b; node_id_a_lat <= node_id_a; node_id_b_lat <= node_id_b; job_bias <= {DATA_WIDTH{1'b0}}; job_activation <= ACT_RELU; state <= S_MEMWAIT; end end S_MEMWAIT: begin if (mem_grant) begin pf_start <= 1'b1; state <= S_PREFETCH; end end S_PREFETCH: begin if (pf_done) begin consume_done <= 1'b1; state <= S_SWAP; end end S_SWAP: begin job_valid_np <= 1'b1; state <= S_JOBSTART; end S_JOBSTART: begin if (job_valid_np && job_ready_np) begin job_valid_np <= 1'b0; tcnt <= 16'd0; state <= S_TILEREQ; end end // pre-EXP-0083 baseline: issue ONE tile request per // iteration, wait for its own valid pulse -- no // look-ahead overlap with the previous tile's consume. S_TILEREQ: begin tile_req <= 1'b1; tile_base <= tcnt[BUFADDRW-1:0]*P_IN[BUFADDRW-1:0]; tile_seen <= 1'b0; act_seen <= 1'b0; act_req <= 1'b1; state <= S_TILEWAIT; end // pre-EXP-0083 real join: weight_tile_gather.v's tile_valid // and act_tile_fetch.v's act_valid are BOTH one-cycle pulses // (act_tile_fetch.v has no level-hold the way ddr_prefetch_ // mgr.v's ddrpf_tile_valid does) -- each needs its own seen // latch since they don't arrive on the same cycle in general. S_TILEWAIT: begin if (tile_valid) begin weight_data_r <= tile_data; tile_seen <= 1'b1; end if (act_valid) begin input_data_a_r <= act_data_a_w; input_data_b_r <= act_data_b_w; act_seen <= 1'b1; end if ((tile_valid || tile_seen) && (act_valid || act_seen)) begin tile_last <= (tcnt == n_tiles_lat - 16'd1); operand_valid <= 1'b1; state <= S_OPERAND; end end S_OPERAND: begin if (operand_valid && operand_ready) begin operand_valid <= 1'b0; tile_last <= 1'b0; if (tcnt == n_tiles_lat - 16'd1) begin result_ready <= 1'b1; state <= S_RESULT; end else begin tcnt <= tcnt + 16'd1; state <= S_TILEREQ; end end end S_RESULT: begin if (result_valid_np) begin result_data_a <= result_data_a_np; result_data_b <= result_data_b_np; result_node_id_a <= result_node_id_a_np; result_node_id_b <= result_node_id_b_np; result_addr_a_out <= result_addr_a_lat; result_addr_b_out <= result_addr_b_lat; result_ready <= 1'b0; job_done <= 1'b1; state <= S_IDLE; end end default: state <= S_IDLE; endcase end end endmodule