Pipelined multiplier: 3-stage LUT-based replaces shift_add, FSM simplified to 2-state
This commit is contained in:
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
@@ -0,0 +1 @@
|
||||
{"_example": "Fill with {\"file\": \"<path>\", \"reason\": \"<why>\"}. Put spec/research files only — no code paths. Run `python3 .trellis/scripts/get_context.py --mode packages` to list available specs. Delete this line once real entries are added."}
|
||||
@@ -0,0 +1,56 @@
|
||||
# Pipelined Multiplier for Matmul IP
|
||||
|
||||
## Goal
|
||||
|
||||
Replace 4× shift_add_mult (32 cycle/op) with 4× 3-stage pipelined multipliers (1 result/cycle after fill), reducing compute from 420 cycle/group to ~15 cycle/group.
|
||||
|
||||
## Requirements
|
||||
|
||||
1. **Multiplier**: 32×32→64, 3-stage pipeline, LUT-only (no DSP)
|
||||
2. **FSM**: simplified from 4-state (C_IDLE/C_CALC/C_WAIT_MULT/C_ACCUM) to 2-state (C_IDLE/C_RUN)
|
||||
3. **Pipeline matching**: 3-entry shift register for calc_idx/cur_bank delay line
|
||||
4. **Accumulation**: unchanged (4-way sum registered)
|
||||
5. **Interface**: same ports as shift_add_mult (clk, rstn, start, a, b, p, done) for drop-in replacement
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
- [ ] Simulation: CRC32 matches (10 groups)
|
||||
- [ ] Lint clean
|
||||
- [ ] Compile passes
|
||||
- [ ] No DSP used
|
||||
- [ ] WNS ≥ 0 (timing passes for sys_clk=50MHz)
|
||||
- [ ] Expected time improvement: compute ~420 cycle → ~15 cycle
|
||||
|
||||
## Technical Approach
|
||||
|
||||
### Multiplier Design
|
||||
|
||||
```verilog
|
||||
(* use_dsp = "no" *)
|
||||
module pipelined_mult (
|
||||
input clk, rstn, start,
|
||||
input [31:0] a, b,
|
||||
output [63:0] p,
|
||||
output done
|
||||
);
|
||||
// 3-stage: reg(a,b) → compute product → output
|
||||
endmodule
|
||||
```
|
||||
|
||||
### FSM Reduction
|
||||
|
||||
```
|
||||
Before: C_IDLE → C_CALC(1) → C_WAIT_MULT(32) → C_ACCUM(1)
|
||||
←──────── 12 rounds ────────→ = 420 cycles
|
||||
|
||||
After: C_IDLE → C_RUN(12 + 3 pipe delay) → C_IDLE
|
||||
Issue 4 mults/cycle for 12 cycles
|
||||
Results arrive 3 cycles later → accumulate
|
||||
Total: 12 + 3 + 1 = 16 cycles
|
||||
```
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- More than 4 multipliers
|
||||
- Changes to DMA, CRC32, interrupts
|
||||
- FFT integration
|
||||
@@ -0,0 +1,26 @@
|
||||
{
|
||||
"id": "pipelined-multiplier-for-matmul-ip",
|
||||
"name": "pipelined-multiplier-for-matmul-ip",
|
||||
"title": "Pipelined multiplier for matmul IP",
|
||||
"description": "",
|
||||
"status": "in_progress",
|
||||
"dev_type": null,
|
||||
"scope": null,
|
||||
"package": null,
|
||||
"priority": "P2",
|
||||
"creator": "fallensigh",
|
||||
"assignee": "fallensigh",
|
||||
"createdAt": "2026-06-25",
|
||||
"completedAt": null,
|
||||
"branch": null,
|
||||
"base_branch": "no-fft",
|
||||
"worktree_path": null,
|
||||
"commit": null,
|
||||
"pr_url": null,
|
||||
"subtasks": [],
|
||||
"children": [],
|
||||
"parent": null,
|
||||
"relatedFiles": [],
|
||||
"notes": "",
|
||||
"meta": {}
|
||||
}
|
||||
@@ -1,51 +1,27 @@
|
||||
// ═══════════════════════════════════════════════════════
|
||||
// 基础时序乘法器模块 (无 DSP,移位累加,32个周期)
|
||||
// 3-stage pipelined multiplier (LUT-based, no DSP)
|
||||
// latency=3, throughput=1 result/cycle
|
||||
// ═══════════════════════════════════════════════════════
|
||||
module shift_add_mult (
|
||||
(* use_dsp = "no" *)
|
||||
module pipelined_mult_32x32 (
|
||||
input clk,
|
||||
input rstn,
|
||||
input start,
|
||||
input [31:0] a,
|
||||
input [31:0] b,
|
||||
output reg [63:0] p,
|
||||
output reg done
|
||||
output reg [63:0] p
|
||||
);
|
||||
reg [5:0] cnt;
|
||||
reg [63:0] a_reg;
|
||||
reg [31:0] b_reg;
|
||||
reg busy;
|
||||
reg [31:0] a_r, b_r;
|
||||
reg [63:0] prod;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!rstn) begin
|
||||
busy <= 1'b0;
|
||||
done <= 1'b0;
|
||||
p <= 64'b0;
|
||||
cnt <= 6'd0;
|
||||
a_reg<= 64'b0;
|
||||
b_reg<= 32'b0;
|
||||
a_r <= 32'b0; b_r <= 32'b0;
|
||||
prod <= 64'b0; p <= 64'b0;
|
||||
end else begin
|
||||
if (start && !busy) begin
|
||||
a_reg <= {32'b0, a};
|
||||
b_reg <= b;
|
||||
p <= 64'b0;
|
||||
cnt <= 6'd0;
|
||||
busy <= 1'b1;
|
||||
done <= 1'b0;
|
||||
end else if (busy) begin
|
||||
if (cnt == 6'd32) begin
|
||||
busy <= 1'b0;
|
||||
done <= 1'b1;
|
||||
end else begin
|
||||
if (b_reg[0]) begin
|
||||
p <= p + a_reg;
|
||||
end
|
||||
a_reg <= a_reg << 1;
|
||||
b_reg <= b_reg >> 1;
|
||||
cnt <= cnt + 6'd1;
|
||||
end
|
||||
end else begin
|
||||
done <= 1'b0;
|
||||
end
|
||||
a_r <= a; // Stage 1: register inputs
|
||||
b_r <= b;
|
||||
prod <= a_r * b_r; // Stage 2: LUT-based multiply
|
||||
p <= prod; // Stage 3: register output
|
||||
end
|
||||
end
|
||||
endmodule
|
||||
@@ -323,9 +299,7 @@ module matmul_axi_slave (
|
||||
|
||||
// 前向声明引擎的状态
|
||||
localparam C_IDLE = 2'd0;
|
||||
localparam C_CALC = 2'd1;
|
||||
localparam C_WAIT_MULT = 2'd2;
|
||||
localparam C_ACCUM = 2'd3;
|
||||
localparam C_RUN = 2'd1;
|
||||
reg [1:0] state;
|
||||
reg cur_bank;
|
||||
reg calc_done_pulse;
|
||||
@@ -344,8 +318,8 @@ module matmul_axi_slave (
|
||||
done <= 1'b0;
|
||||
error <= 1'b0;
|
||||
end else begin
|
||||
if (req_0 && state == C_CALC && cur_bank == 1'b0) req_0 <= 1'b0;
|
||||
if (req_1 && state == C_CALC && cur_bank == 1'b1) req_1 <= 1'b0;
|
||||
if (req_0 && state == C_RUN && cur_bank == 1'b0) req_0 <= 1'b0;
|
||||
if (req_1 && state == C_RUN && cur_bank == 1'b1) req_1 <= 1'b0;
|
||||
|
||||
if (calc_done_pulse) begin
|
||||
done <= 1'b1;
|
||||
@@ -524,102 +498,104 @@ module matmul_axi_slave (
|
||||
// ==========================================
|
||||
// 计算引擎 (Compute FSM)
|
||||
// ==========================================
|
||||
reg [3:0] calc_idx;
|
||||
|
||||
wire [1:0] row = calc_idx[3:2];
|
||||
wire [1:0] col = calc_idx[1:0];
|
||||
|
||||
reg mult_start;
|
||||
wire mult_done [0:3];
|
||||
wire [63:0] mult_p [0:3];
|
||||
reg [63:0] mult_p_r [0:3];
|
||||
reg [31:0] m_in_a [0:3];
|
||||
reg [31:0] m_in_b [0:3];
|
||||
|
||||
genvar i;
|
||||
generate
|
||||
for (i = 0; i < 4; i = i + 1) begin : mult_inst
|
||||
shift_add_mult u_mult (
|
||||
pipelined_mult_32x32 u_mult (
|
||||
.clk (clk),
|
||||
.rstn (resetn),
|
||||
.start (mult_start),
|
||||
.a (m_in_a[i]),
|
||||
.b (m_in_b[i]),
|
||||
.p (mult_p[i]),
|
||||
.done (mult_done[i])
|
||||
.p (mult_p[i])
|
||||
);
|
||||
end
|
||||
endgenerate
|
||||
|
||||
// Pipeline delay shift registers for accumulation (4 stages = 3 multiplier pipe + 1)
|
||||
reg [3:0] acc_idx_d1, acc_idx_d2, acc_idx_d3, acc_idx_d4;
|
||||
reg acc_bank_d1, acc_bank_d2, acc_bank_d3, acc_bank_d4;
|
||||
reg [4:0] pipe_cnt;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!resetn) begin
|
||||
state <= C_IDLE;
|
||||
busy <= 1'b0;
|
||||
cur_bank <= 1'b0;
|
||||
calc_idx <= 4'd0;
|
||||
mult_start <= 1'b0;
|
||||
calc_done_pulse <= 1'b0;
|
||||
pipe_cnt <= 5'd0;
|
||||
acc_idx_d1 <= 4'd0;
|
||||
acc_idx_d2 <= 4'd0;
|
||||
acc_idx_d3 <= 4'd0;
|
||||
acc_idx_d4 <= 4'd0;
|
||||
acc_bank_d1 <= 1'b0;
|
||||
acc_bank_d2 <= 1'b0;
|
||||
acc_bank_d3 <= 1'b0;
|
||||
acc_bank_d4 <= 1'b0;
|
||||
end else begin
|
||||
calc_done_pulse <= 1'b0;
|
||||
|
||||
// Pipeline shift: issue_idx → d1 → d2 → d3 → d4 (4 cycles total)
|
||||
acc_idx_d4 <= acc_idx_d3;
|
||||
acc_idx_d3 <= acc_idx_d2;
|
||||
acc_idx_d2 <= acc_idx_d1;
|
||||
acc_idx_d1 <= pipe_cnt[3:0];
|
||||
acc_bank_d4 <= acc_bank_d3;
|
||||
acc_bank_d3 <= acc_bank_d2;
|
||||
acc_bank_d2 <= acc_bank_d1;
|
||||
acc_bank_d1 <= cur_bank;
|
||||
|
||||
case (state)
|
||||
C_IDLE: begin
|
||||
calc_idx <= 4'd0;
|
||||
pipe_cnt <= 5'd0;
|
||||
if (req_0) begin
|
||||
cur_bank <= 1'b0;
|
||||
busy <= 1'b1;
|
||||
state <= C_CALC;
|
||||
state <= C_RUN;
|
||||
end else if (req_1) begin
|
||||
cur_bank <= 1'b1;
|
||||
busy <= 1'b1;
|
||||
state <= C_CALC;
|
||||
state <= C_RUN;
|
||||
end else begin
|
||||
busy <= 1'b0;
|
||||
end
|
||||
end
|
||||
|
||||
C_CALC: begin
|
||||
C_RUN: begin
|
||||
// Issue 4 new operands every cycle (pipe_cnt 0-11, 12 rounds)
|
||||
if (pipe_cnt < 5'd12) begin
|
||||
if (cur_bank == 1'b0) begin
|
||||
m_in_a[0] <= b0_a[{row, 2'd0}]; m_in_b[0] <= b0_b[{2'd0, col}];
|
||||
m_in_a[1] <= b0_a[{row, 2'd1}]; m_in_b[1] <= b0_b[{2'd1, col}];
|
||||
m_in_a[2] <= b0_a[{row, 2'd2}]; m_in_b[2] <= b0_b[{2'd2, col}];
|
||||
m_in_a[3] <= b0_a[{row, 2'd3}]; m_in_b[3] <= b0_b[{2'd3, col}];
|
||||
m_in_a[0] <= b0_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b0_b[{2'd0, pipe_cnt[1:0]}];
|
||||
m_in_a[1] <= b0_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b0_b[{2'd1, pipe_cnt[1:0]}];
|
||||
m_in_a[2] <= b0_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b0_b[{2'd2, pipe_cnt[1:0]}];
|
||||
m_in_a[3] <= b0_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b0_b[{2'd3, pipe_cnt[1:0]}];
|
||||
end else begin
|
||||
m_in_a[0] <= b1_a[{row, 2'd0}]; m_in_b[0] <= b1_b[{2'd0, col}];
|
||||
m_in_a[1] <= b1_a[{row, 2'd1}]; m_in_b[1] <= b1_b[{2'd1, col}];
|
||||
m_in_a[2] <= b1_a[{row, 2'd2}]; m_in_b[2] <= b1_b[{2'd2, col}];
|
||||
m_in_a[3] <= b1_a[{row, 2'd3}]; m_in_b[3] <= b1_b[{2'd3, col}];
|
||||
end
|
||||
mult_start <= 1'b1;
|
||||
state <= C_WAIT_MULT;
|
||||
end
|
||||
|
||||
C_WAIT_MULT: begin
|
||||
mult_start <= 1'b0;
|
||||
if (mult_done[0] && mult_done[1] && mult_done[2] && mult_done[3]) begin
|
||||
mult_p_r[0] <= mult_p[0];
|
||||
mult_p_r[1] <= mult_p[1];
|
||||
mult_p_r[2] <= mult_p[2];
|
||||
mult_p_r[3] <= mult_p[3];
|
||||
state <= C_ACCUM;
|
||||
m_in_a[0] <= b1_a[{pipe_cnt[3:2], 2'd0}]; m_in_b[0] <= b1_b[{2'd0, pipe_cnt[1:0]}];
|
||||
m_in_a[1] <= b1_a[{pipe_cnt[3:2], 2'd1}]; m_in_b[1] <= b1_b[{2'd1, pipe_cnt[1:0]}];
|
||||
m_in_a[2] <= b1_a[{pipe_cnt[3:2], 2'd2}]; m_in_b[2] <= b1_b[{2'd2, pipe_cnt[1:0]}];
|
||||
m_in_a[3] <= b1_a[{pipe_cnt[3:2], 2'd3}]; m_in_b[3] <= b1_b[{2'd3, pipe_cnt[1:0]}];
|
||||
end
|
||||
end
|
||||
|
||||
C_ACCUM: begin
|
||||
if (cur_bank == 1'b0)
|
||||
b0_c[calc_idx] <= ({2'b0, mult_p_r[0]} + {2'b0, mult_p_r[1]}) +
|
||||
({2'b0, mult_p_r[2]} + {2'b0, mult_p_r[3]});
|
||||
// Accumulate results from 4 cycles ago (pipe_cnt 4-15)
|
||||
if (pipe_cnt >= 5'd4 && pipe_cnt < 5'd16) begin
|
||||
if (acc_bank_d4 == 1'b0)
|
||||
b0_c[acc_idx_d4] <= ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
|
||||
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
|
||||
else
|
||||
b1_c[calc_idx] <= ({2'b0, mult_p_r[0]} + {2'b0, mult_p_r[1]}) +
|
||||
({2'b0, mult_p_r[2]} + {2'b0, mult_p_r[3]});
|
||||
b1_c[acc_idx_d4] <= ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
|
||||
({2'b0, mult_p[2]} + {2'b0, mult_p[3]});
|
||||
end
|
||||
|
||||
if (calc_idx == 4'd15) begin
|
||||
if (pipe_cnt == 5'd16) begin
|
||||
calc_done_pulse <= 1'b1;
|
||||
busy <= 1'b0;
|
||||
state <= C_IDLE;
|
||||
end else begin
|
||||
calc_idx <= calc_idx + 4'd1;
|
||||
state <= C_CALC;
|
||||
pipe_cnt <= pipe_cnt + 5'd1;
|
||||
end
|
||||
end
|
||||
endcase
|
||||
|
||||
Reference in New Issue
Block a user