Wednesday, June 13, 2007

Veilog Basics (II)

Issues with Verilog:

Incomplete Specification of Conditions
(if-else or case) leads to 'Latches' (described later)

module mux_3to1(a,b,c,sel,out);
input [0:1] sel;
input a,b,c;
output out;
always@(a or b or c or sel) begin
case (sel)
2'b0: a;
2'b1: b;
2'b2: c; // what happens when 3 occurs????
endcase

endmodule
  • Thus for handling the case of 'three' as sel input a latch is introduced (which is unnecessary) to store the previous value.
  • The same is the case with a 'if' condition without a 'else'
  • To avoid this either precede the condition with default value for output or handle all the cases
    • Each if with a else condition
    • Each case with a default condition
CASE1:
always@(a or b or c or sel) begin
out = 1'b1;
case (sel)
2'b0: out = a;
2'b1: out = b;
2'b2: out = c;
endcase

CASE2:
always@(a or b or c or sel) begin
case (sel)
2'b0: out = a;
2'b1: out = b;
2'b2: out = c;
default: out = 1'b1;
endcase

Priority Logic:
Consider a case of 4 to 2 encoder, the truth table looks like
(I3,I2,I1,I0|E1,E2),
(0,0,0,1|0,0),(0,0,1,0|0,1),(0,1,0,0|1,0),(1,0,0,0|1,1),
For all others(x,x,x,x|x,x)
The code for such a module may look like

module may_encode_4to2(i,e);
input [0:3] i;
output [0:1] e;

always @ (i) begin
if(i[0]==1) e=2'b00;
else if(i[1]==1) e=2'b'01;
else if(i[2]==1) e =2'b'10;
else if(i[3]==1) e=2'b'11;
else e=2'bxx;
end

endmodule
  • Intension: Whenever two inputs are '1' the output must be don't care
  • Consider the input: i[0:4] = (1,0,0,1), the resultant output must be a don't care but unfortunately the output is a (0,0).
  • Reason: Since (i[0]==1) takes higher priority compared to the final else condition and so may fail. If-else and case statements are interpreted literally
  • Resulting Circuit: A serial bit comparison circuit.
  • Prevention: Try to give mutually exclusive inputs for comparison functions as demonstrated below so that the logic evaluated is simpler and circuit implemented would be in parallel
module encoder_4to2(i,3);
input [0:3] i;
output [0:1] o;
reg e;

always @ (i) begin
if (i=4'b0001) e=0;
else if (i=4'b0010) e=1;
else if (i=4'b0100) e=2;
else if (i=4'b1000) e=3;
else e=2'bxx
end

endmodule

Interconnecting Modules:
To maintain large designs modularity plays a important role. Verilog supports higher modules which contain sub-modules interconnected to each other. Lets consider a example of a ALU which does the basic functionalities of addition, subtraction and multiplication on the two input 32 bit values (in case of multiplication lets assume input to be 16 bits) and outputs the requested functionality.
The table for functionality may look like (assume F0 and F1 to be selectors and A and B be the input)

(F0,F1,Func)(0,0,A+B)(0,1,A-B)(1,1,A*B)

The below is a example of the ALU with the test setup. The test setup consists of initializing the registers with the required input and modifying the input after delays.

// Individual Components
module mux32three(i1,i2,i3,sel,out); // 32 bit 3 to 1 mux
input [31:0] i1,i2,i3;
input [1:0] sel;
output [31:0] out;
reg [31:0] out;

always @ (i1 or i2 or i3) begin
case (sel)
2'b00: out=i1;
2'b01: out=i2;
2'b10: out=i3;
default: out=32'bx;
endcase
end
endmodule

module add32(i1,i2,o); // 32 bit adder
input [31:0] i1,i2;
output [31:0] o;
assign o = i1+i2;
endmodule

module sub32(i1,i2,o); // 32 bit subtraction module
input [31:0] i1,i2;
output [31:0] o;
assign o = i1-i2;
endmodule

module mul16(i1,i2,o); // 16 bit multiplier
input [15:0] i1,i2;
output [31:0] o;
assign o = i1*i2;
endmodule

// ALU Module formed by inter-connecting modules
module alu(a,b,sel,alu_out); // ALU Module
input [31:0] a,b;
input [1:0] sel;
output [31:0] alu_out;

wire [31:0] add_out, sub_out, mul_out; // Intermediate wires to connect sub-modules

add32 adder(a,b,add_out);
sub32 subtract(a,b,sub_out);
mul16 multiply(a[15:0],b[15:0],mul_out);
mux32three out_mux(add_out,sub_out,mul_out,sel,alu_out);

endmodule

// Test Workspace which instantiates the alu and gives test input
module test_alu;
reg [31:0] a,b;
reg [1:0] func;

wire [31:0] our_alu_out;

initial // This sub-routine is called only once
begin
a = 32'd10;
b = 32'd10;
func = 2'd0;
#2 // Delay element (2 cycle delay)
func = 2'd1;
#2
func = 2'd2;
end

alu our_alu(a,b,func,our_alu_out);

endmodule

Modules Can be interconnected by specifying the ports as ordered or associate the port with the input/outputs.

alu our_alu(a,b,func,our_alu_out);// Can also be called as
alu our_alu(.a(a),.alu_out(our_alu_out),.b(b),.sel(func));
// in which case the order of inputs need not be maintained

Also the Verilog has primitive routines which need not be instantiated and must be ordered.
eg: and(in1,in2,in3,out)


Useful Boolean Functions:
  • Bitwise Operator: Operates on individual bits of a vector
    • ~a(NOT), a&b(AND), a|b(OR), a^b(XOR), a~^b(XNOR)
  • Logical Operator: Acts on the vector as a whole
    • !a(NOT), a&&b(AND), a||b(OR)
  • Reduction Operator: Acts on each bit of a single input
    • &a (AND), ~&a(NAND), |a(OR), ~|a(NOR), ^a(XOR)
    • &(4'b0110) = 0&1&1&0=1'b0
  • Comparison Operator:
    • ab,a<=b,a>=b - Relational Operator
    • a==b , a!=b - logical equality (whenever a or b contains x or z the result is unknown else return 0 or 1based on comparison)
    • a===b,a!==b - Case equality (does a bit by bit comparison even when x and z are present and return 1 or 0 based on comparison)
  • Note the difference between ! and ~

No comments: