Combinatorial Verilog¶
Wires and net declarations¶
wire a, b;
wire y;
wire [1:0] a2, b2;
Inputs and outputs to and from modules are automatically declared as wires, unless they are subsequently declared as registers (next talk).
module mymod (
input [1:0] y2;
output [2:0] y3;
)
Logic bitwise primitives¶
Negation
assign y = ~a;
AND, OR and exclusive-OR gates
assign y = a & b;
assign y = a | b;
assign y = a ^ b;
Reduction¶
wire y;
wire [1:0] a2;
assign y = | a2;
is equivalent to:
wire y;
wire [1:0] a2;
assign y = a2[1] | a2[0];
Concatenation and Replication¶
wire y;
wire [1:0] y2;
wire [2:0] y3;
assign y2 = {a,b}; // creates a 2-bit signal of a with b
assign y2 = {a,1'b0}; // a with 1 bit binary 0 (constant)
assign y3 = {a,b,1'b1}; // a with b with binary 1 (constant)
assign y3 = {a,2'b10}; // a with 2 binary bits 1, 0
assign y3 = {a,a2}; // a with a2 (a2 is 2 bits)
assign y3 = {a,a2[0],1'b1}; // a with single bit from a2 with 1
assign {y2,y} = {y3[1:0],a}; // multiple assignment: creates y2 as
// 2 bits from y3 and y as a
assign y3 = {a,2{1'b1}}; // a with 2 lots of binary 1
Note use of //
to introduce a comment.
Shifting¶
Both arithmetic and logic shifts are provided. The following table illustrates the difference.
a a >> 2 a >>> 2 a << 2 a <<< 3
01001111 00010011 00010011 00111100 00111100
11001111 00110011 11110011 00111100 00111100
Examples:
assign y2 = a2 >> 1; // Logical 0's shifted in
assign y2 = a2 >>> 1; // Arithemtic MSB sign bit shifted in
assign y2 = a2 << 1; // Logical shift left same result as
assign y2 = a2 <<< 1; // Arithmetic shift left
Rotation¶
Rotate right 1 bit:
assign y4 = {y3[0],y3[2:1]};
Rotate right 2 bit:
assign y4 = {y3[1:0],y3[2]};
Operator precedence¶
() [] :: .
+ - ! ~ & ~& | ~| ^ ~^ ^~ ++ -- (unary)
**
* / %
+ - (binary)
<< >> <<< >>>
< <= > >= inside dist
== != === !== =?= !?=
& (binary)
^ ~^ ^~ (binary)
| (binary)
&&
||
? : (conditional operator)
>
= += -= *= /= %= &= ^= |= <<= >>= <<<= >>>= := :/ <=
{} {{}}
Combinatorial always blocks¶
For use when simple expressions get too complicated
always @(*)
a = b;
always @(*)
begin
a = b;
y = a | b;
end
SystemVerilog offers a more explicit format
always_comb
a = b;
If/Else (1)¶
wire [7:0] a, b;
wire [7:0] min;
always_comb
if(a < b)
min = a;
else
min = b;
If/Else (2)¶
More generally:
always_comb
if(boolean)
begin // need begin...end if >1 line of code within block
// if code
end
else
begin
// else code
end
Conditional example: 4-bit decoder¶
Given a 2 bit value input, set that bit in the output, but only if the enable input is asserted (high). Truth table:
en a1 a2 y
0 - - 0000
1 0 0 0001
1 0 1 0010
1 1 0 0100
1 1 1 1000
Conditional example: implementation¶
module decoder (
input [1:0] a,
input en,
output [3:0] y
)
always_comb
if (~en)
y = 4'b0000; // 4-bit wide, binary representation: 0000
else if(a == 2'b00)
y = 4'b0001;
else if(a == 2'b01)
y = 4'b0010;
else if(a == 2'b10)
y = 4'b0100;
else
y = 4'b1000;
endmodule
Conditional example: improved¶
module decoder (
input [1:0] a,
input en,
output [3:0] y
)
always_comb
case ({en,a})
3'b000, 3'b001,3'b010,3'b011: y = 4'b0000;
3'b100: y = 4'b0001;
3'b101: y = 4'b0010;
3'b110: y = 4'b0100;
3'b111: y = 4'b1000;
endcase // {en,a}
endmodule
Uncertainty: X and Z values¶
X is the “don’t care” value. Specifiying this can make for more efficient synthesis, since the tools can choose whichever value is most efficient.
Z is the “high impedence” value, typically used for connections that can be both inputs and outputs, typically under the control of an enable signal.
assign y = (oen) ? a : 1'bz;
Decoder example using X¶
module decoder (
input [1:0] a,
input en,
output [3:0] y
)
always_comb
casex ({en,a})
3'b0xx: y = 4'b0000;
3'b100: y = 4'b0001;
3'b101: y = 4'b0010;
3'b110: y = 4'b0100;
3'b111: y = 4'b1000;
endcase // {en,a}
endmodule
There is also casez
.
Multiple assignment¶
always_comb
if (en) y = 1'b0;
always_comb
y = a & b;
Won’t synthesize because y
is the output of two circuits which is
contraditory. It should be written as:
always_comb
if (en)
y = 1'b0;
else
y = a & b;
Exercise 2¶
Start with button_led.v
in the basic_verilog/button_led
directory. Complete it so that the LED which is lit up depends on whether the
button is pressed.
Build it with:
make button_led
Then experiment using both buttons, so that each combination of buttons lights
a different LED. Use a case
statement for this.