Files
fpga_modem/rtl/core/mul_const.v
2025-10-19 16:18:40 +02:00

71 lines
2.2 KiB
Verilog
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
`timescale 1ns/1ps
// =============================================================================
// Multiply a value by a constant
// Use a shift-add algorithm instead of a multiplier
// parameters:
// -- W : data width
// -- C : constant
// inout:
// -- x : input of width W
// -- y : output of widht 2W
// =============================================================================
module mul_const_shiftadd#(
parameter integer W = 16,
parameter integer C = 16'sh7fff
)(
input wire signed [W-1:0] x,
output wire signed [2*W-1:0] y
);
// Sign and magnitude of constant
localparam integer C_NEG = (C < 0) ? 1 : 0;
localparam integer C_ABS = (C < 0) ? -C : C;
// MSB index of |C| (0-based). Keeps network minimal.
function integer msb_index;
input integer v;
integer i;
begin
msb_index = -1;
for (i = 0; i < 32; i = i + 1)
if (v >> i) msb_index = i;
end
endfunction
localparam integer I_MAX = (C_ABS == 0) ? 0 : msb_index(C_ABS);
// 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] ? (x_ext <<< i) : {PPW{1'b0}};
end
endgenerate
// 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];
end else begin
assign sum[0] = part[0];
for (i = 1; i <= I_MAX; i = i + 1) begin : GEN_SUM
assign sum[i] = sum[i-1] + part[i];
end
end
endgenerate
// Apply sign of C
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