Search code examples
verilogmodelsim

Verilog: Multiply signed by unsigned


Right now I'm trying to adjust the amplitude of 12 bit signed input by an 8-bit variable.

module mixer_4input (in, amp, out);

input signed    [11:0]  in;
input           [7:0]   amp;
wire signed     [8:0]   signed_amp;
output signed  [19:0]   out;
  
assign signed_amp = amp; 
assign out = $signed((in  >> 8) * signed_amp);  
//assign out = $signed(amp) * (in >> 8); //this one works wrong too
  
endmodule

modelsim screenshot here

But the output is either have a missing sign or just completely wrong. radix type in modelsim is set according to what I wait to see

What am I doing wrong? Thanks


Solution

  • This line will not sign-extend as I think you are expecting:

    assign signed_amp = amp;
    

    amp is 8-bits wide and unsigned. Verilog will widen it to 9 bits by adding a 1'b0 to the left, whatever the state of bit 7 of amp. The fact that signed_amp is signed is irrelevant.

    To make this work, you need to first convert amp to be signed using the $signed system function:

    assign signed_amp = $signed(amp);
    

    I think this is also not behaving as you expect:

    assign out = $signed(amp) * (in >> 8);
    

    >> is a logical shift right. Because of that, zeros will be added on the left. I suspect you need this:

    assign out = $signed(amp) * (in >>> 8);
    

    using the arithmetic shift right operator - >>>, which will preserve the sign of in.