exp: real P&R of verified weight-reuse memory path + packed core (EXP-0063)
New hardware/v3/rtl/np_packed_weight_reuse_top.v: flat structural synthesis wrapper around the EXP-0062-verified module chain (real SDR SDRAM controller -> layer_prefetch_ctrl.v -> layer_weight_buffer.v -> weight_tile_gather.v -> neural_processor_packed.v). Real Vivado post-route: 8/240 DSP48E1 (unchanged, memory path uses zero DSPs), WNS -2.502ns @ 200MHz -> Fmax ~133.3MHz, only -1.2% vs the isolated single core (134.9MHz, EXP-0059). Real memory-path control logic adds negligible Fmax cost at this scale. Full writeup in hardware/v2/logs/experiments.log EXP-0063. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01MUG92aM9m68TRc4rG55BcC
This commit is contained in:
@@ -3880,3 +3880,48 @@ EXP-0060) for a real system-adjacent Fmax number; (2) neural_director.v
|
|||||||
port to dispatch job PAIRS per packed core remains the next real
|
port to dispatch job PAIRS per packed core remains the next real
|
||||||
integration step for a genuine multi-core, multi-layer system, still
|
integration step for a genuine multi-core, multi-layer system, still
|
||||||
not started.
|
not started.
|
||||||
|
|
||||||
|
EXP-0063 -- real P&R of the EXP-0062-verified weight-reuse memory path
|
||||||
|
+ packed core together (2026-09-17)
|
||||||
|
|
||||||
|
CONTEXT: EXP-0062's own next_action -- synthesize the just-verified
|
||||||
|
combined path (sdram_controller.v -> layer_prefetch_ctrl.v ->
|
||||||
|
layer_weight_buffer.v -> weight_tile_gather.v -> neural_processor_
|
||||||
|
packed.v), not just the isolated compute core (EXP-0059) or the
|
||||||
|
zero-interconnect compute array (EXP-0060), for a real Fmax number
|
||||||
|
that includes actual memory-path control logic, not just DSP/placement
|
||||||
|
density.
|
||||||
|
|
||||||
|
METHOD: new hardware/v3/rtl/np_packed_weight_reuse_top.v, flat
|
||||||
|
structural wrapper instantiating the real, EXP-0062-verified module
|
||||||
|
chain with its real internal connections; control ports (pf_start,
|
||||||
|
tile_req, operand_valid, ...) exposed at the top level rather than
|
||||||
|
internally sequenced (the closed-loop sequencing is neural_director.v's
|
||||||
|
still-not-built job, deliberately out of scope here -- this module
|
||||||
|
exists only to let Vivado see the real combined logic together).
|
||||||
|
Real Vivado 2026.1 synth + opt_design + place_design + route_design,
|
||||||
|
same 200MHz constraint and part (xc7a100tcsg324-1) as EXP-0059/0060,
|
||||||
|
via hardware/v3/synth/synth_np_packed_weight_reuse_top.tcl.
|
||||||
|
|
||||||
|
RESULT (real, post-route): 8/240 DSP48E1 (3.33%, unchanged from the
|
||||||
|
isolated core -- the memory path itself uses zero DSPs, as expected).
|
||||||
|
WNS -2.502ns @ 200MHz -> real critical path 7.502ns -> Fmax ~133.3MHz.
|
||||||
|
Vs EXP-0059's isolated single core (134.9MHz): only -1.2%.
|
||||||
|
|
||||||
|
DECISION: real memory-path control logic (prefetch controller, double-
|
||||||
|
buffered weight scratchpad, tile gather adapter, SDRAM controller) adds
|
||||||
|
negligible Fmax cost on top of the compute core alone, consistent with
|
||||||
|
EXP-0060's own finding that placement/interconnect density near the
|
||||||
|
compute core is not the dominant Fmax driver at this scale. The
|
||||||
|
remaining open question (still not answered by EXP-0059/0060/0063)
|
||||||
|
is what a REAL multi-core Director-driven system does to Fmax --
|
||||||
|
none of these three checks include neural_director.v or N>1 packed
|
||||||
|
cores sharing a single memory path with real arbitration.
|
||||||
|
|
||||||
|
next_action: neural_director.v port for job-PAIR dispatch per packed
|
||||||
|
core remains the largest, still-not-started real integration step
|
||||||
|
needed before a genuine multi-core system-level P&R number can be
|
||||||
|
trusted. Until that exists (correctness-verified per this project's
|
||||||
|
own standard, per EXP-0062's own disclosed lesson about saturating-
|
||||||
|
output tests hiding real bugs), no further Fmax numbers from larger
|
||||||
|
configurations should be treated as system-representative.
|
||||||
|
|||||||
@@ -0,0 +1,149 @@
|
|||||||
|
`timescale 1ns/1ps
|
||||||
|
|
||||||
|
// ============================================================
|
||||||
|
// V3 -- synthesis top for the EXP-0062 verified weight-reuse memory
|
||||||
|
// path + packed compute core, flat structural wiring (real modules,
|
||||||
|
// real internal connections), for a real P&R resource/timing check.
|
||||||
|
//
|
||||||
|
// Control ports (pf_start/tile_req/operand_valid/...) are exposed
|
||||||
|
// directly at the top level rather than internally sequenced -- the
|
||||||
|
// closed-loop sequencing logic (what EXP-0062's testbench did
|
||||||
|
// procedurally) is the still-not-built neural_director.v integration,
|
||||||
|
// deliberately out of scope here. This module exists ONLY to let
|
||||||
|
// Vivado see the REAL combined logic (SDRAM controller + prefetch +
|
||||||
|
// weight buffer + tile gather + packed compute core) together for
|
||||||
|
// utilization/timing purposes, matching EXP-0059's own single-core
|
||||||
|
// out-of-context methodology.
|
||||||
|
// ============================================================
|
||||||
|
module np_packed_weight_reuse_top #(
|
||||||
|
parameter DATA_WIDTH = 8,
|
||||||
|
parameter P_IN = 8,
|
||||||
|
parameter ACC_WIDTH = 32,
|
||||||
|
parameter BURST_LEN = 8,
|
||||||
|
parameter ROW_BITS = 13,
|
||||||
|
parameter COL_BITS = 10,
|
||||||
|
parameter BANK_BITS = 2,
|
||||||
|
parameter ADDR_WIDTH = BANK_BITS + ROW_BITS + COL_BITS,
|
||||||
|
parameter LAYER_BYTES = 128,
|
||||||
|
parameter BUFADDRW = $clog2(LAYER_BYTES)
|
||||||
|
)(
|
||||||
|
input wire clk,
|
||||||
|
input wire rst,
|
||||||
|
|
||||||
|
// ---- layer_prefetch_ctrl.v control ----
|
||||||
|
input wire pf_start,
|
||||||
|
input wire [ADDR_WIDTH-1:0] pf_layer_base,
|
||||||
|
output wire pf_busy,
|
||||||
|
output wire pf_done,
|
||||||
|
|
||||||
|
// ---- layer_weight_buffer.v control ----
|
||||||
|
input wire consume_done,
|
||||||
|
|
||||||
|
// ---- weight_tile_gather.v control ----
|
||||||
|
input wire tile_req,
|
||||||
|
input wire [BUFADDRW-1:0] tile_base,
|
||||||
|
output wire tile_valid,
|
||||||
|
|
||||||
|
// ---- neural_processor_packed.v job/operand control ----
|
||||||
|
input wire job_valid,
|
||||||
|
output wire job_ready,
|
||||||
|
input wire [15:0] job_node_id_a,
|
||||||
|
input wire [15:0] job_node_id_b,
|
||||||
|
input wire signed [DATA_WIDTH-1:0] job_bias,
|
||||||
|
input wire [1:0] job_activation,
|
||||||
|
input wire operand_valid,
|
||||||
|
output wire operand_ready,
|
||||||
|
input wire signed [DATA_WIDTH*P_IN-1:0] input_data_a,
|
||||||
|
input wire signed [DATA_WIDTH*P_IN-1:0] input_data_b,
|
||||||
|
input wire tile_last,
|
||||||
|
output wire result_valid,
|
||||||
|
input wire result_ready,
|
||||||
|
output wire signed [DATA_WIDTH-1:0] result_data_a,
|
||||||
|
output wire signed [DATA_WIDTH-1:0] result_data_b,
|
||||||
|
output wire [15:0] result_node_id_a,
|
||||||
|
output wire [15:0] result_node_id_b,
|
||||||
|
|
||||||
|
// ---- real SDRAM pins ----
|
||||||
|
output wire sdram_cke,
|
||||||
|
output wire sdram_cs_n,
|
||||||
|
output wire sdram_ras_n,
|
||||||
|
output wire sdram_cas_n,
|
||||||
|
output wire sdram_we_n,
|
||||||
|
output wire [BANK_BITS-1:0] sdram_ba,
|
||||||
|
output wire [ROW_BITS-1:0] sdram_a,
|
||||||
|
inout wire [15:0] sdram_dq,
|
||||||
|
output wire [1:0] sdram_dqm
|
||||||
|
);
|
||||||
|
wire ctrl_req, ctrl_wr, ctrl_ready, ctrl_busy;
|
||||||
|
wire [ADDR_WIDTH-1:0] ctrl_addr;
|
||||||
|
wire [16*BURST_LEN-1:0] ctrl_wdata, ctrl_rdata;
|
||||||
|
wire [2*BURST_LEN-1:0] ctrl_wmask;
|
||||||
|
|
||||||
|
sdram_controller #(
|
||||||
|
.CLK_FREQ_MHZ(64), .BURST_LEN(BURST_LEN),
|
||||||
|
.ROW_BITS(ROW_BITS), .COL_BITS(COL_BITS), .BANK_BITS(BANK_BITS)
|
||||||
|
) u_ctrl (
|
||||||
|
.clk(clk), .rst(rst),
|
||||||
|
.req(ctrl_req), .wr(ctrl_wr), .addr(ctrl_addr),
|
||||||
|
.wdata(ctrl_wdata), .wmask(ctrl_wmask),
|
||||||
|
.rdata(ctrl_rdata), .ready(ctrl_ready), .busy(ctrl_busy),
|
||||||
|
.sdram_cke(sdram_cke), .sdram_cs_n(sdram_cs_n), .sdram_ras_n(sdram_ras_n),
|
||||||
|
.sdram_cas_n(sdram_cas_n), .sdram_we_n(sdram_we_n),
|
||||||
|
.sdram_ba(sdram_ba), .sdram_a(sdram_a), .sdram_dq(sdram_dq), .sdram_dqm(sdram_dqm)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire pf_fill_we;
|
||||||
|
wire [BUFADDRW-1:0] pf_fill_addr;
|
||||||
|
wire [DATA_WIDTH-1:0] pf_fill_data;
|
||||||
|
|
||||||
|
layer_prefetch_ctrl #(
|
||||||
|
.DATA_WIDTH(DATA_WIDTH), .LAYER_BYTES(LAYER_BYTES), .BURST_LEN(BURST_LEN), .ADDR_WIDTH(ADDR_WIDTH)
|
||||||
|
) u_pf (
|
||||||
|
.clk(clk), .rst(rst),
|
||||||
|
.start(pf_start), .layer_base(pf_layer_base), .busy(pf_busy), .done(pf_done),
|
||||||
|
.fill_we(pf_fill_we), .fill_addr(pf_fill_addr), .fill_data(pf_fill_data),
|
||||||
|
.ctrl_req(ctrl_req), .ctrl_wr(ctrl_wr), .ctrl_addr(ctrl_addr),
|
||||||
|
.ctrl_wdata(ctrl_wdata), .ctrl_wmask(ctrl_wmask),
|
||||||
|
.ctrl_rdata(ctrl_rdata), .ctrl_ready(ctrl_ready), .ctrl_busy(ctrl_busy)
|
||||||
|
);
|
||||||
|
|
||||||
|
wire [BUFADDRW-1:0] lwb_rd_addr;
|
||||||
|
wire [DATA_WIDTH-1:0] lwb_rd_data;
|
||||||
|
|
||||||
|
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()
|
||||||
|
);
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
|
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), .job_ready(job_ready),
|
||||||
|
.job_node_id_a(job_node_id_a), .job_node_id_b(job_node_id_b),
|
||||||
|
.job_bias(job_bias), .job_activation(job_activation),
|
||||||
|
.operand_valid(operand_valid), .operand_ready(operand_ready),
|
||||||
|
.input_data_a(input_data_a), .input_data_b(input_data_b),
|
||||||
|
.weight_data(tile_data), .tile_last(tile_last),
|
||||||
|
.result_valid(result_valid), .result_ready(result_ready),
|
||||||
|
.result_data_a(result_data_a), .result_data_b(result_data_b),
|
||||||
|
.result_node_id_a(result_node_id_a), .result_node_id_b(result_node_id_b),
|
||||||
|
.np_state(np_state), .np_error(np_error)
|
||||||
|
);
|
||||||
|
endmodule
|
||||||
@@ -0,0 +1,14 @@
|
|||||||
|
read_verilog -sv /home/michele/Develop/FPGA-Neural/hardware/v2/rtl/layer_prefetch_ctrl.v
|
||||||
|
read_verilog -sv /home/michele/Develop/FPGA-Neural/hardware/v2/rtl/layer_weight_buffer.v
|
||||||
|
read_verilog -sv /home/michele/Develop/FPGA-Neural/hardware/v3/rtl/weight_tile_gather.v
|
||||||
|
read_verilog -sv /home/michele/Develop/FPGA-Neural/hardware/v3/rtl/neural_processor_packed.v
|
||||||
|
read_verilog -sv /home/michele/Develop/FPGA-Neural/hardware/v2/nms/rtl/sdram_controller.v
|
||||||
|
read_verilog -sv /home/michele/Develop/FPGA-Neural/hardware/v3/rtl/np_packed_weight_reuse_top.v
|
||||||
|
synth_design -top np_packed_weight_reuse_top -part xc7a100tcsg324-1 -mode out_of_context
|
||||||
|
create_clock -name clk -period 5.000 [get_ports clk]
|
||||||
|
opt_design
|
||||||
|
place_design
|
||||||
|
route_design
|
||||||
|
report_utilization -file /tmp/util_weight_reuse_top_postroute.rpt
|
||||||
|
report_timing_summary -file /tmp/timing_weight_reuse_top_postroute.rpt
|
||||||
|
write_checkpoint -force /tmp/weight_reuse_top_postroute.dcp
|
||||||
Reference in New Issue
Block a user