feat: real result-writeback engine, removes the last hard N-scaling pin blocker (EXP-0088)
Adds result_writeback.v, one instance per packed_slot.v, writing each completed job's result directly into DDR3 at the job's own result_addr_a/b instead of driving literal top-level pins -- the same architectural shape as the weight-fetch path, in reverse. job_done now means "durably in DDR3", not "captured in a register only a pin could see". n2_system_ddr3_top.v's own s0_result_data_a/b, s1_result_data_a/b top-level package pins are removed (and the now-dangling XDC constraint for them), closing the real, hard scaling blocker docs/ARCHITECTURE_ ANALYSIS.md flagged since EXP-0074/0079 (8 bits x 2 lanes x N cores -> 256 pins at N=16). Addressing reuses the exact same JOB_ADDR_WIDTH->ctrl-bus-word truncation x_base_a/w_base already use (verified against act_tile_ fetch.v's/layer_prefetch_ctrl.v's own real code, not guessed). The host reads results back via the already-existing READ_MEM (0x02) SPI opcode -- no new protocol. A real EXP-0066-class bug (issuing ctrl_req before mem_grant) was caught and fixed before ever compiling, by re-deriving the design against act_tile_fetch.v's own proven S_MEMWAIT/S_GAP sequencing. Verified two ways: tb_packed_slot.v extended with a real DDR3 read-after-write check (9/9 PASS, confirms the write actually landed, not just that job_done pulsed); tb_n2_system_ddr3.v re-run via real xsim to confirm correct behavior under real 2-slot shared-bus arbitration (8/8 PASS, 0 errors, consistent timing with EXP-0087's own baseline for this workload). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
@@ -179,6 +179,55 @@ module tb;
|
||||
reg signed [DATA_WIDTH-1:0] expected_a, expected_b;
|
||||
integer wd;
|
||||
|
||||
// EXP-0088: real read-after-write check that result_writeback.v
|
||||
// (inside the DUT) actually landed the correct value in DDR3 at
|
||||
// result_addr_a/b -- not just that job_done eventually pulsed.
|
||||
// Format matches result_writeback.v's own header exactly: one
|
||||
// 32-bit ctrl-word per lane, {node_id[15:0], 8'h00,
|
||||
// result_data[7:0]}.
|
||||
task automatic verify_writeback(
|
||||
input integer li, input integer pos_a, input integer pos_b,
|
||||
input [ADDR_WIDTH-1:0] raddr_a, input [ADDR_WIDTH-1:0] raddr_b,
|
||||
input signed [DATA_WIDTH-1:0] exp_data_a, input signed [DATA_WIDTH-1:0] exp_data_b,
|
||||
input [15:0] exp_nid_a, input [15:0] exp_nid_b
|
||||
);
|
||||
reg [31:0] word_a, word_b;
|
||||
reg [SDRAM_ADDR_WIDTH-1:0] burst_addr;
|
||||
reg [2:0] word_in_block;
|
||||
begin
|
||||
pre_active = 1'b1;
|
||||
|
||||
burst_addr = {raddr_a[SDRAM_ADDR_WIDTH-1:3], 3'b0};
|
||||
word_in_block = raddr_a[2:0];
|
||||
@(posedge clk); while (ctrl_busy) @(posedge clk);
|
||||
wpre_req = 1'b1; wpre_wr = 1'b0; wpre_addr = burst_addr;
|
||||
@(posedge clk); wpre_req = 1'b0;
|
||||
while (!ctrl_ready) @(posedge clk);
|
||||
word_a = ctrl_rdata[word_in_block*32 +: 32];
|
||||
|
||||
burst_addr = {raddr_b[SDRAM_ADDR_WIDTH-1:3], 3'b0};
|
||||
word_in_block = raddr_b[2:0];
|
||||
@(posedge clk); while (ctrl_busy) @(posedge clk);
|
||||
wpre_req = 1'b1; wpre_wr = 1'b0; wpre_addr = burst_addr;
|
||||
@(posedge clk); wpre_req = 1'b0;
|
||||
while (!ctrl_ready) @(posedge clk);
|
||||
word_b = ctrl_rdata[word_in_block*32 +: 32];
|
||||
|
||||
pre_active = 1'b0;
|
||||
|
||||
if (word_a[7:0] !== exp_data_a || word_a[31:16] !== exp_nid_a) begin
|
||||
$display("FAIL li=%0d pos_a=%0d: WRITEBACK readback mismatch lane A: word=%08h (data=%0d nid=%0d) expected data=%0d nid=%0d",
|
||||
li, pos_a, word_a, $signed(word_a[7:0]), word_a[31:16], $signed(exp_data_a), exp_nid_a);
|
||||
errors = errors + 1;
|
||||
end
|
||||
if (word_b[7:0] !== exp_data_b || word_b[31:16] !== exp_nid_b) begin
|
||||
$display("FAIL li=%0d pos_b=%0d: WRITEBACK readback mismatch lane B: word=%08h (data=%0d nid=%0d) expected data=%0d nid=%0d",
|
||||
li, pos_b, word_b, $signed(word_b[7:0]), word_b[31:16], $signed(exp_data_b), exp_nid_b);
|
||||
errors = errors + 1;
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
task automatic run_one_pair(input integer li, input integer pos_a, input integer pos_b);
|
||||
begin
|
||||
tests = tests + 1;
|
||||
@@ -224,6 +273,10 @@ module tb;
|
||||
end else begin
|
||||
$display("PASS li=%0d pos_a=%0d pos_b=%0d: a=%0d b=%0d (packed_slot.v real sequencer)",
|
||||
li, pos_a, pos_b, $signed(result_data_a), $signed(result_data_b));
|
||||
// EXP-0088: real DDR3 read-after-write check -- job_done
|
||||
// now means "written to DDR3", confirm it actually was.
|
||||
verify_writeback(li, pos_a, pos_b, result_addr_a, result_addr_b,
|
||||
expected_a, expected_b, node_id_a, node_id_b);
|
||||
end
|
||||
end
|
||||
endtask
|
||||
|
||||
Reference in New Issue
Block a user