Clean way to truncate result of addition or subtraction - verilog

When I do addition or subtraction in Verilog, some compilers emit warning.
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
// warning example
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 11 to match size of target (10) File: xxx.sv Line: xxx
Warning (13469): Verilog HDL assignment warning at xxx.sv(xxx): truncated value with size 32 to match size of target (10) File: xxx.sv Line: xxx
I want to find clean way to remove these warnings. I tried two methods:
// method 1
b <= (a + 1)[9 : 0];
// method 2
logic [10 : 0] d;
d <= a + 1;
b <= d[9 : 0];
I thought the first method would compile, but it was invalid syntax in verilog.
Second method works, but it is too verbose and dirty.
Is there any other clean ways?

From IEEE Std 1364-2001.
Page 73:
Table 29—Bit lengths resulting from self-determined expressions:
Unsized constant number = Same as integer
Page 45:
NOTE Implementations may limit the maximum size of an integer variable, but they shall at least be 32 bits.
So the warnings you see come from trying to operate one unsized numeric constant (32 bits at least) with a sized variable (10 bits), so the synthesizer warns about the result may overflow.
So, just make sure all your operands have the same size:
Instead of:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 1;
c <= a - 1;
end
Do:
// code example
logic [9 : 0] a, b, c;
always_ff #(posedge clk) begin
b <= a + 10'd1;
c <= a - 10'd1;
end

1 id a 32-bit value. As a result the width of the expression is 32.
The way around is to use a sized value of '1', i.e.
b <= a + 1'b1;
c <= b - 1'b1;
This can potentially give you an 11-bit result. Carryon bit will be lost. At this point you can do some other tricks. I guess this is the most common one. Use a carry on bit.
logic con;
logic[9:0] a,b;
...
{con, a} <= b + 1'b1;
You can use a temp variable, as in your example.
In general, verilog standard does allow free truncation or extension of operand widths and no warning is required. Definitely in this case you can ignore the warning or turn it off. I have not seen simulators which would warn about it. Just certain rule in linting tools.

Use curley concatination braces
b <= {a + 1}[9 : 0];
or change the constant size (which defaults to 32-bits)
b <= a + 10'd1;

Related

What does '1 mean in verilog?

I have a register with 4bits.
reg[3:0] a;
And I want to assign a single bit to it like
a <= '1;
Apparently it is not the same 1'b1 and 1.
I am new to verilog and not sure about its syntax.
Can anyone enlighten me please.
This sets all bits to 1, I believe.
Just to answer the original question,
To assign '1' to a[3:0], do one of the following (assuming you're in an always block):
a <= 4'b1; // binary 1 in 4 digits
a <= 4'h1; // hexadecimal 1 in 4 digits
a <= 4'd1; // decimal
a <= 4'b0001; // I prefer this syntax with explicit zero padding
Each of the above assignments can also explicitly specify the range of the signal:
a[3:0] <= 4'h1;
Note that the assignment <= could be replaced with = depending on your needs.

Implementing one-bit flags in a 32Bit ALU using Verilog

I am working on an assignment and am a little lost and don't really know how to get started. I need to implement the following flags in a 32Bit ALU:
• Z ("Zero"): Set to 1 ("True") if the result of the operation is zero
• N ("Negative"): Set to 1 ("True") if the first bit of the result is 1, which indicates a negative number
• O ("Overflow"): Set to 1 ("True") to indicate that the operation overflowed the bus width.
Additionally, a comparison function that compares input a to input b and then set one of three flags:
• LT if input a is less than input b
• GT if input a is greater than input b
• EQ if input a is equal to input b
I need to modify this ALU to include the three flags and comparison outputs then change the test bench to test for all of these modifications.
This was all the information I received for this assignment and there is no textbook or any other resources really. It's an online class, and I cannot get a response from my instructor. So I am a little confused as to how to get started. I am still a total newbie when it comes to digital logic so please bear with me. I just need some help understanding how these flags and comparison works. If any one can explain this a little better to me as far as how they work and what they do, and possibly how I would implement them into the ALU and testbench, I would really appreciate it.
I don't expect anyone to do my assignment, I really just need help understanding it.
ALU
module alu32 (a, b, out, sel);
input [31:0] a, b;
input [3:0] sel;
output [31:0] out,
reg [31:0] out;
//Code starts here
always #(a, b, sel)
begin
case (sel)
//Arithmetic Functions
0 : out <= a + b;
1 : out <= a - b;
2 : out <= b - a;
3 : out <= a * b;
4 : out <= a / b;
5 : out <= b % a;
//Bit-wise Logic Functions
6 : out <= ~a; //Not
7 : out <= a & b; //And
8 : out <= a | b; //Or
9 : out <= a ^ b; //XOR
10 : out <= a ^~ b; //XNOR
//Logic Functions
11 : out <= !a;
12 : out <= a && b;
13 : out <= a || b;
default: out <= a + b;
endcase
end
endmodule
ALU Testbench
module alu32_tb();
reg [31:0] a, b;
reg [3:0] sel;
wire [31:0] out;
initial begin
$monitor("sel=%d a=%d b=%d out=%d", sel,a,b,out);
//Fundamental tests - all a+b
#0 sel=4'd0; a = 8'd0; b = 8'd0;
#1 sel=4'd0; a = 8'd0; b = 8'd25;
#1 sel=4'd0; a = 8'd37; b = 8'd0;
#1 sel=4'd0; a = 8'd45; b = 8'd75;
//Arithmetic
#1 sel=4'd1; a = 8'd120; b = 8'd25; //a-b
#1 sel=4'd2; a = 8'd30; b = 8'd120; //b-a
#1 sel=4'd3; a = 8'd75; b = 8'd3; //a*b
#1 sel=4'd4; a = 8'd75; b = 8'd3; //a/b
#1 sel=4'd5; a = 8'd74; b = 8'd3; //a%b
//Bit-wise Logic Functions
#1 sel=4'd6; a = 8'd31; //Not
#1 sel=4'd7; a = 8'd31; b = 8'd31; //And
#1 sel=4'd8; a = 8'd30; b = 8'd1; //Or
#1 sel=4'd9; a = 8'd30; b = 8'd1; //XOR
#1 sel=4'd10; a = 8'd30; b = 8'd1; //XNOR
//Logic Functions
#1 sel=4'd11; a = 8'd25; //Not
#1 sel=4'd12; a = 8'd30; b = 8'd0; //And
#1 sel=4'd13; a = 8'd0; b = 8'd30; //Or
#1 $finish;
end
alu32 myalu (.a(a), .b(b), .out(out), .sel(sel));
endmodule
You can add these flag outputs to the design. Like the following. Simply connect them in testbench.
// In design:
output zero;
output overflow;
output negative;
// In testbench:
wire zero,overflow,negative;
alu32 myalu (.a(a), .b(b), .out(out), .sel(sel), .zero(zero), .overflow(overflow),.negative(negative));
For logic part, you can do it with continuous assignments. You may need to add some logic for using these flags only during certain values of sel.
Z ("Zero"): Set to 1 ("True") if the result of the operation is zero
So, we can have condition like all the bits of out must be zero. This can be done in many other ways.
// Bit wise OR-ing on out
assign zero = ~(|out);
O ("Overflow"): Set to 1 ("True") to indicate that the operation overflowed the bus width.
According to this description and the code shown, you simply want carry flag here.That is, a signed extension of addition operation. Refer to this page on WikiPedia for overflow condition.
But, Overflow condition is not the same as the carry bit. Overflow represents data loss while carry represents a bit used for calculation in next stage.
So, doing something like following may be useful:
// Extend the result for capturing carry bit
// Simply use this bit if you want result > bus width
{carry,out} <= a+b;
// overflow in signed arithmetic:
assign overflow = ({carry,out[31]} == 2'b01);
N ("Negative"): Set to 1 ("True") if the first bit of the result is 1, which indicates a negative number
Again this is simply the MSB of the out register. But, the underflow condition is entirely a different thing.
// Depending on sel, subtraction must be performed here
assign negative = (out[31] == 1 && (sel == 1 || sel == 2));
Also, simple condition like assign lt = (a<b) ? 1 : 0; and others can detect the input LT, GT and EQ conditions.
Refer the answer here for the overflow/underflow flag understanding. Overflow-Carry link may also be useful.
Refer Carryout-Overflow, ALU in Verilog and ALU PDF for further information about ALU implementation.

Quartus and modelsim - compile size casting

I'll try to compile in Quartus and simulate in ModelSim some module.
See this:
module somemodule(
... inputs, outputs, etc...
);
localparam BUFFER_LEN = 96;
localparam BUFFER_LENW = $clog2(BUFFER_LEN);
localparam DATA_WIDTH = 32;
logic [BUFFER_LENW-1:0] bits_remain;
always_ff #(posedge rd_clk) begin : _proc_bitsremain
if (state == LOAD) begin
case (somevalue)
1: bits_remain <= DATA_WIDTH * 1;
2: bits_remain <= DATA_WIDTH * 2;
default: bits_remain <= BUFFER_LEN;
endcase
end
else
bits_remain <= bits_remain - 1;
end
endmodule
So, I compile it in modelsim. I have 0 errors and 0 warnings. Simulation is success, all is good. Next, I compile (synthesis) it in Quartus, and I have this warning:
Warning (10230): Verilog HDL assignment warning at <location>:
truncated value with size 32 to match size of target (7)
So, I understand the warning, and fix it by size casting:
module somemodule(
... inputs, outputs, etc...
);
localparam BUFFER_LEN = 96;
localparam BUFFER_LENW = $clog2(BUFFER_LEN);
logic [BUFFER_LENW-1:0] bits_remain;
always_ff #(posedge rd_clk) begin : _proc_bitsremain
if (state == LOAD) begin
case (somevalue)
1: bits_remain <= BUFFER_LENW'(DATA_WIDTH * 1);
2: bits_remain <= BUFFER_LENW'(DATA_WIDTH * 2);
default: bits_remain <= BUFFER_LENW'(BUFFER_LEN);
endcase
end
else
bits_remain <= BUFFER_LENW'(bits_remain - 1);
end
endmodule
In Quartus compilation is success. But, If I'll try to compile this code in ModelSim again, I have a error:
** Error: <location>(148): near "'": syntax error, unexpected '\'', expecting ';'
Where I wrong and why modelSim can't compile a size casting?
The casting is covered by section 6.24 in IEEE 1800-2012 & IEEE 1800-2009. IEEE 1800 is the SystemVerilog standard. I do not see it covered in any of the Verilog standards (please leave a comment if you can point me to the section in IEEE 1364-1995, 2001 or 2005).
Forcing to use system verilog compiler might solve the issue, normally done through changing the file extension to '.sv' or adding a -sv flag to the command line.
The standards do not dictate which parts are for simulation only and which are synthesisable, so you may run into issues where you can simulate but not synthesise. If I have followed the question correctly the reverse is true at the minute. which could just be differing levels of support for SystemVerilog.
However you can cast using temp variables or have a temp variable to catch the extra bits, which never gets used and is optimised away.
reg [W-1:0] temp_two;
always #* begin
temp_two = (DATA_WIDTH * 2);
end
//...
bits_remain <= temp_two[4:0];
Or
reg [W-5:0] temp_throw_away;
{temp_throw_away, bits_remain} <= (DATA_WIDTH * 2);
The legality of the syntax BUFFER_LENW'(DATA_WIDTH * 1) is questionable in the current SystemVerilog standard. The LRM only mentions a positive decimal number appearing before the ' and everything else is interpreted as a type. However many tools now allow an integer parameter as you have done so here. ModelSim 10.3 and later releases now support this extension to the LRM.
There are two currently legal ways to write this in SystemVerilog. One is with a part-select on a concatenation.
bits_remain <= {DATA_WIDTH * 2}[BUFFER_LENW-1:0];
The other way is using a typedef and bit-stream cast
typedef logic [BUFFER_LENW-1:0] buffer_width_t;
buffer_width_t bits_remain;
bits_remain = buffer_width_t'(DATA_WIDTH * 2);
To typecast from a 32-bit unsigned to 8-bit unsigned, you need to select the bits you want from the 32-bit local parameter, and then perform any operations you want in the usual way.
localparam MY_CONST_32_BITS = 96; // parameters always seem to be type cast to 32 bit, even if you pass 8'd96 as the value.
wire [7:0] my_const_8_bits = MY_CONST_32_BITS[7:0]; // Select lower 8 bits out of 32 bits
wire [8:0] double_my_const_9_bits = my_const_8_bits * 8'd2; // 8 bit wide unsigned decimal value 2.
The above code compiles fine for me in Altera Quartus tools.

Verilog - generate weighted random numbers

I am trying to generate random single bits and this is simple as long as you want a normal randomization:
wire R;
assign R = $random % 2;
What I am looking for is a sort of weighted probability like:
wire R;
assign R = 60%(0) || 40%(1);
Forgive me if it is not conform to standard Verilog code, it is just to give an idea of what I want.
Can anyone help me out?
Thank you
The SystemVerilog solution has a distribution method within randomize called dist. Weights are assigned by value_or_range := weight or value_or_range :/ distributed_weight. This exert from the IEEE Std 1800-2012 § 18.5.4 page 476 gives a clear example:
When weights are applied to ranges, they can be applied to each value in the range, or they can be applied to the range as a whole. For example:
x dist { [100:102] := 1, 200 := 2, 300 := 5}
means x is equal to 100, 101, 102, 200, or 300 with a weighted ratio of 1-1-1-2-5, and
x dist { [100:102] :/ 1, 200 := 2, 300 := 5}
means x is equal to one of 100, 101, 102, 200, or 300 with a weighted ratio of
1/3-1/3-1/3-2-5.
dist is used in randomization so it needs to be mare of a randomize() with (or a class constraint). randomize returns a success bit, therefore it should be in called within an assert, void'(), or the RHS of an assignment.
In your we can set the weight of 0 to 6 and the weight of 1 to 4, creating a total weight of 10 with a 60/40 distribution. Example:
reg R;
initial begin
assert( randomize(R) with { R dist { 0 := 6, 1 := 4 }; } );
end
From more about dist see IEEE Std 1800-2012 § 18.5.4 "Distribution".
Create a random integer then based on Value return 1 or 0; NB you may want to seed your random number, for repeatability use the same seed. This way when a test fails it can be debugged.
$urandom works a little different to $random it doe not update the seed value so should only be seeded the first time it is called in a thread (always block). It is also thread safe, each always block works independently.
initial begin
$urandom(seed);
$urandom;
$urandom;
end
integer temp;
reg r ;
always # ... begin
temp = $urandom; //Range: +2_147_483_647 -2_147_483_648
// weighting; 0 would be 50:50
// real weighting is (0.1 + 0.5), 0.5 inherent from positive number.
r = (temp > (2_147_483_647*0.1);
end
NB: the random functions are not synthesizable and should only be used for testbenches. if you want a random number for synthesis check out this Question
For Verilog you can always so something like:
integer R;
R = ($dist_uniform(0,100) < 60) : $dist_uniform(0,5) : $dist_uniform(6,10)
and this in SystemVerilog would be the same as:
std::randomize(R) with {R dist {[0:5] :/60, [6:10] :/ 40} ;};
You could also do this procedural code:
randcase
60: R = 1;
40: R = 0;
endcase
Following Code Will Generate Random Variable as Per Your Requirement :
program top;
class Packet;
rand reg R;
constraint percentage {R dist {1:=60,0:=40};};
function void display;
$display("Random Reg : %0d",this.R);
endfunction
endclass
Packet P;
initial
begin
P = new;
repeat(10)
begin
P.randomize();
P.display;
end
end
endprogram
It seems not so hard at verilog.
reg [7:0] R;
reg rand_bit;
R = $random();
if (R < 76)
rand_bit = 1'b0;
else
rand_bit = 1'b1;
Here I assume that $random is pretty uniform. I think it should work :)
Something like:
wire R;
if ($random[7:0]>(40*255/100))
assign R = 1'b0;
else
assign R = 1'b1;
I'm assuming that the algorithm that $random uses produces numbers that are equally random whatever bits you take from it.

Verilog Signed Multiplication "loses" the Signed Bit

I am writing a code which uses a multiplier module which returns weird answers when one of the inputs is a negative number. I am guessing this has to do with how Verilog treats signed numbers and the module is not storing the result properly in the 'reg signed out' decleration. All my input/output/wire/reg declarations are signed, so I am not sure what I am missing and what else I need to do to tell Verilog to take care of this. Sorry for the beginner question!
For example,
When X[0] is 1610 and Theta1[1] is -123, the result I am getting from the multiplier module is:
6914897148530
Here are the relevant parts of my code:
module mult(in1, in2, out, mult_start); // multiplication module
input signed [32-1:0] in1, in2;
input mult_start;
output signed [64-1:0] out;
reg signed [64-1:0] out;
always #(in1 or in2 or mult_start)
begin
if (mult_start)
begin
out <= (in1 * in2) & {64{1'b1}};
end
else
out <= out;
end
endmodule
module child_one (clk, rst_b, sig_start, Input_X, Input_Theta1)
// Internal Variables Memory
reg signed [`REG_LENGTH-1:0] Theta1 [0:217-1];
reg signed [`REG_LENGTH-1:0] X [0:216-1];
wire signed [`OUT_LENGTH-1:0] prod_1 [0:217-1];
reg signed [`OUT_LENGTH-1:0] prod_sum;
wire signed [`OUT_LENGTH-1:0] sig_result;
mult mult_001 (X[0], Theta1[1], prod_1[1], mult_start);
mult mult_002 (X[1], Theta1[2], prod_1[2], mult_start);
mult mult_003 (X[2], Theta1[3], prod_1[3], mult_start);
mult mult_004 (X[3], Theta1[4], prod_1[4], mult_start);
always #(posedge clk or negedge rst_b)
begin
if (sig_start == 1)
begin
if (state == 4'b0000)
begin
state <= 4'b0001; // initialize state variable to zero
k <= 0;
result_done <= 0;
index <= 0;
end
else if (state == 4'b0001) // Start Multiplication Operation
begin
k <= result_done ? 0 : k + 1;
result_done <= result_done ? 1 : (k == 10);
state <= result_done ? 4'b0010 : 4'b0001;
mult_start <= result_done ? 1'b1 : 1'b0;
//mult_start <= 1'b1;
//state <= 4'b0010;
end
else if (state == 4'b0010) // Stop Multiplication Operation
begin
k <= 0;
result_done <= 0;
mult_start <= 0;
state <= 4'b0011;
end
end
end
endmodule
Thanks,
Faisal.
Thanks for all the help and suggestions. Writing a separate testbench for the mult module helped arrive at a solution.
My issue was in the mult module. Since my inputs are 32 bits long, the mult output would be 32*2+1 = 65 bits long. My output port 'out' was only assigned to be 64 bits long which resulted in a sign issue when the answer was a negative number. Assigning it to be 65 bits long took care of my problem.
The issue is the & {64{1'b1}} part in the mult module. {64{1'b1}} is an unsigned subexpression. This causes in1 and in2 and to be treated as unsigned regardless of their declaration, and causes unsigned multiplication to be performed. The resulting bits assigned to out are then interpreted as signed again because of its declaration, but by then it's too late.
As you alluded to, the general Verilog signedness rule is that if any operand in a simple expression is unsigned, all operands in the expression are interpreted as unsigned, and thus the operators perform unsigned math. (There are many other nuances to the rules (e.g. relational operators), but they aren't applicable here.)
Note that you can't make {64{1'b1}} signed by changing it to {64{1'sb1}} because the result of the replication operator is always unsigned regardless of its operand. But you could wrap it in the $signed() system function, making the rest of the expression (the * and & steps) fully signed. Thus this would work correctly:
out <= (in1 * in2) & $signed({64{1'b1}});
But you really don't need to mask the result with that &. Regardless of the width of the inputs and the result of the multiplication, Verilog rules state that the final value of the RHS of the assignment will simply be truncated (discarding some MSBs) to the width of the LHS, if the RHS were wider. Thus masking with 64 ones is completely redundant.
To address the currently-accepted answer... It is not true that 65 bits are needed for 32x32 signed->signed multiplication. Only 64 bits are needed to handle even the most-extreme cases:
minimum result: -(2^31) * ((2^31) - 1) = -4611686016279904256 > -(2^63)
maximum result: ((2^31) - 1) * ((2^31) - 1) = 4611686014132420609 < (2^63) - 1
In general, for fully-signed multiplication of N bits by M bits, you only need N+M bits for the product (and N+M-1 would suffice if not for the single most-negative times most-negative case). This is also true for fully-unsigned multiplication. But if you were mixing signed and unsigned multiplicands/product (and using $signed() as needed to get Verilog to behave as desired), you would need an extra result bit in some cases (e.g. unsigned*unsigned->signed).

Resources