Integers and integer expressions can be tricky in Verilog. For example what's the result of the following?
module m;
reg [7:0] a, b;
initial begin
a=100; b=200;
$display("%d", (a + b) >> 1 );
$display("%d", (a + b) / 2 );
end
endmodule
The standard provides a thorough explanation on expression evaluation, but if you need a shorter version, this post is for you!
Integers
Integers are represented by a group of bits, length of the container in bits, and sign info (signed or unsigned). Examples:
3'b101 // bits 101, len 3, unsigned
3'sb101 // bits 101, len 3, signed
5'd2 // bits 10, len 5, unsigned (d=decimal)
5'hA // bits 1010, len 5, unsigned (h=hex)
5'sd1 // bits 1, len 5, signed
'sd1 // bits 1, len 32 (default), signed
'd1 // bits 1, len 32 (default), unsigned
6 // bits 110, len 32 (default),
// signed (default when no base is specified!)
-2 // we treat this as the expression as
// -(2) and not a negative number.
// We'll come back to expressions later.
The tricky part is: if no base is specified, it's unsigned; and if base is specified it's unsigned.
Also keep in mind that the default length when it's not specified is MOST LIKELY 32. The standard says it's AT LEAST 32 bits, but the actual default value is up to the simulator/synthesizer.
What happens if the container's length doesn't match the length of the bits we have? If the container is larger, we add zeros to the left (we "zero-extend" it). If the container is smaller than the bits , we remove the leftmost bits.
3'b110 // specified length matches value length
2'b110 // will be cropped to 10
5'b110 // add zeros to make the length 5. result is 00110
5'sb110 // for signed numbers we still zero-extend,
// and NOT sign-extend. Result is 00110
4 // len 32, signed. 00000000000000000000000000000100
Tricky part: signed literals like 5'sb110 are zero-extended ONLY when simulator is determining their initial value. In all other cases, whenever a signed number needs to be extended, it's going to be SIGN-extended.
The functions $signed()
and $unsigned()
are used to change the signedness of the integer. These functions DON'T change the bits. They merely change the type to signed or unsigned. The type determines how the operators operate on values. For example,
Assignments and expressions
Assignment is a kind of statement where we assign a new value to a net or a variable. There is always a = or a <= operator in an assignment. The left-hand-side (LFS) is the name of the net/variable, and the right-hand-side (RHS) is an expression whose value needs to be determined.
module m;
wire w = 1; // assigns 1 to w
assign w = 0; // assigns 0 to w
reg a, b; // declarations, no assignment
initial begin
a = 1; // assigns 1 to a
b <= 2; // assigns 2 to b
end
endmodule
An expression consists of operands and operators. It gets evaluated, and is turned into a value, which might then be assigned to a net/variable.
We will analyze the following 3 cases separately:
a = 10 // assignment without an expression
10+a*b // expression without an assignment
b = a+2 // assignment with an expression
Assignment without an expression
The simplest of the three cases. The size of the LHS is determined by its declaration. The size of the RHS is either specified or inferred to be 32. To fit the size of the net/variable, the RHS is either truncated, or extended. Unsigned numbers are zero-extended, and signed numbers are sign-extended.
module m;
reg a; // declaration. len 1
reg [4:0] b; // declaration. len 5
reg signed s; // declaration. signed, len 1
initial begin
a = 1'b0; // same size
a = 3'b110; // truncate rhs to "0"
b = 1'b1; // zero-extend rhs to "00001"
b = 1'sb1; // sign-extend rhs to "11111"
b = 2'sb1; // rhs is "01". sign-extend to "00001"
b[2:1] = 3; // lhs len: 2. rhs len: 32. truncate to "11"
{a, b} = 7'hCC; // lhs len: 6. rhs len: 7.
// truncate "11001100" to "1001100"
// a gets "0", b gets "01100".
// leftmost "1" is dropped
{a, b} = 7'shCC; // same as above
b = a; // a is unsigned 1 bit long. zero-extend to 5 bits
b = s; // s is signed 1 bit long. sign-extend to 5 bits
b = 2'sb10; // s is signed, "10". sign-extend to "11110"
end
endmodule
Note: when assigning unsigned to signed, and signed to unsigned, we extend depending on RHS. It doesn't matter whether reg on LHS is signed or not.
Expression without an assignment
Expressions without an assignment are called "self-determined" and are encountered in places like:
- if statements
- while statements
- range select
- delay expressions
They are evaluated in 3 steps:
- Parse the expression according to the precedence and associativity rules
- Do the sign analysis
- Do the bit length (size) analysis
1. Precedence and associativity
Precedence is done according to the following table:
This means A+B*C
is A+(B*C)
since *
has a higher precedence than +
.
Associativity is what happens when two operators have the same precedence. In verilog, it's always left-to-right, except for the ?: operator. This means that A+B+C
is seen as (A+B)+C
.
And regarding ?: associativity:
a ? b ? c : d : e // a ? (b ? c : d) : e
a ? b : c ? d : e // a ? b : (c ? d : e)
a ? b ? c : d : e ? f : g // a ? (b ? c : d) : (e ? f : g)
2. Sign analysis
We go from bottom to top, and apply these rules:
- Bit select
a[3]
is always unsigned. - Range select
a[3:0]
is always unsigned. - Concatenation
{3'sd4, 4'd5}
is always unsigned. - Replication
{4{5'd6}}
is always unsigned. - Comparison
a==b
is always unsigned. - For unary operators
-a
,~a
the sign doesn't change. - For binary operators, if both operands are signed, result is signed. Otherwise, unsigned.
- For shift operators, the RHS is treated as unsigned, and result has the same signedness as the LHS.
- For
a?b:c
operator, if bothb
andc
are signed, result is signed. Otherwise, unsigned.
3. Bit length analysis
The following table from the standard applies:
Examples
-12 / 3
// First, the expression is parsed into ( -(12) ) / 3.
// Sign analysis:
// Both 12 and 3 are signed. -a doesn't change the signedness.
// a/b results in signed since both operands are signed.
// Bit length analysis:
// Both 12 and 3 are 32-bit. -a doesn't change the length.
// a/b happens in 32-bit context. Result is 32-bit.
// Evaluation:
// 12 = 000...1100
// -12 = 111...0011 +1
// = 111...0100
// signed interpretation of this number: -12
// -12 / 3 gives -4 (signed)
-'d12 / 3
// Expression is parsed the same way.
// Sign analysis:
// 'd12 is unsigned. -a keeps it unsigned.
// Since one of the operands is unsigned,
// division is in unsigned context.
// 3 is signed, so it is turned into unsigned.
// Its value doesn't change.
// Bit length analysis:
// Both 'd12 and 3 are 32-bit. -a doesn't change the length.
// a/b happens in 32-bit context. Result is 32-bit.
// Evaluation:
// 'd12 = 000...1100
// -'d12 = 111...0011 +1
// = 111...0100
// unsigned interpretation of this number: 4294967284
// after the division, result is 1431655761.33...
// the number is rounded down to 1431655761
-'sd12 / 3
// Expression is parsed the same way.
// Sign analysis:
// 'sd12 is signed. It's the same as 12.
// So the evaluation proceeds the same way as in -12/3.
// Result is -4.
-4'sd12 / 3
// Expression is parsed the same way.
// Sign analysis:
// All operands are signed,
// so everything happens in signed context.
// Bit length analysis:
// 4'sd12 is 4-bit. -a keeps the length at 4-bit.
// 3 is 32-bit. a/b happens in 32-bit context.
// For it to happen in 32-bit context,
// 4'sd12 is first extended to 32-bit.
// -a gives 32-bit and division happens in 32-bit context.
// Important:
// what's extended to 32-bit is the constant 4'sd12
// and NOT the result of -4'sd12.
// Always propagate the extension all the way to constants.
// Also note that it's not the same as typing 32'sd12.
// 4'sd12 = 1100
// extend to 32-bit: 111...1100
// apply -a: 000...0011 +1
// = 000...0100
// signed interpretation of this number: 4
// then result is 4/3 = 1
Tip: Use the $displayb system task to see the result of a self-determined expression.
Assignment with an expression
The rules slightly change when an assignment is combined with an expression. It's NOT just evaluating the expression and then doing assignment. Expressions in an assignment context are called "context-determined".
The sign analysis doesn't change: do it as if there was no assignment.
Bit length analysis must now involve the LHS of the assignment.
Examples
integer intA; // same as reg signed [31:0]
reg [15:0] regA; // unsigned
reg signed [15:0] regS; // signed
intA = -4'd12; // 4'd12 = 1100 unsigned
// max(lhs, -4'd12) = max(32,4) = 32
// extend 4'd12 to 32 bits: 000...1100
// apply -x: 111...0011 +1
// =111...0100
// signed interpretation: -12
regA = intA / 3; // both operands signed, so result is signed
// max(lhs, intA, 3) = max(16,32,32) = 32
// extend intA to 32-bit. Same value.
// -12/3 yields -4. In binary 111...1100
// Truncate to 16 bits: 111...1100
// now regA holds 111...1100
// unsigned interpretation: 65532
regA = -4'd12; // 4'd12 = 1100 unsigned
// max(16,4) = 16.
// extend to 16 bits: 000...1100
// apply -x: 111...0011 +1
// =111...0100
// now regA holds 111...0100
// unsigned interpretation: 65524
intA = regA / 3; // regA is unsigned, 3 is signed
// so divide in unsigned context
// max(intA,regA,3) = max(16,16,32) = 32
// extend regA to 32 bits. value stays same
// 65524/3 = 21841.33..
// round down: 21841
// now intA holds 21841
intA = -4'd12 / 3; // 4'd12 = 1100
// unsigned/signed = unsigned
// max(16,4,32) = 32
// extend 4'd12 to 32-bit: 000...1100
// apply -x: 111...0011 +1
// =111...0100
// unsigned interpretation: 4294967284
// divide by 3 and round down: 1431655761
// in hex: 0x55555551
// in order to save to intA,
// truncate to 16-bit: 0x5551 = 21841
regA = -12 / 3; // signed/signed = signed
// max(16,32,32) = 32
// extend 12 to 32-bit: 000...1100
// apply -x: 111...0011 +1
// =111...0100
// signed interpretation: -12
// -12/3 gives -4 = 111...1100
// truncate to 16 bits: 0xfffc = 65532
regS = -12 / 3; // signed/signed = signed
// max(16,32,32) = 32
// do the same procedure above
// result is -4
// truncate to 16 bits: 0xfffc
// signed interpretation: -4
regS = -4'sd12 / 3; // signed/signed = signed
// 4'sd12 = 1100
// max(16,4,32) = 32
// extend 4'sd12 to 32-bit: 111...1100
// apply -x: 000...0011 +1
// =000...0100
// signed interpretation: 4
// now divide 4/3 = 1 = 000...0001
// truncate to 16 bits and save to regS
// regS now holds 1, signed
Next example:
module m;
reg [7:0] a, b, avg;
reg [8:0] big;
initial begin
a = 255;
b = 1;
avg = (a + b) >> 1;
// unsigned+unsigned = unsigned
// unsigned >> x = unsigned
// for context-determined expressions:
// len( (a+b)>>1 ) = len(a+b)
// and len(a+b) = max(len(avg), len(a), len(b))
// = max(8,8,8) = 8
// so addition is in 8-bit context
// 255+1 in 8-bits gives 0. carry is lost
// then 0>>1 gives 0.
// avg holds 0.
avg = (a + b + 0) >> 1;
// first parse: ((a+b)+0) >> 1
// unsigned+unsigned+signed = unsigned
// unsigned >> x = unsigned
// for context-determined expressions:
// len( (a+b+0)>>1 ) = len(a+b+0)
// and len(a+b+0) = max(len(avg), len(a), len(b), len(0))
// = max(8, 8, 8, 32) = 32
// so addition is in 32-bit context
// 255+1 in 32-bits gives 256. carry is kept
// then 256>>1 gives 128.
// avg is 128
// or you could use a 9-bit register:
big = (a + b) >> 1;
// unsigned+unsigned = unsigned
// unsigned >> x = unsigned
// for context-determined expressions:
// len(a+b) = max(len(big), len(a), len(b))
// = max(9, 8, 8) = 9
// so addition is in 9-bit context
// 255+1 in 32-bits gives 256. carry is kept
// then 256>>1 gives 128.
end
endmodule
Another example:
module bitlength();
reg [3:0] a,b,c;
reg [4:0] d;
initial begin
a = 9;
b = 8;
c = 1;
$displayb(c ? (a&b) : d);
// here there's no assignment,
// so c ? (a&b) : d is self-determined
// unsigned & unsigned = unsigned, and
// x ? unsigned : unsigned = unsigned
// len(c ? (a&b) : d) = max(len(a&b), len(d))
// = max(len(a), len(b), len(d))
// = max(4,4,5) = 5
// so first extend a and b to 5 bits:
// a = 9 = 1001 -> 01001
// b = 8 = 1000 -> 01000
// a&b = 01000
// since c=1, result is 01000
end
endmodule
Last example:
module m;
reg [3:0] a; // len 4
reg [5:0] b; // len 6
reg [15:0] c; // len 16
initial begin
a = 4'hF; // =15
b = 6'hA; // =10
$display("a*b=%h", a*b);
// a*b is self-determined.
// len(a*b) = max(len(a), len(b)) = max(4,6) = 6
// 15*10 = 150 = 10010110
// truncate to 6 bits: 010110 = 0x16
c = {a**b};
$display("a**b=%h", c);
// {a**b} is context-determined
// a**b is self-determined because of {} rule
// len(a**b) = len(a) = 4
// so 15**10 = 0x86430aac61
// truncate to 4 bits: 0x1
// in order to assign 4 bits to 16-bit c
// extend it to 16 bits: 0x0001
c = a**b;
$display("c=%h", c);
// a**b is context-determined due to assignment
// len(a**b) = max(len(c), len(a))
// = max(16,4) = 16
// so 15**10 = 0x86430aac61
// truncate to 16 bits: 0xac61
end
endmodule
Top comments (0)