mirror of
https://github.com/allaunthefox/Research-Stack.git
synced 2026-07-30 18:56:16 +00:00
This squashes all local history (768 commits) onto the scrubbed PR #90 baseline. Individual commits were lost during filter-repo corruption; the working tree content is preserved intact. Build: N/A (working tree state only)
496 lines
18 KiB
Verilog
496 lines
18 KiB
Verilog
// Mode-Multiplexed DSP Slice
|
|
// Derived from expansion paths document: mode-multiplexing instead of partial reconfiguration
|
|
// Target: Gowin GW1NR-9 (20 hard DSP macros) or iCE40 HX8K (soft logic)
|
|
// Q16.16 fixed-point arithmetic
|
|
// 6 modes: Multiply, Accumulate, Convolution, FFT-Butterfly, FIR-Tap, Adaptive
|
|
|
|
`timescale 1ns / 1ps
|
|
|
|
`include "s3c_core.v"
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// DSP Mode Enumeration
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
localparam MODE_MUL = 3'd0; // Multiply: A * B
|
|
localparam MODE_ACC = 3'd1; // Accumulate: Acc + A * B
|
|
localparam MODE_CONV = 3'd2; // Convolution: Sum(A[i] * B[i])
|
|
localparam MODE_FFTBFLY = 3'd3; // FFT Butterfly: Twiddle multiply
|
|
localparam MODE_FIRTAP = 3'd4; // FIR Tap: Coeff * Sample + Acc
|
|
localparam MODE_ADAPTIVE = 3'd5; // Adaptive: Learning rate update
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// Gowin DSP Macro Wrapper (18x18 multiplier with 54-bit accumulator)
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
module gowin_dsp_macro (
|
|
input wire clk,
|
|
input wire rst_n,
|
|
input wire [31:0] a, // Q16.16 operand A
|
|
input wire [31:0] b, // Q16.16 operand B
|
|
input wire [53:0] acc_in, // 54-bit accumulator input
|
|
input wire acc_en, // Accumulator enable
|
|
input wire rst_acc, // Reset accumulator
|
|
output wire [31:0] mul_out, // Q16.16 product
|
|
output wire [53:0] acc_out // 54-bit accumulator output
|
|
);
|
|
// Gowin DSP macro instantiation (simplified for simulation)
|
|
// In synthesis, this maps to GW_DSP_MULT_18X18 or similar
|
|
|
|
reg [31:0] mul_reg;
|
|
reg [53:0] acc_reg;
|
|
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
mul_reg <= 32'd0;
|
|
acc_reg <= 54'd0;
|
|
end else begin
|
|
// Q16.16 multiplication
|
|
mul_reg <= (a[31:16] * b[31:16]) >> 16; // Simplified
|
|
|
|
// Accumulator
|
|
if (rst_acc) begin
|
|
acc_reg <= 54'd0;
|
|
end else if (acc_en) begin
|
|
acc_reg <= acc_in + {22'b0, mul_reg};
|
|
end else begin
|
|
acc_reg <= acc_in;
|
|
end
|
|
end
|
|
end
|
|
|
|
assign mul_out = mul_reg;
|
|
assign acc_out = acc_reg;
|
|
endmodule
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// Soft Multiplier (for iCE40 HX8K - no hard DSPs)
|
|
// Iterative bit-serial to save LUTs
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
module soft_multiplier (
|
|
input wire clk,
|
|
input wire rst_n,
|
|
input wire start,
|
|
input wire [31:0] a,
|
|
input wire [31:0] b,
|
|
output reg busy,
|
|
output reg [31:0] product
|
|
);
|
|
reg [4:0] bit_count;
|
|
reg [31:0] a_shift;
|
|
reg [31:0] b_shift;
|
|
reg [31:0] result;
|
|
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
busy <= 1'b0;
|
|
bit_count <= 5'd0;
|
|
a_shift <= 32'd0;
|
|
b_shift <= 32'd0;
|
|
result <= 32'd0;
|
|
product <= 32'd0;
|
|
end else begin
|
|
if (start && !busy) begin
|
|
busy <= 1'b1;
|
|
bit_count <= 5'd0;
|
|
a_shift <= a;
|
|
b_shift <= b;
|
|
result <= 32'd0;
|
|
end else if (busy) begin
|
|
if (b_shift[0]) begin
|
|
result <= result + a_shift;
|
|
end
|
|
a_shift <= a_shift << 1;
|
|
b_shift <= b_shift >> 1;
|
|
bit_count <= bit_count + 1'b1;
|
|
|
|
if (bit_count == 5'd31) begin
|
|
product <= result;
|
|
busy <= 1'b0;
|
|
end
|
|
end
|
|
end
|
|
end
|
|
endmodule
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// Mode-Multiplexed DSP Slice
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
module dsp_slice_mode_mux (
|
|
input wire clk,
|
|
input wire rst_n,
|
|
input wire [2:0] mode, // Current mode
|
|
input wire [31:0] operand_a, // Q16.16 operand A
|
|
input wire [31:0] operand_b, // Q16.16 operand B
|
|
input wire [31:0] coeff, // Q16.16 coefficient (for FIR/FFT)
|
|
input wire [53:0] acc_in, // 54-bit accumulator input
|
|
input wire valid_in, // Input valid
|
|
output reg [31:0] result, // Q16.16 result
|
|
output reg [53:0] acc_out, // 54-bit accumulator output
|
|
output reg valid_out, // Output valid
|
|
output reg busy // Slice busy
|
|
);
|
|
// Gowin DSP macro (or soft multiplier on iCE40)
|
|
wire [31:0] mul_out;
|
|
wire [53:0] dsp_acc_out;
|
|
|
|
gowin_dsp_macro dsp_inst (
|
|
.clk(clk),
|
|
.rst_n(rst_n),
|
|
.a(operand_a),
|
|
.b(operand_b),
|
|
.acc_in(acc_in),
|
|
.acc_en(mode == MODE_ACC || mode == MODE_CONV || mode == MODE_FIRTAP),
|
|
.rst_acc(mode != MODE_ACC && mode != MODE_CONV && mode != MODE_FIRTAP),
|
|
.mul_out(mul_out),
|
|
.acc_out(dsp_acc_out)
|
|
);
|
|
|
|
// Mode-specific processing
|
|
reg [31:0] mode_result;
|
|
reg [53:0] mode_acc;
|
|
reg [2:0] pipeline_stage;
|
|
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
result <= 32'd0;
|
|
acc_out <= 54'd0;
|
|
valid_out <= 1'b0;
|
|
busy <= 1'b0;
|
|
mode_result <= 32'd0;
|
|
mode_acc <= 54'd0;
|
|
pipeline_stage <= 3'd0;
|
|
end else begin
|
|
valid_out <= 1'b0;
|
|
|
|
if (valid_in) begin
|
|
busy <= 1'b1;
|
|
pipeline_stage <= 3'd1;
|
|
end
|
|
|
|
case (pipeline_stage)
|
|
3'd1: begin
|
|
// Stage 1: Multiply
|
|
mode_result <= mul_out;
|
|
mode_acc <= dsp_acc_out;
|
|
pipeline_stage <= 3'd2;
|
|
end
|
|
3'd2: begin
|
|
// Stage 2: Mode-specific processing
|
|
case (mode)
|
|
MODE_MUL: begin
|
|
mode_result <= mul_out;
|
|
mode_acc <= 54'd0;
|
|
end
|
|
MODE_ACC: begin
|
|
mode_result <= mul_out;
|
|
mode_acc <= dsp_acc_out;
|
|
end
|
|
MODE_CONV: begin
|
|
mode_result <= mul_out;
|
|
mode_acc <= dsp_acc_out;
|
|
end
|
|
MODE_FFTBFLY: begin
|
|
// Twiddle multiply: operand_a * coeff
|
|
mode_result <= mul_out;
|
|
mode_acc <= 54'd0;
|
|
end
|
|
MODE_FIRTAP: begin
|
|
// FIR tap: coeff * operand_a + acc
|
|
mode_result <= mul_out;
|
|
mode_acc <= dsp_acc_out;
|
|
end
|
|
MODE_ADAPTIVE: begin
|
|
// Adaptive: learning rate update
|
|
mode_result <= mul_out;
|
|
mode_acc <= 54'd0;
|
|
end
|
|
default: begin
|
|
mode_result <= 32'd0;
|
|
mode_acc <= 54'd0;
|
|
end
|
|
endcase
|
|
pipeline_stage <= 3'd3;
|
|
end
|
|
3'd3: begin
|
|
// Stage 3: Output
|
|
result <= mode_result;
|
|
acc_out <= mode_acc;
|
|
valid_out <= 1'b1;
|
|
busy <= 1'b0;
|
|
pipeline_stage <= 3'd0;
|
|
end
|
|
endcase
|
|
end
|
|
end
|
|
endmodule
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// Multi-Slice DSP Array (4 slices for parallel processing)
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
module dsp_slice_array (
|
|
input wire clk,
|
|
input wire rst_n,
|
|
input wire [2:0] mode [0:3], // Mode for each slice
|
|
input wire [31:0] operand_a [0:3], // Q16.16 operand A for each slice
|
|
input wire [31:0] operand_b [0:3], // Q16.16 operand B for each slice
|
|
input wire [31:0] coeff [0:3], // Q16.16 coefficient for each slice
|
|
input wire [53:0] acc_in [0:3], // 54-bit accumulator input for each slice
|
|
input wire valid_in,
|
|
output reg [31:0] results [0:3], // Q16.16 results
|
|
output reg [53:0] acc_outs [0:3], // 54-bit accumulator outputs
|
|
output reg valid_out,
|
|
output wire array_busy
|
|
);
|
|
wire [31:0] slice_results [0:3];
|
|
wire [53:0] slice_acc_outs [0:3];
|
|
wire [3:0] slice_valids;
|
|
wire [3:0] slice_busies;
|
|
|
|
genvar i;
|
|
generate
|
|
for (i = 0; i < 4; i = i + 1) begin : slice_gen
|
|
dsp_slice_mode_mux slice_inst (
|
|
.clk(clk),
|
|
.rst_n(rst_n),
|
|
.mode(mode[i]),
|
|
.operand_a(operand_a[i]),
|
|
.operand_b(operand_b[i]),
|
|
.coeff(coeff[i]),
|
|
.acc_in(acc_in[i]),
|
|
.valid_in(valid_in),
|
|
.result(slice_results[i]),
|
|
.acc_out(slice_acc_outs[i]),
|
|
.valid_out(slice_valids[i]),
|
|
.busy(slice_busies[i])
|
|
);
|
|
end
|
|
endgenerate
|
|
|
|
integer j;
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
for (j = 0; j < 4; j = j + 1) begin
|
|
results[j] <= 32'd0;
|
|
acc_outs[j] <= 54'd0;
|
|
end
|
|
valid_out <= 1'b0;
|
|
end else begin
|
|
for (j = 0; j < 4; j = j + 1) begin
|
|
results[j] <= slice_results[j];
|
|
acc_outs[j] <= slice_acc_outs[j];
|
|
end
|
|
valid_out <= &slice_valids;
|
|
end
|
|
end
|
|
|
|
assign array_busy = |slice_busies;
|
|
endmodule
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// DSP Slice with S3C Integration
|
|
// Combines mode-multiplexed DSP with S3C manifold processing
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
module dsp_s3c_integrated (
|
|
input wire clk,
|
|
input wire rst_n,
|
|
input wire [2:0] dsp_mode,
|
|
input wire [31:0] audio_sample, // Q16.16 audio sample
|
|
input wire [31:0] filter_coeff, // Q16.16 filter coefficient
|
|
input wire sample_valid,
|
|
output reg [31:0] dsp_result,
|
|
output reg [3:0] s3c_state,
|
|
output reg s3c_emit,
|
|
output reg [31:0] s3c_j_score,
|
|
output reg dsp_valid
|
|
);
|
|
// DSP slice array
|
|
wire [31:0] operand_a [0:3];
|
|
wire [31:0] operand_b [0:3];
|
|
wire [31:0] coeff [0:3];
|
|
wire [53:0] acc_in [0:3];
|
|
wire [31:0] dsp_results [0:3];
|
|
wire [53:0] dsp_acc_outs [0:3];
|
|
wire array_busy;
|
|
|
|
integer k;
|
|
always @(*) begin
|
|
for (k = 0; k < 4; k = k + 1) begin
|
|
operand_a[k] = audio_sample;
|
|
operand_b[k] = filter_coeff;
|
|
coeff[k] = filter_coeff;
|
|
acc_in[k] = 54'd0;
|
|
end
|
|
end
|
|
|
|
wire [2:0] modes [0:3];
|
|
assign modes[0] = dsp_mode;
|
|
assign modes[1] = dsp_mode;
|
|
assign modes[2] = dsp_mode;
|
|
assign modes[3] = dsp_mode;
|
|
|
|
dsp_slice_array dsp_array (
|
|
.clk(clk),
|
|
.rst_n(rst_n),
|
|
.mode(modes),
|
|
.operand_a(operand_a),
|
|
.operand_b(operand_b),
|
|
.coeff(coeff),
|
|
.acc_in(acc_in),
|
|
.valid_in(sample_valid),
|
|
.results(dsp_results),
|
|
.acc_outs(dsp_acc_outs),
|
|
.valid_out(dsp_valid),
|
|
.array_busy(array_busy)
|
|
);
|
|
|
|
// Use first slice result
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
dsp_result <= 32'd0;
|
|
end else if (dsp_valid) begin
|
|
dsp_result <= dsp_results[0];
|
|
end
|
|
end
|
|
|
|
// S3C processing on DSP result
|
|
wire [15:0] s3c_sample;
|
|
assign s3c_sample = dsp_result[31:16];
|
|
|
|
// S3C shell decomposition
|
|
wire [15:0] s3c_k, s3c_a, s3c_b;
|
|
wire [31:0] s3c_mass, s3c_width;
|
|
|
|
s3c_shell_decomposition s3c_shell (
|
|
.n(s3c_sample),
|
|
.k(s3c_k),
|
|
.a(s3c_a),
|
|
.b(s3c_b),
|
|
.mass(s3c_mass),
|
|
.width(s3c_width)
|
|
);
|
|
|
|
// S3C J-score
|
|
wire [31:0] s3c_massResonance, s3c_mirrorResonance, s3c_spectralCoupling, s3c_jScore_wire;
|
|
|
|
s3c_j_score s3c_jscore (
|
|
.handleK(s3c_k),
|
|
.handleA(s3c_a),
|
|
.handleB(s3c_b),
|
|
.massResonance(s3c_massResonance),
|
|
.mirrorResonance(s3c_mirrorResonance),
|
|
.spectralCoupling(s3c_spectralCoupling),
|
|
.total(s3c_jScore_wire)
|
|
);
|
|
|
|
// S3C emission gate
|
|
wire s3c_kappaA, s3c_kappaC;
|
|
|
|
s3c_three_point_contact s3c_contact (
|
|
.handleK(s3c_k),
|
|
.handleA(s3c_a),
|
|
.handleB(s3c_b),
|
|
.kappaA(s3c_kappaA),
|
|
.kappaB(),
|
|
.kappaC(s3c_kappaC)
|
|
);
|
|
|
|
wire s3c_emit_wire;
|
|
s3c_emission_gate s3c_emit_inst (
|
|
.kappaA(s3c_kappaA),
|
|
.kappaC(s3c_kappaC),
|
|
.jScore(s3c_jScore_wire),
|
|
.emit(s3c_emit_wire)
|
|
);
|
|
|
|
// Register S3C outputs
|
|
always @(posedge clk or negedge rst_n) begin
|
|
if (!rst_n) begin
|
|
s3c_state <= 4'd0;
|
|
s3c_emit <= 1'b0;
|
|
s3c_j_score <= 32'd0;
|
|
end else if (dsp_valid) begin
|
|
s3c_emit <= s3c_emit_wire;
|
|
s3c_j_score <= s3c_jScore_wire;
|
|
|
|
if (s3c_emit_wire) begin
|
|
s3c_state <= 4'd4;
|
|
end else begin
|
|
s3c_state <= 4'd0;
|
|
end
|
|
end
|
|
end
|
|
endmodule
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
// Testbench
|
|
// ═══════════════════════════════════════════════════════════════════════════
|
|
module dsp_s3c_testbench;
|
|
reg clk;
|
|
reg rst_n;
|
|
reg [2:0] dsp_mode;
|
|
reg [31:0] audio_sample;
|
|
reg [31:0] filter_coeff;
|
|
reg sample_valid;
|
|
|
|
wire [31:0] dsp_result;
|
|
wire [3:0] s3c_state;
|
|
wire s3c_emit;
|
|
wire [31:0] s3c_j_score;
|
|
wire dsp_valid;
|
|
|
|
dsp_s3c_integrated dut (
|
|
.clk(clk),
|
|
.rst_n(rst_n),
|
|
.dsp_mode(dsp_mode),
|
|
.audio_sample(audio_sample),
|
|
.filter_coeff(filter_coeff),
|
|
.sample_valid(sample_valid),
|
|
.dsp_result(dsp_result),
|
|
.s3c_state(s3c_state),
|
|
.s3c_emit(s3c_emit),
|
|
.s3c_j_score(s3c_j_score),
|
|
.dsp_valid(dsp_valid)
|
|
);
|
|
|
|
initial clk = 0;
|
|
always #18.5185 clk = ~clk;
|
|
|
|
initial begin
|
|
rst_n = 0;
|
|
dsp_mode = MODE_MUL;
|
|
audio_sample = 32'd0;
|
|
filter_coeff = 32'd0;
|
|
sample_valid = 0;
|
|
|
|
#100;
|
|
rst_n = 1;
|
|
|
|
#100;
|
|
|
|
// Test multiply mode
|
|
dsp_mode = MODE_MUL;
|
|
audio_sample = 32'sd10000 << 16;
|
|
filter_coeff = 32'sd2000 << 16;
|
|
sample_valid = 1;
|
|
#100;
|
|
sample_valid = 0;
|
|
#500;
|
|
|
|
$display("Mode MUL: result=%d, s3c_state=%d, s3c_emit=%b, s3c_j_score=%d",
|
|
dsp_result, s3c_state, s3c_emit, s3c_j_score);
|
|
|
|
// Test accumulate mode
|
|
dsp_mode = MODE_ACC;
|
|
audio_sample = 32'sd15000 << 16;
|
|
filter_coeff = 32'sd3000 << 16;
|
|
sample_valid = 1;
|
|
#100;
|
|
sample_valid = 0;
|
|
#500;
|
|
|
|
$display("Mode ACC: result=%d, s3c_state=%d, s3c_emit=%b, s3c_j_score=%d",
|
|
dsp_result, s3c_state, s3c_emit, s3c_j_score);
|
|
|
|
#1000;
|
|
$finish;
|
|
end
|
|
endmodule
|