diff --git a/hardware/v2/logs/experiments.log b/hardware/v2/logs/experiments.log index 69f09c9..e797603 100644 --- a/hardware/v2/logs/experiments.log +++ b/hardware/v2/logs/experiments.log @@ -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 integration step for a genuine multi-core, multi-layer system, still 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. diff --git a/hardware/v3/rtl/np_packed_weight_reuse_top.v b/hardware/v3/rtl/np_packed_weight_reuse_top.v new file mode 100644 index 0000000..2ec00c8 --- /dev/null +++ b/hardware/v3/rtl/np_packed_weight_reuse_top.v @@ -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 diff --git a/hardware/v3/synth/synth_np_packed_weight_reuse_top.tcl b/hardware/v3/synth/synth_np_packed_weight_reuse_top.tcl new file mode 100644 index 0000000..9d74b44 --- /dev/null +++ b/hardware/v3/synth/synth_np_packed_weight_reuse_top.tcl @@ -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