Added mul tb and fixed

This commit is contained in:
Joppe Blondel
2025-10-19 16:18:40 +02:00
parent eb7caaf2c5
commit b2858ac5ee
5 changed files with 136 additions and 17 deletions

View File

@@ -41,9 +41,11 @@ files_xco = boards/mimas_v1/ip/clk_gen.xco
[target.sim]
toolchain = iverilog
runtime = all
toplevel = tb_nco_q15
toplevel = tb_sigmadelta
ivl_opts = -Irtl/util
files_verilog = sim/tb/tb_nco_q15.v
sim/tb/tb_sigmadelta.v
sim/tb/tb_mul_const.v
rtl/core/nco_q15.v
rtl/core/lvds_comparator.v
rtl/core/sigmadelta_rcmodel_q15.v

View File

@@ -17,11 +17,11 @@ module mul_const_shiftadd#(
input wire signed [W-1:0] x,
output wire signed [2*W-1:0] y
);
// Absolute value and sign of C
localparam integer C_NEG = (C < 0) ? 1 : 0;
localparam integer C_ABS = (C < 0) ? -C : C;
// Sign and magnitude of constant
localparam integer C_NEG = (C < 0) ? 1 : 0;
localparam integer C_ABS = (C < 0) ? -C : C;
// Find MSB index of C_ABS to size the network
// MSB index of |C| (0-based). Keeps network minimal.
function integer msb_index;
input integer v;
integer i;
@@ -31,19 +31,26 @@ module mul_const_shiftadd#(
if (v >> i) msb_index = i;
end
endfunction
localparam integer I_MAX = (C_ABS == 0) ? 0 : msb_index(C_ABS);
// Partial products
wire signed [W+I_MAX:0] part [0:I_MAX];
// Width big enough for the largest partial product: W bits shifted by I_MAX
localparam integer PPW = W + I_MAX + 1;
// Pre-extend x to PPW so shifts dont truncate high/sign bits
wire signed [PPW-1:0] x_ext = {{(PPW-W){x[W-1]}}, x};
// Partial products (only where Cs bit is 1)
wire signed [PPW-1:0] part [0:I_MAX];
genvar i;
generate
for (i = 0; i <= I_MAX; i = i + 1) begin : GEN_PARTS
assign part[i] = (C_ABS[i]) ? ($signed(x) <<< i) : { (W+I_MAX+1){1'b0} };
assign part[i] = C_ABS[i] ? (x_ext <<< i) : {PPW{1'b0}};
end
endgenerate
// Adder chain (simple; replace with tree if you want higher performance)
wire signed [W+I_MAX:0] sum [0:I_MAX];
// Adder chain (you can replace with a balanced tree for speed)
wire signed [PPW-1:0] sum [0:I_MAX];
generate
if (I_MAX == 0) begin
assign sum[0] = part[0];
@@ -56,10 +63,9 @@ module mul_const_shiftadd#(
endgenerate
// Apply sign of C
wire signed [W+I_MAX:0] mag = (I_MAX==0) ? part[0] : sum[I_MAX];
wire signed [W+I_MAX:0] prod = C_NEG ? -mag : mag;
// Stretch to fixed y width (truncate/extend as you wish outside)
assign y = prod;
wire signed [PPW-1:0] mag = (I_MAX == 0) ? part[0] : sum[I_MAX];
wire signed [PPW-1:0] prod = C_NEG ? -mag : mag;
// Stretch/extend to 2W result width
assign y = {{((2*W)-PPW){prod[PPW-1]}}, prod};
endmodule

View File

@@ -12,7 +12,7 @@
// -- clk : input clock
// -- resetn : reset signal
// -- sd_sample : 1 bit sample output from sd sampler
// -- sample_q15 : output samples in q1.15
// -- sample_q15 : output samples in q.15
// =============================================================================
module sigmadelta_rcmodel_q15 #(
parameter integer alpha_q15 = 16'sh0b00
@@ -25,9 +25,10 @@ module sigmadelta_rcmodel_q15 #(
reg signed [15:0] y_q15;
wire signed [15:0] sd_q15 = sd_sample ? 16'sh7fff : 16'sh0000;
wire signed [15:0] e_q15 = sd_q15 - y_q15;
// wire signed [31:0] prod_q30 = $signed(e_q15) * $signed(alpha_q15);
wire signed [31:0] prod_q30;
// Use shift-add algorithm for multiplication
mul_const_shiftadd #(.C(alpha_q15)) alpha_times_e (e_q15, prod_q30);
mul_const_shiftadd #(.C($signed(alpha_q15))) alpha_times_e ($signed(e_q15), prod_q30);
wire signed [15:0] y_next_q15 = y_q15 + (prod_q30>>>15);
// clamp to [0, 0x7FFF] (keeps signal view tidy)

72
sim/tb/tb_mul_const.v Normal file
View File

@@ -0,0 +1,72 @@
`timescale 1ns/1ps
module tb_mul_const();
// -------------------------------------------------------------------------
// Parameters
// -------------------------------------------------------------------------
localparam integer W = 16;
localparam integer C = 16'sh0B3B; // alpha_q15 0.08774
localparam signed [W-1:0] C_S = C[W-1:0];
// -------------------------------------------------------------------------
// DUT I/O
// -------------------------------------------------------------------------
reg signed [W-1:0] x;
wire signed [(2*W)-1:0] y;
// Instantiate DUT
mul_const_shiftadd #(
.W(W),
.C(C)
) dut (
.x(x),
.y(y)
);
// -------------------------------------------------------------------------
// Reference and verification
// -------------------------------------------------------------------------
reg signed [(2*W)-1:0] expected;
integer i;
integer errors;
initial begin
$display("------------------------------------------------------");
$display(" Testbench: mul_const_shiftadd");
$display(" W = %0d, C = %0d (0x%0h)", W, $signed(C_S), C_S);
$display("------------------------------------------------------");
errors = 0;
// Exhaustively test all 16-bit signed values
for (i = -(1<<(W-1)); i < (1<<(W-1)); i = i + 1) begin
x = i;
#1; // let combinational logic settle
expected = $signed(x) * $signed(C_S);
if (y !== expected) begin
$display("FAIL: x=%6d (0x%04h) * C=%6d -> y=%10d (0x%08h), expected=%10d (0x%08h)",
$signed(x), x, $signed(C_S),
$signed(y), y, $signed(expected), expected);
errors = errors + 1;
// Uncomment next line if you want to stop on first mismatch
// $stop;
end
// progress message every 4096 iterations
if (((i + (1<<(W-1))) % 4096) == 0)
$display("Progress: %5d / %5d values tested...",
i + (1<<(W-1)), (1<<W));
end
if (errors == 0)
$display("✅ PASS: All %0d test cases matched perfectly.", (1<<W));
else
$display("❌ FAIL: %0d mismatches found out of %0d cases.",
errors, (1<<W));
$finish;
end
endmodule

38
sim/tb/tb_sigmadelta.v Normal file
View File

@@ -0,0 +1,38 @@
`timescale 1ns/1ps
module tb_sigmadelta();
// Clock and reset generation
reg clk;
reg resetn;
initial clk <= 1'b0;
initial resetn <= 1'b0;
always #6.667 clk <= !clk;
initial #40 resetn <= 1'b1;
// Default run
initial begin
$dumpfile("out.vcd");
$dumpvars;
#1_000_000
$finish;
end;
wire sd_a;
wire sd_b;
wire sd_o;
// 3K3R 220PC 15MHZT
sigmadelta_sampler sd_sampler(
.clk(clk),
.a(sd_a), .b(sd_b),
.o(sd_o)
);
wire signed [15:0] sample_q15;
sigmadelta_rcmodel_q15 rc_model(
.clk(clk), .resetn(resetn),
.sd_sample(sd_o),
.sample_q15(sample_q15)
);
endmodule