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 clk,
|
||||||
input rstn,
|
input rstn,
|
||||||
input start,
|
|
||||||
input [31:0] a,
|
input [31:0] a,
|
||||||
input [31:0] b,
|
input [31:0] b,
|
||||||
output reg [63:0] p,
|
output reg [63:0] p
|
||||||
output reg done
|
|
||||||
);
|
);
|
||||||
reg [5:0] cnt;
|
reg [31:0] a_r, b_r;
|
||||||
reg [63:0] a_reg;
|
reg [63:0] prod;
|
||||||
reg [31:0] b_reg;
|
|
||||||
reg busy;
|
|
||||||
|
|
||||||
always @(posedge clk) begin
|
always @(posedge clk) begin
|
||||||
if (!rstn) begin
|
if (!rstn) begin
|
||||||
busy <= 1'b0;
|
a_r <= 32'b0; b_r <= 32'b0;
|
||||||
done <= 1'b0;
|
prod <= 64'b0; p <= 64'b0;
|
||||||
p <= 64'b0;
|
|
||||||
cnt <= 6'd0;
|
|
||||||
a_reg<= 64'b0;
|
|
||||||
b_reg<= 32'b0;
|
|
||||||
end else begin
|
end else begin
|
||||||
if (start && !busy) begin
|
a_r <= a; // Stage 1: register inputs
|
||||||
a_reg <= {32'b0, a};
|
b_r <= b;
|
||||||
b_reg <= b;
|
prod <= a_r * b_r; // Stage 2: LUT-based multiply
|
||||||
p <= 64'b0;
|
p <= prod; // Stage 3: register output
|
||||||
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
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
@@ -323,9 +299,7 @@ module matmul_axi_slave (
|
|||||||
|
|
||||||
// 前向声明引擎的状态
|
// 前向声明引擎的状态
|
||||||
localparam C_IDLE = 2'd0;
|
localparam C_IDLE = 2'd0;
|
||||||
localparam C_CALC = 2'd1;
|
localparam C_RUN = 2'd1;
|
||||||
localparam C_WAIT_MULT = 2'd2;
|
|
||||||
localparam C_ACCUM = 2'd3;
|
|
||||||
reg [1:0] state;
|
reg [1:0] state;
|
||||||
reg cur_bank;
|
reg cur_bank;
|
||||||
reg calc_done_pulse;
|
reg calc_done_pulse;
|
||||||
@@ -344,8 +318,8 @@ module matmul_axi_slave (
|
|||||||
done <= 1'b0;
|
done <= 1'b0;
|
||||||
error <= 1'b0;
|
error <= 1'b0;
|
||||||
end else begin
|
end else begin
|
||||||
if (req_0 && state == C_CALC && cur_bank == 1'b0) req_0 <= 1'b0;
|
if (req_0 && state == C_RUN && cur_bank == 1'b0) req_0 <= 1'b0;
|
||||||
if (req_1 && state == C_CALC && cur_bank == 1'b1) req_1 <= 1'b0;
|
if (req_1 && state == C_RUN && cur_bank == 1'b1) req_1 <= 1'b0;
|
||||||
|
|
||||||
if (calc_done_pulse) begin
|
if (calc_done_pulse) begin
|
||||||
done <= 1'b1;
|
done <= 1'b1;
|
||||||
@@ -524,102 +498,104 @@ module matmul_axi_slave (
|
|||||||
// ==========================================
|
// ==========================================
|
||||||
// 计算引擎 (Compute FSM)
|
// 计算引擎 (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];
|
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_a [0:3];
|
||||||
reg [31:0] m_in_b [0:3];
|
reg [31:0] m_in_b [0:3];
|
||||||
|
|
||||||
genvar i;
|
genvar i;
|
||||||
generate
|
generate
|
||||||
for (i = 0; i < 4; i = i + 1) begin : mult_inst
|
for (i = 0; i < 4; i = i + 1) begin : mult_inst
|
||||||
shift_add_mult u_mult (
|
pipelined_mult_32x32 u_mult (
|
||||||
.clk (clk),
|
.clk (clk),
|
||||||
.rstn (resetn),
|
.rstn (resetn),
|
||||||
.start (mult_start),
|
|
||||||
.a (m_in_a[i]),
|
.a (m_in_a[i]),
|
||||||
.b (m_in_b[i]),
|
.b (m_in_b[i]),
|
||||||
.p (mult_p[i]),
|
.p (mult_p[i])
|
||||||
.done (mult_done[i])
|
|
||||||
);
|
);
|
||||||
end
|
end
|
||||||
endgenerate
|
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
|
always @(posedge clk) begin
|
||||||
if (!resetn) begin
|
if (!resetn) begin
|
||||||
state <= C_IDLE;
|
state <= C_IDLE;
|
||||||
busy <= 1'b0;
|
busy <= 1'b0;
|
||||||
cur_bank <= 1'b0;
|
cur_bank <= 1'b0;
|
||||||
calc_idx <= 4'd0;
|
|
||||||
mult_start <= 1'b0;
|
|
||||||
calc_done_pulse <= 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
|
end else begin
|
||||||
calc_done_pulse <= 1'b0;
|
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)
|
case (state)
|
||||||
C_IDLE: begin
|
C_IDLE: begin
|
||||||
calc_idx <= 4'd0;
|
pipe_cnt <= 5'd0;
|
||||||
if (req_0) begin
|
if (req_0) begin
|
||||||
cur_bank <= 1'b0;
|
cur_bank <= 1'b0;
|
||||||
busy <= 1'b1;
|
busy <= 1'b1;
|
||||||
state <= C_CALC;
|
state <= C_RUN;
|
||||||
end else if (req_1) begin
|
end else if (req_1) begin
|
||||||
cur_bank <= 1'b1;
|
cur_bank <= 1'b1;
|
||||||
busy <= 1'b1;
|
busy <= 1'b1;
|
||||||
state <= C_CALC;
|
state <= C_RUN;
|
||||||
end else begin
|
end else begin
|
||||||
busy <= 1'b0;
|
busy <= 1'b0;
|
||||||
end
|
end
|
||||||
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
|
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[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[{row, 2'd1}]; m_in_b[1] <= b0_b[{2'd1, col}];
|
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[{row, 2'd2}]; m_in_b[2] <= b0_b[{2'd2, col}];
|
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[{row, 2'd3}]; m_in_b[3] <= b0_b[{2'd3, col}];
|
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
|
end else begin
|
||||||
m_in_a[0] <= b1_a[{row, 2'd0}]; m_in_b[0] <= b1_b[{2'd0, col}];
|
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[{row, 2'd1}]; m_in_b[1] <= b1_b[{2'd1, col}];
|
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[{row, 2'd2}]; m_in_b[2] <= b1_b[{2'd2, col}];
|
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[{row, 2'd3}]; m_in_b[3] <= b1_b[{2'd3, col}];
|
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
|
|
||||||
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;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
C_ACCUM: begin
|
// Accumulate results from 4 cycles ago (pipe_cnt 4-15)
|
||||||
if (cur_bank == 1'b0)
|
if (pipe_cnt >= 5'd4 && pipe_cnt < 5'd16) begin
|
||||||
b0_c[calc_idx] <= ({2'b0, mult_p_r[0]} + {2'b0, mult_p_r[1]}) +
|
if (acc_bank_d4 == 1'b0)
|
||||||
({2'b0, mult_p_r[2]} + {2'b0, mult_p_r[3]});
|
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
|
else
|
||||||
b1_c[calc_idx] <= ({2'b0, mult_p_r[0]} + {2'b0, mult_p_r[1]}) +
|
b1_c[acc_idx_d4] <= ({2'b0, mult_p[0]} + {2'b0, mult_p[1]}) +
|
||||||
({2'b0, mult_p_r[2]} + {2'b0, mult_p_r[3]});
|
({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;
|
calc_done_pulse <= 1'b1;
|
||||||
busy <= 1'b0;
|
busy <= 1'b0;
|
||||||
state <= C_IDLE;
|
state <= C_IDLE;
|
||||||
end else begin
|
end else begin
|
||||||
calc_idx <= calc_idx + 4'd1;
|
pipe_cnt <= pipe_cnt + 5'd1;
|
||||||
state <= C_CALC;
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
endcase
|
endcase
|
||||||
|
|||||||
Reference in New Issue
Block a user