Seyed Kian
Seyed Kian

Reputation: 45

Signed and Unsigned Multiplication Problem in Verilog

I have been working on approximate multiplication recently and I want to write a Verilog code for dynamic segment multiplication (DSM) . It suggest that you find the first index in you number which has a value of 1 and then take other 3 indexes next to it to form a 4 bit number that represent an 8 bit number then you should multiply these 4 bit numbers instead of 8 bits then some shifts to have the final result it helps a lot on hardware actually.. but my problem is about multiplication of these segments because sometimes they should be considered signed and some time unsigned I have the last 3 lines of my code: (a and b are input 8 bit numbers) and m1 and m2 are segments I wrote m,m2 as reg signed [3:0] and a and b as input signed [7:0] Here is my code:

    assign out = ({a[7],b[7]}==2'b11)||({a[7],b[7]}==2'b00) ? ($unsigned(m1)*$unsigned(m2)) << (shift_m1+shift_m2) : 16'dz;
assign out = ({a[7],b[7]}==2'b01) ? ($signed({1'b0,m1})*$signed(m2)) << (shift_m1+shift_m2) : 16'dz;
assign out = ({a[7],b[7]}==2'b10) ? ($signed(m1)*$signed({1'b0,m2})) << (shift_m1+shift_m2) : 16'dz;

But in simulation Verilog always considers segments as unsigned and does unsigned multiplication even though I noted signed or unsigned mark... Can anyone help? I read all of the questions about this problem in stackoverflow and other places but still cannot solve this issue...

Upvotes: 0

Views: 3284

Answers (1)

dave_59
dave_59

Reputation: 42788

The rules for non-self determined operands say that if one operand is unsigned, the result is unsigned. 16'dz is unsigned.

The conditional operator i ? j : k has the condition operand i self-determined, but the two selections j and k are in a context based on the assignment or expression it is a part of. The shift operator i << j has the shift amount operand j self-determined.

All of the context rules are explained in section 11.6.1 Rules for expression bit lengths in the IEEE 1800-2017 SystemVerilog LRM.

You can get your desired result by using the signed literal 16'sdz.

However the logic you wrote may not be synthesizable for certain technologies that do not allow using a z state inside your device. The correct and more readable way is using a case statement:

alway @(*) case({a[7],b[7]})
  2'b00, 
  2'b11: out = $unsigned(m1)*$unsigned(m2) << shift_m1+shift_m2;
  2'b01: out = $signed({1'b0,m1})*m2       << shift_m1+shift_m2;
  2'b10: out = m1*$signed({1'b0,m2})       << shift_m1+shift_m2;
endcase

Upvotes: 1

Related Questions