Digital design
Verilog
What is Verilog
Hardware Description Language (HDL) Developed in 1984 Standard: IEEE 1364, Dec 1995
Abstraction levels in Verilog
Behavioral RTL Gate
Our focus
Transistor
module
Basic building block in Verilog module
- Created by declaration (cant be nested) - Used by instantiation
Interface is defined by ports Ports provide interface for by which a module can communicate with its environment May contain instances of other modules All modules run concurrently
module(Cont.)
module my_module(out1, .., inN);
in1 in2
my_module
out1
out2
output out1, .., outM; input in1, .., inN;
f
inN outM
.. // declarations .. // description of f (maybe .. // sequential)
endmodule
Everything you write in Verilog must be inside a module exception: compiler directives
module(Cont.)
Example: half adder
module half_adder(S, C, A, B); output S, C; input A, B;
A
B Half Adder
S
C
wire S, C, A, B;
assign S = A ^ B; assign C = A & B; endmodule
User identifiers
Must not be keywords Maximum of 1024 characters in identifier Formed from {[A-Z], [a-z], [0-9], _, $}, but cant begin with $ or [0-9] myidentifier m_y_identifier 3my_identifier XXXXXX $my_identifier XXXXXX _myidentifier$ Case sensitivity myid Myid Keywords are lower case
Statement/declaration termination
Terminate statement/declaration with semicolon ;
Comments
// The rest of the line is a comment /* Multiple line comment */
/* Nesting /* comments */ do not work
*/
Free format
Free format within statement except for within quotes - Strings enclosed in double quotes and must be on a single line
Verilog value set
0 represents low logic level or false condition 1 represents high logic level or true condition x represents unknown logic level
represents high impedance logic level
Numbers in Verilog
<size><radix> <value>
No of bits Binary b or B Octal o or O Decimal d or D Hexadecimal h or H
Consecutive chars 0-f, x, z
- 8h ax = 1010xxxx - 12o 3zx7 = 011zzzxxx111
Numbers in Verilog(Cont.)
You can insert _ for readability - 12b 000_111_010_100 Represent the same number - 12b 000111010100 - 12o 07_24 Bit extension - MS bit = 0, x or z extend this 4b x1 = 4b xx_x1 - MS bit = 1 zero extension 4b 1x = 4b 00_1x
Numbers in Verilog(Cont.)
If size is ommitted it - is inferred from the value or - takes the simulation specific number of bits or - takes the machine specific number of bits
If radix is ommitted too .. decimal is assumed
- 15 = <size>d 15
Nets
Doesnt store value, just a connection Can be thought as hardware wires driven by logic Equal z when unconnected Various types of nets - wire - wand (wired-AND) - wor (wired-OR) - tri (tri-state) In following examples: Y is evaluated, automatically, every time A or B changes input, output and inout ports are default wire
Nets(Cont.)
A B Y
wire Y; // declaration assign Y = A & B;
A Y
wand Y; // declaration assign Y = A; assign Y = B;
B
wor Y; // declaration assign Y = A; assign Y = B;
dr A Y
tri Y; // declaration assign Y = (dr) ? A : z;
Registers
Variables that store values Event-driven modeling Do not represent real hardware but real hardware can be implemented with registers Only one type: reg reg A, C; // declaration // assignments are always done inside a procedure A = 1; C = A; // C gets the logical value 1 A = 0; // C is still 1 C = 0; // C is now 0
Vectors
Represent buses wire [3:0] busA; reg [1:4] busB; reg [1:0] busC; Left number is MS bit Slice management
busC = busA[2:1];
busC[1] = busA[2]; busC[0] = busA[1];
busB[1] = busA[3]; busB[2] = busA[2]; busB[3] = busA[1]; busB[4] = busA[0];
Vector assignment (by position)
busB = busA;
integer and real data types
Declaration
integer i, k; real r;
Use as registers (inside procedures)
i = 1; // assignments occur inside procedure r = 2.9; k = r; // k is rounded to 3
integers are not initialized reals are initialized to 0.0 integers are usually 32 bits
Arrays
Syntax reg var [-15: 16]; // 32 1-bit regs reg [7:0] mem [ 0:1023]; // 1024 8-bit regs Accessing array elements - Entire element: mem[10] = 8b 10101010; - Element subfield (needs temporary storage): reg [7:0] temp; .. Temp = mem[10]; var[6] = temp[2];
Arrays(Cont.)
Limitations:
Cannot access array subfield or entire array at once
var[2:9] = ???; // WRONG!! var = ???; // WRONG!!
No multi-dimentional arrays
reg var[1:10] [1:100]; // WRONG!! Arrays dont work for the Real data type
real r[1:10]; // WRONG !!
time data type
Special data type for simulation time measuring
Declaration
time my_time; Use inside procedure
my_time = $time; // get current sim time
Simulation runs at simulation time, not real time
Strings
Implemented with regs: reg [8*13:1] string_val; // can hold up to 13 chars .. string_val = Hello Verilog ; string_val = hello; // MS Bytes are filled with 0 string_val = I am overflowed; // I is truncated
Escaped chars:
- \n - \t - %% - \\ - \ newline tab % \
Port assignments
module
input
reg or net
net
module
output
reg or net
net
module
inout
net
net
Operators
Logical Operators Bit-wise Operators Unary/Reduction Operators Shift Operators Concatenations Operator Relational Operators Equality Operators Conditional Operators Arithmetic Operators && , || , ! & , | , ~ , ^ , ~^ , ^~ & , | , ^ , ~& , ~| , ~^ , ^~ >> , << {} > , < , >= , <= == , != , === , !== ?: +, -,*,/,%
Operators(Cont.)
Logical Operators
&& logical AND || logical OR ! logical NOT Operands evaluated to ONE bit value: 0, 1 or x Result is ONE bit value: 0, 1 or x A = 6; A && B 1 && 0 0 B = 0; A || !B 1 || 1 1 C = x; C || B x || 0 x
but C&&B=0
Operators(Cont.)
Bitwise operators
& | ~ ^ ~^ or ^~ bitwise AND bitwise OR bitwise NOT bitwise XOR bitwise XNOR
Operation on bit by bit basis
Operators(Cont.)
Unary/Reduction Operators
& | ^ ~& ~| ~^ or ^~ AND OR XOR NAND NOR XNOR
One multi-bit operand One single-bit result
a = 4b1001; c = |a; // c = 1|0|0|1 = 1
Operators(Cont.)
>> shift right << shift left
Shift operators
Result is same size as first operand, always zero filled
reg [3:0] A; 1 1 0 reg [3:0] A; 1 1 0
1 1
A << 2 A >> 2
0 0
1 0
0 1
0 1
Operators(Cont.)
Concatenation operator
{op1, op2, ..} concatenates op1, op2, .. to single number Operands must be sized reg a; reg [2:0] b, c; a = 1b 1; b = 3b 010; c = 3b 101; catx = {a, b, c}; // catx = 1_010_101 caty = {b, 2b11, a}; // caty = 010_11_1 catz = {b, 1}; // WRONG !! Replication catr = {4{a}, b, 2{c}}; // catr = 1111_010_101101
Operators(Cont.)
Relational operators
> < >= <= greater than less than greater or equal than less or equal than
Result is one bit value: 0, 1 or x 1>0 b1x1 <= 0 10 < z 1 x x
Operators(Cont.)
Equality operators
== != === !== logical equality logical inequality case equality case inequality
Return 0, 1 or x
Return 0 or 1
- 4b 1z0x == 4b 1z0x x - 4b 1z0x != 4b 1z0x x - 4b 1z0x === 4b 1z0x 1 - 4b 1z0x !== 4b 1z0x 0
Operators(Cont.)
Conditional operator
cond_expr ? true_expr : false_expr;
Like a 2-to-1 mux
A B
1 0 sel
Y = (sel)? A : B;
Operators(Cont.)
Arithmetic operators
+, -, *, /, % If any operand is x the result is x Negative registers: - regs can be assigned negative but are treated as unsigned reg [15:0] regA; .. regA = -4d12; // stored as 216-12 = 65524
regA/3
// evaluates to 21861
Operators(Cont.)
Arithmetic operators(Cont.)
Negative integers: - can be assigned negative values
- different treatment depending on base specification or not
reg [15:0] regA; integer intA; .. intA = - 12/3; // evaluates to -4 (no base spec)
intA = -d 12/3; // evaluates to 1431655761 (base spec)
Operators(Cont.)
Operator Precedence
Use parentheses to enforce your priority
Continuous assignements
Syntax:
assign #delay <id> = <expr>;
optional net type !! wire S, C, A, B; assign S = A ^ B; assign C = A & B; module half_adder(S, C, A, B); output S, C; input A, B;
Where to write them:
- inside a module - outside procedures
Properties:
- they all execute in parallel - are order independent - are continuously active
endmodule
A B Half Adder
S C
Instances
A module provides a template from which you can create actual objects. When a module is invoked, Verilog creates a unique object from the template. Each object has its own name, variables, parameters and I/O interface.
Instances(Cont.)
Example: full adder
module full_adder(sum, cout, in1, in2, cin); output sum, cout; input in1, in2, cin; wire sum, cout, in1, in2, cin; wire I1, I2, I3;
Module name
half_adder ha1(I1, I2, in1, in2); half_adder ha2(sum, I3, I1, cin); assign cout = I2 || I3; endmodule
Instance name
Instances(Cont.)
Port connections/associations
Connect/associate module port by order list Connect/associate module port by name (Recommended)
Gate level
Built-in gate primitives: - and, nand, nor, or, xor, xnor, buf, not, bufif0, bufif1, notif0, notif1 - No declaration; can only be instantiated - Instances of primitives may include delays buf b1(a, b); // Zero delay buf #3 b2(c, d); // Delay of 3 time unit buf #(4,5) b3(e, f); // Rise=4 time unit, fall=5 time unit buf #(3:4:5) b4(g, h); // Min-typical-max time unit Usage: nand (out, in1, in2); 2-input NAND without delay and #2 (out, in1, in2, in3); /* 3-input AND with 2 time unit delay */ //Usually better to provide instance name for debugging not #1 N1(out, in); /* NOT with 1 time unit delay and instance name */ xor X1(out, in1, in2); // 2-input XOR with instance name Write them inside module, outside procedures
Gate level(Cont.)
Example: 2-to-1 multiplexor
module mux2_1(out,in1,in2,sel); output out; input in1,in2,sel; wire out,in1,in2,sel;
in1 in2
n1
a1 a2
iv_sel
a1_o
o 1
out
wire iv_sel,a1_o,a2_o;
a2_o
sel
and not and or
a1(a1_o,in1,sel); n1(iv_sel,sel); a2(a2_o, in2, iv_sel); o1(out,a1_0,a2_o);
endmodule
Gate level(Cont.)
Example: half adder
module half_adder(S, C, A, B); output S, C; input A, B; wire S, C, A, B;
xor #2 (S, A, B); and #1 (C, A, B);
endmodule
User defined primitive(UDP)
User defined primitive(UDP) is building block defined by designer Way to define gates and sequential elements using a truth table It can have multiple inputs but only one output None of its inputs and output can be a vector
The first signal in the port list is always output. However, in the truth table the output signal value is at the end (after a colon). Input order in the truth table must follow the order given in the port list Combinational UDPs dont need initialization on the other side sequential UDPs need. Cannot be defined within modules.
Often simulate faster than using expressions, collections of primitive gates, etc. Most often used for specifying custom gate libraries
User defined primitive(Cont.)
primitive carry(out, a, b, c); output out; input a, b, c;
? represents any value of 1, 0, X b represents any value of 1 or 0 Value Z is not allowed in UDPs
Combinational UDPs output for unspecified combinations is always X
table 00? : 0; 0?0 : 0; ?00 : 0; 11? : 1; 1?1 : 1; ?11 : 1; endtable endprimitive
Truth table may include dont-care (?) entries
User defined primitive(Cont.)
Primitive dff ( q, clk, data); output q; input clk, data; r for rising edge, same as (01) f for falling edge, same as (10) p for positive edge, same as (01) , (0X) , (X1) n for negative edge, same as (10) , (1X) , (X0) * for any change, same as (??) Symbol indicates the next state is the same as the current state
reg q;
Initial q=0; table // clk data q new-q (01) 0 : ? : 0; (01) 1 : ? : 1; (0x) 1 : 1 : 1; (0x) 0 : 0 : 0; (?0) ? : ? : -; (??) ? : ? : -; endtable endprimitive
// Latch a 0 // Latch a 1 // Hold when d and q both 1 // Hold when d and q both 0 // Hold when clk falls // Hold when clk stable
Behavioral model Procedures
Procedures are sections of code that execute sequentially Procedural statements are statements inside a procedure e.g. another 2-to-1 mux implementation
begin if (sel == 0) Y = B; else Y = A; end
Execution Flow
Procedural assignments: Y must be reg
Behavioral model(Cont.) Procedures(Cont.)
Modules can contain any number of procedures Procedures execute in parallel (in respect to each other) and can be expressed in two types of blocks: - initial they execute only once - always they execute for ever (until simulation finishes) When a procedure has multiple statements, they must be
grouped using begin and end (for sequential statements)
or fork and join (for concurrent statements)
Behavioral model(Cont.) Procedures(Cont.)
Procedural assignment is used to assign value to variables A variable can be a signal defined by reg or a name defined by integer (another form of register-type signal) A variable cannot be a net type signal Difference between continuous assignment and procedural assignment - In continuous assignment changes the value of the target net whenever the right-hand-side operands change value - Procedural assignment changes the target register only when the assignment is executed according to the sequence of operations
Behavioral model(Cont.)
initial blocks
Start execution at simulation time zero and finish when their last statement executes
module nothing; initial $display(Im first); initial begin #50; $display(Really?); end endmodule
Will be displayed at sim time 0
Will be displayed at sim time 50
Behavioral model(Cont.)
always blocks
Start execution at simulation time zero and continue until simulation finishes Sensitivity list specifies events on which signals activating always blocks
module
always begin
always begin
end
always begin
end
end
Behavioral model(Cont.)
Delays in procedures
Inter-assignment delay: Delay specified in front of procedural assignment statements (e.g. #3 a = b&c;) delay the execution of the entire statement.
module delayTest; integer a, b, c; initial begin a = 2; b = 3; end initial #3 a = 4; initial #5 c = a + b;
Change a from 2 to 4 after 3 time unit
endmodule
Execution order: 1. delay 2. evaluation 3. assignment
Result: c=7
Intra-assignment delay: Delay specified right after = in procedural assignment statements (e.g. a = #3 b&c;) just delay the assignment operation. The evaluation of the right hand side expression is executed without delay.
module delayTest; integer a, b, c; initial begin a = 2; b = 3; end
Behavioral model(Cont.) Delays in procedures(Cont.)
Change a from 2 to 4 after 3 time unit
initial #3 a = 4;
initial c = #5 a + b; endmodule Execution order: 1. evaluation 2. delay 3. assignment
Result: c=5
Behavioral model(Cont.)
Fundamental problem
In a synchronous system, all flip-flops sample simultaneously at positive edge of clock In Verilog, always @(posedge clk) blocks run in some undefined sequence
Behavioral model(Cont.)
Blocking assignments v.s. Non-blocking assignments
Blocking assignments use = as assignment symbol Blocking assignments are performed sequentially
initial begin a = #1 1; // assignment at time 1 b = #3 0; // assignment at time 4 (3+1) c = #6 1; // assignment at time 10 (6+3+1) end
Non-blocking assignments use <= as assignment symbol Non-blocking assignments are performed concurrently
initial begin #1 a <= 1; // assignment at time 1 #3 b <= 0; // assignment at time 3 #6 c <= 1; // assignment at time 6 end
Behavioral model(Cont.) Blocking assignments v.s. Non-blocking assignments(Cont.)
This doesnt work as youd expect: This version does work:
reg d1, d2, d3, d4; always @(posedge clk) d2 <= d1; always @(posedge clk) d3 <= d2; always @(posedge clk) d4 <= d3;
Non-blocking rule: - RHS evaluated when assignment runs - LHS updated only after all events for the current instant have run
reg d1, d2, d3, d4;
always @(posedge clk) d2 = d1; always @(posedge clk) d3 = d2; always @(posedge clk) d4 = d3;
These run in some order, but you dont know which
Behavioral model(Cont.) Blocking assignments v.s. Non-blocking assignments(Cont.)
A sequence of blocking assignments communicate
1
A sequence of nonblocking assignments dont communicate a<= 1; b<= a; c <= b; //a = 1 //b = old value of a //c = old value of b
1 a
a = 1; b = a; c = b; // a = b = c = 1
c
Behavioral model(Cont.)
Events
An event occurs when a net or register changes it value. The event can be further specified as a rising edge (by posedge) or falling edge (by negedge) of a signal.
An event control statement always starts with symbol @
always @(signal1 or signal2 or ..) begin .. end always @(posedge clk) begin .. end always @(negedge clk) begin .. end
execution triggers every time any signal changes execution triggers every time clk changes from 0 to 1 execution triggers every time clk changes from 1 to 0
Behavioral model(Cont.) wait
wait statements allow designers to more specifically control when to execute statements. wait suspends activity in behavior until expression following wait is true wait (expr)
always begin wait (ctrl) #10 cnt = cnt + 1; #10 cnt2 = cnt2 + 2; end
execution loops every time ctrl = 1 (level sensitive timing control)
Behavioral model(Cont.)
Example: half adder
module half_adder(S, C, A, B); output S, C; input A, B; reg S,C; wire A,B; always @(A or B) begin S = A ^ B; C = A && B; end endmodule
Behavioral model(Cont.)
Example: D flip flop
module dff(Q, D, Clk); output Q; input D, Clk; reg Q; wire D, Clk; always @(posedge Clk) Q = D; endmodule
Timing
initial begin #5 c = 1; #5 b = 0; #5 d = c; end
Each assignment is blocked by its previous one
d
c b
5
Time
10
15
Timing(Cont.)
initial begin fork #5 c = 1; #5 b = 0; #5 d = c; join end
Assignments are not blocked here
d c b 0 5 Time 10 15
Procedural statements if
if (expr1) true_stmt1; else if (expr2) true_stmt2; .. else def_stmt;
Procedural statements(Cont.)
Example: 4-to-1 multiplexor
module mux4_1(out, in, sel); output out; input [3:0] in; input [1:0] sel; reg out; wire [3:0] in; wire [1:0] sel;
always @(in or sel) if (sel == 0) out = in[0]; else if (sel == 1) out = in[1]; else if (sel == 2) out = in[2]; else out = in[3]; endmodule
Procedural statements(Cont.)
case
case (expr)
item_1, .., item_n : stmt1; item_n+1, .., item_m : stmt2; .. default : def_stmt;
endcase
Procedural statements(Cont.)
Example: 4-to-1 multiplexor
module mux4_1(out, in, sel); output out; Input [3:0] in; Input [1:0] sel; reg out; wire [3:0] in; wire [1:0] sel; always @(in or sel) case (sel) 0: out = in[0]; 1: out = in[1]; 2: out = in[2]; 3: out = in[3]; endcase endmodule
Procedural statements(Cont.)
for
for (init_assignment; cond; step_assignment) stmt;
Procedural statements(Cont.) Example: Counter
module count(Y, start); output [3:0] Y; input start;
reg [3:0] Y; wire start; integer i; initial Y = 0; always @(posedge start) for (i = 0; i < 3; i = i + 1) #10 Y = Y + 1; endmodule
Procedural statements(Cont.)
while
module count(Y, start); output [3:0] Y; input start;
while (expr) stmt;
reg [3:0] Y; wire start; integer i; initial Y = 0; always @(posedge start) begin i = 0; while (i < 3) begin #10 Y = Y + 1; i = i + 1; end end endmodule
Usually used in Testbenches rather than for synthesized logic
Procedural statements(Cont.)
repeat
module count(Y, start); output [3:0] Y; input start; repeat (times) stmt; reg [3:0] Y; wire start;
Can be either an integer or a variable
initial Y = 0;
always @(posedge start) repeat (4) #10 Y = Y + 1;
Usually used in Testbenches rather than for synthesized logic
endmodule
Procedural statements(Cont.)
forever
module test; reg clk;
forever stmt;
Executes until Simulation finishes
initial begin clk = 0; forever #10 clk = ~clk; end
Tclk = 20 time units
Usually used in Testbenches rather than for synthesized logic
other_module1 o1(clk, ..); other_module2 o2(.., clk, ..); endmodule
Mixed model
module simple(Y, c, clk, res); output Y; input c, clk, res;
Code that contains various both gate, RTL, and behavioral styles
reg Y; wire c, clk, res; wire n; not( n, c); // gate-level always @(res or posedge clk) if (res) Y = 0; else Y = n; endmodule
Verilog subroutines
Subroutines lead to more readable code and make code-reuse easy Types of subroutines are: task and function Subroutines can be used only in behavioural blocks and contain behavioural statements Verilog offers a large set of system built-in tasks and functions
Verilog subroutines(Cont.)
tasks
Declared within a module Referenced only by a behavior within the module Parameters passed to task as input and inout and from task as output or inout Local variables can be declared Recursion is not supported
Verilog subroutines(Cont.) tasks(Cont.)
task Factorial; output [31:0] outfact; input [ 3:0] n; integer count;
Task invocation
reg [31:0] result; reg [ 3:0] data; Factorial (result,data);
begin outfact = 1; for(count = n; count > 0 ;count = count-1) outfact = outfact * count; end endtask
Verilog subroutines(Cont.)
functions
Implement combinational behavior May call other functions with no recursion Reference in an expression, e.g. RHS No output or inout allowed Implicit register having name and range of function
Verilog subroutines(Cont.) functions(Cont.)
function [31:0] Factorial; input [ 3:0] n; reg [ 3:0] count;
Function call
reg [31:0] result; reg [ 3:0] data; result = Factorial (data);
begin Factorial = 1; for(count = n; count > 0 ;count = count-1) Factorial = Factorial*count; end endtask
System tasks
Always written inside procedures
Built-in system tasks or functions begin with $ $display( .., arg2, arg3, ..); - It much likes printf() in C, displays formatted string in std output when encountered $monitor( .., arg2, arg3, ..); - It likes $display(), but displays string each time any of arg2, arg3, .. Changes $stop; - It suspends simulation when encountered $finish; - It finishes simulation when encountered $fopen(filename); - It returns file descriptor (integer); then, you can use $fdisplay( fd, .., arg2, arg3, ..); or $fmonitor( fd, .., arg2, arg3, ..); to write to file $fclose(fd); - closes file $random(seed); - It returns random integer; give her an integer as a seed
System tasks(Cont.)
$display and $monitor string format
Compiler directives
`include filename - inserts contents of file into current file - write it anywhere in code `define <text1> <text2> - text1 substitutes text2;
`timescale <time unit>/<precision> - e.g. `timescale 10ns/1ns later: #5 a = b;
- e.g. `define BUS reg [31:0] in declaration part: BUS data; 50ns
parameter
in[3:0] p_in[3:0]
out[1:0]
wu
clk
wd
Implelementation without parameters
module dff2bit(Q, D, clk); output [1:0] Q; input [1:0] D; input clk;
module dff4bit(Q, D, clk); output [3:0] Q; input [3:0] D; input clk;
reg [3:0] Q; wire [3:0] D; wire clk;
always @(posedge clk) Q = D;
reg [1:0] Q; wire [1:0] D; wire clk;
always @(posedge clk) Q = D;
endmodule
endmodule
Parameter(Cont.)
Implelementation without parameters
module top(out, in, clk); output [1:0] out; input [3:0] in; Input clk; wire [1:0] out; wire [3:0] in; wire clk; wire [3:0] p_in; wire wu, wd; assign wu = p_in[3] & p_in[2]; assign wd = p_in[1] & p_in[0]; dff4bit instA(p_in, in, clk); dff2bit instB(out, {wu, wd}, clk); /* notice the concatenation*/ endmodule // internal nets
Parameter(Cont.)
Implelementation with parameters
module dff(Q, D, clk); parameter WIDTH = 4; output [WIDTH-1:0] Q; input [WIDTH-1:0] D; input clk; reg [WIDTH-1:0] Q; wire [WIDTH-1:0] D; wire clk; always @(posedge clk) Q = D; endmodule
module top(out, in, clk); output [1:0] out; input [3:0] in; input clk;
wire [1:0] out; wire [3:0] in; wire clk; wire [3:0] p_in; wire wu, wd; assign wu = p_in[3] & p_in[2]; assign wd = p_in[1] & p_in[0]; dff instA(p_in, in, clk); /* WIDTH = 4, from declaration */
dff instB(out, {wu, wd}, clk); defparam instB.WIDTH = 2; /* We changed WIDTH for instB only */ endmodule
Testing your modules
Use Verilog module to produce testing environment including stimulus generation and/or response monitoring
Testbench
Stimulus
Design Under Test (DUT)
Response
Testing your modules(Cont.)
Testbench (Testbench.v) Design Under Test(DUT) (DUT.v)
Verilog Simulator
Verilog Parser
..
User Interface Simulation Engine
d c b
Test Mode Simulation Results Files
10
15
Testing your modules(Cont.)
Example for Testbench
module top_test; wire [1:0] t_out; reg [3:0] t_in; reg clk; top inst(t_out, t_in, clk); initial begin clk = 0; forever #10 clk = ~clk; end // Tops signals
// Tops instance // Generate clock
initial begin // Generate remaining inputs $monitor($time, " %b -> %b", t_in, t_out); #5 t_in = 4'b0101; #20 t_in = 4'b1110; #20 t_in[0] = 1; #300 $finish; end endmodule
Discrete-event simulation
Basic idea: only do work when something changes Centered around an event queue - Contains events labeled with the simulated time at which they are to be executed Scheduler - Execute every event for the current simulated time - Doing this changes system state and may schedule events in the future - When there are no events left at the current time instance, advance simulated time soonest event in the queue
Discrete-event simulation(Cont.)
Non-preemptive, no priorities A process must explicitly request a context switch Events at a particular time unordered Undefined execution order convenient for implementing event queue Context switching behavior convenient for simulation Two types of events - Evaluation events compute functions of inputs - Update events change outputs - Split necessary for delays, non-blocking assignments, etc.
a <= b + c;
Update event writes new value of a and schedules any evaluation events that are sensitive to a change on a Evaluation event reads values of b and c, adds them, and schedules an update event
Verilog simulation behavior
Concurrent processes ( initial , always ) run until they stop at one of the following - #(n) : Schedule process to resume n time units from now - wait(expression) : Schedule process resume when expression becomes true - @( senstivity list) : Schedule process resume when any variable in sensitivity list changes - @(posedge clk) : Schedule process resume when clk changes from 0 to 1 Infinite loops are possible and the simulator does not check for them
- This runs forever: no context switch allowed, so ready can never change
while (~ready) while (~ready)begin @(ready); count = count + 1; count = count + 1; #( clk_period ); end wait(ready);
Verilog simulation behavior(Cont.)
Race conditions - These can execute in either order: final value of a undefined
always @(posedge clk) a = 0; always @(posedge clk) a = 1;
thanks
digital design