`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 don’t truncate high/sign bits wire signed [PPW-1:0] x_ext = {{(PPW-W){x[W-1]}}, x}; // Partial products (only where C’s 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