Spring 2018 :: CSE 502
Introduction to
SystemVerilog
Nima Honarmand
(Slides adapted from Prof. Milder’s ESE-507 course)
Spring 2018 :: CSE 502
First Things First
• SystemVerilog is a superset of Verilog
– The SystemVeriog subset we use is 99% Verilog + a few
new constructs
– Familiarity with Verilog (or even VHDL) helps but is not
necessary
• SystemVerilog resources and tutorials on the course
“Assignments” web page
Spring 2018 :: CSE 502
Hardware Description Languages (HDL)
• HDLs are used for a variety of purposes in hardware design
– Functional simulation
– Timing simulation
– Hardware synthesis
– Testbench development
– …
• Many different features to accommodate all of these
– We focus on functional simulation
• With HDLs, you describe hardware in one of two styles (usually)
– Structural model (network of gates and transistors)
– Behavioral model (high-level statements such as assignments, if, while, …)
• We use behavioral modeling for the course project
– Much simpler than designing with gates
Spring 2018 :: CSE 502
HDLs vs. Programming Languages (1)
• Have syntactically similar constructs:
– Data types, variables, operators, assignments, if statements,
loops, …
• But very different mentality and semantic model
• Statements are evaluated in parallel (unless specified
otherwise)
– Statements model hardware
– Hardware is inherently parallel
Reset your mind! You are a HW developer now.
Stop thinking like a SW programmer!
Spring 2018 :: CSE 502
HDLs vs. Programming Languages (2)
• Software programs are organized as a set of
subroutines
– Subroutines call each other, passing arguments and
return values
– When in callee, caller’s execution is paused
• Hardware descriptions are organized as a hierarchy
of hardware modules
– A hierarchy of module instances connected to each
other using wires
– Modules are active at the same time
Spring 2018 :: CSE 502
Modules
• The basic building block in SystemVerilog
– Interfaces with outside using ports
– Ports are either input or output (for now) all ports declared here
module name
module mymodule(a, b, c, f);
output f;
input a, b, c;
declare which // Description goes here
ports are inputs, endmodule
which are outputs
// alternatively
module mymodule(input a, b, c, output f);
// Description goes here
endmodule
6
Spring 2018 :: CSE 502
Module Instantiation
name of module mymodule(a, b, c, f);
module to output f;
instantiate input a, b, c;
module_name inst_name(port_connections);
endmodule
name of connect the ports
instance
• You can instantiate your own modules or pre-defined gates
– Always inside another module
• Predefined: and, nand, or, nor, xor, xnor
– for these gates, port order is <output, input(s)>
• For your modules, port order is however you defined it
7
Spring 2018 :: CSE 502
Connecting Ports
• In module instantiation, can specify port connections
by name or by order
module mod1(input a, b, output f);
// ...
endmodule
// by order
module mod2(input c, d, output g);
mod1 i0(c, d, g);
endmodule Advice: Use
by-name
// by name connections
module mod3(input c, d, output g); (where possible)
mod1 i0(.f(g), .b(d), .a(c));
endmodule
8
Spring 2018 :: CSE 502
Review: Combinational vs. Sequential Logic
• In combinational logic, circuit outputs are pure
function of circuit inputs
– i.e., output values only determined by input values
– Examples: and, or, multiplexer, adder, etc.
• In sequential logic, there are “state” elements that
can “hold” their old values regardless of the input
changes
– Example: any circuit with a latch, flip-flop or any other
“memory” element in it
Spring 2018 :: CSE 502
Combinational Logic
Description
Spring 2018 :: CSE 502
Structural Description
• Example: multiplexor
– Output equals one of the inputs
– Depending on the value of “sel”
module mux(a, b, sel, f);
output f;
input a, b, sel; datatype for describing Boolean logic
logic c, d, not_sel;
not gate0(not_sel, sel);
and gate1(c, a, not_sel); Built-in gates:
and gate2(d, b, sel); port order is:
or gate3(f, c, d); <output, input(s)>
endmodule
Spring 2018 :: CSE 502
Behavioral: Continuous Assignment
• Specify logic behaviorally by writing an expression
to show how the signals are related to each other.
– assign statement
module mux2(a, b, sel, f);
output f;
input a, b, sel;
logic c, d;
d
assign c = a & (~sel);
assign d = b & sel;
assign f = c | d;
c
// or alternatively
assign f = sel ? b : a;
endmodule
12
Spring 2018 :: CSE 502
Behavioral: Procedural Block
• Can use always_comb procedural block to
describe combinational logic using a series of
sequential statements
• All always_comb module mymodule(a, b, c, f);
output f;
blocks are input a, b, c;
independent and
always_comb begin
parallel to each other // Combinational logic
// described
// in C-like syntax
end
endmodule
Spring 2018 :: CSE 502
Procedural Behavioral Mux Description
module mux3(a, b, sel, f);
output logic f; If we are going to drive f this way,
input a, b, sel; need to declare it as logic
always_comb begin
if (sel == 0) begin
f = a; Important: for behavior to be
end combinational, every output (f)
else begin must be assigned in all possible
f = b; control paths
end
end Why? Otherwise, would be a latch
endmodule and not combinational logic.
Spring 2018 :: CSE 502
Avoid Accidental Latch Description
module bad(a, b, f); • This is not
output logic f;
input a, b; combinational, because
for certain values of b, f
always_comb begin
if (b == 1) begin
must remember its
f = a; previous value.
end
end
endmodule
• This code describes a
latch. (If you want a
latch, you should define
it using
always_latch)
Spring 2018 :: CSE 502
Avoid Multiply-Assigned Values
module bad2(...); • Both of these
... blocks execute
always_comb begin
b = ... something ... concurrently
end
always_comb begin • So what is the
b = ... something else ...
end
value of b?
endmodule We don’t know!
Don’t do this!
Spring 2018 :: CSE 502
Multi-Bit Values
• Can define inputs, outputs, or logic with multiple bits
– Also called bit vectors
module mux4(a, b, sel, f);
output logic [3:0] f;
input [3:0] a, b;
input sel;
always_comb begin
if (sel == 0) begin
f = a;
end
else begin
f = b;
end
end
endmodule
Spring 2018 :: CSE 502
Multi-Bit Constants and Concatenation
• Can give constants with specified number bits
– In binary, decimal or hexadecimal
• Can concatenate with { and }
logic [3:0] a, b, c;
• Can
logic reverse
signed order
[3:0] d; (to index buffers left-to-right)
logic [7:0] e;
logic [1:0] f;
assign a = 4’b0010; // four bits, specified in binary
assign b = 4’hC; // four bits, specified in hex == 1100
assign c = 3; // == 0011
assign d = -2; // 2’s complement == 1110 as bits
assign e = {a, b}; // concatenate == 0010_1100
assign f = a[2 : 1]; // two bits from middle == 01
Spring 2018 :: CSE 502
Case Statements and “Don’t-Cares”
module newmod(out, in0, in1, in2);
input in0, in1, in2;
output logic out; output value is
undefined in this case
always_comb begin
case({in0, in1, in2})
3'b000: out = 1;
3'b001: out = 0; Last bit is a “don’t
3'b010: out = 0; care” -- this line will
3'b011: out = x; be active for 100 OR
3'b10x: out = 1; 101
default: out = 0;
endcase default gives “else”
end behavior. Here active
endmodule if 110 or 111
Spring 2018 :: CSE 502
Arithmetic Operators
• Standard arithmetic operators defined: + - * / %
• Many subtleties here, so be careful:
– four bit number + four bit number = five bit number
• Or just the lower four bits
– arbitrary division is difficult
Spring 2018 :: CSE 502
Addition and Subtraction (1)
• Be wary of overflow!
logic [3:0] d, e, f; logic [3:0] a, b;
logic [4:0] c;
assign f = d + e;
assign c = a + b;
4’b1000 + 4’b1000 = 4’b000 Five-bit output can prevent overflow:
In this case, overflows to zero 4’b1000 + 4’b1000 gives 5’b10000
Spring 2018 :: CSE 502
Addition and Subtraction (2)
• Use “signed” if you want values as 2’s complement
logic signed [3:0] g, h, i;
logic signed [4:0] j;
assign g = 4’b0001; // == 1
i == 4’b1010 == -6 assign h = 4’b0111; // == 7
j == 5’b11010 == -6 assign i = g – h;
assign j = g – h;
Spring 2018 :: CSE 502
Multiplication
• Multiply k bit number with m bit number
– How many bits does the result have? k+m
logic signed [3:0] a, b;
logic signed [7:0] c;
assign a = 4'b1110; // -2
assign b = 4'b0111; // 7
assign c = a*b; c = 8’b1111_0010 == -14
• If you use fewer bits in your code
– Gets least-significant bits of the product
logic signed [3:0] a, b, d;
assign a = 4'b1110; // -2
assign b = 4'b0111; // 7
assign d = a*b; d = 4’0010 == 2
Spring 2018 :: CSE 502
Design Example
• Let’s say we want to compute f = a + b*c
– b and c are 4 bits, a is 8 bits, and f is 9 bits
• Let’s a combinational circuit using always_comb
module MAF(f, a, b, c); module MAF(f, a, b, c);
input [7:0] a input [7:0] a
input [3:0] b, c; input [3:0] b, c;
output logic [9:0] f; output logic [9:0] f;
always_comb begin OR logic [7:0] temp;
f = a + b * c;
end always_comb begin
endmodule temp = b * c;
f = a + temp;
end
endmodule
Spring 2018 :: CSE 502
Design Example 2
• Let’s say we want to compute f = (a ? b + 1 : c+2) * d
– a is 1 bit; b, c and d are 4 bits
– How wide should f be to avoid any overflows?
• Let’s a combinational circuit using always_comb
Spring 2018 :: CSE 502
Sequential Logic
Description
Spring 2018 :: CSE 502
Sequential Design
• Everything so far was purely combinational
– Stateless
• What about sequential systems?
– flip-flops, registers, finite state machines
• New constructs
– always_ff @(posedge clk)
– non-blocking assignment <=
Spring 2018 :: CSE 502
Edge-Triggered Events
• Variant of always block called always_ff
– Indicates that block will be sequential logic (flip flops)
• Procedural block activated only on a signal’s edge
– @(posedge …) or @(negedge …)
always_ff @(posedge clk, negedge reset_n) begin
// This block will be evaluated
// anytime clk goes from 0 to 1
// or anytime reset_n goes from 1 to 0
end
Spring 2018 :: CSE 502
Flip Flops (1)
• q remembers what d was at the last clock edge
– One bit of memory
• Without reset:
module flipflop(d, q, clk);
input d, clk;
output logic q;
always_ff @(posedge clk) begin
q <= d;
end
endmodule
Spring 2018 :: CSE 502
Flip Flops (2)
• With asynchronous reset:
module flipflop_asyncr(d, q, clk, rst_n);
input d, clk, rst_n;
output logic q;
always_ff @(posedge clk, negedge rst_n) begin
if (rst_n == 0)
q <= 0;
else
q <= d;
end
endmodule
Spring 2018 :: CSE 502
Flip Flops (3)
• With synchronous reset:
module flipflop_syncr(d, q, clk, rst_n);
input d, clk, rst_n;
output logic q;
always_ff @(posedge clk) begin
if (rst_n == 0)
q <= 0;
else
q <= d;
end
endmodule
Spring 2018 :: CSE 502
Multi-Bit Flip Flop
module flipflop_asyncr(d, q, clk, rst_n);
input [15:0] d;
input clk, rst_n;
output logic [15:0] q;
always_ff @(posedge clk, negedge rst_n) begin
if (rst_n == 0)
q <= 0;
else
q <= d;
end
endmodule
Spring 2018 :: CSE 502
Interlude: Module Parameters
• Parameters allow modules to be easily changed
module my_flipflop(d, q, clk, rst_n);
parameter WIDTH=16;
input [WIDTH-1:0] d;
input clk, rst_n;
default value set to 16
output logic [WIDTH-1:0] q;
...
endmodule
• Instantiate and set parameter: uses default value
my_flipflop f0(d, q, clk, rst_n);
changes parameter to
my_flipflop #(12) f0(d, q, clk, rst_n);
12 for this instance
my_flipflop #(.WIDTH(12)) f0(d, q, clk, rst_n);
Spring 2018 :: CSE 502
Non-Blocking Assignment a <= b
• <= is the non-blocking assignment operator
– All left-hand side values take new values concurrently
always_ff @(posedge clk) begin c gets the old value of b, not
b <= a; value assigned just above
c <= b;
end
• This models synchronous logic!
Spring 2018 :: CSE 502
Non-Blocking vs. Blocking (1)
• Use non-blocking assignment “<= ” to describe
edge-triggered (synchronous) assignments
always_ff @(posedge clk) begin
b <= a;
c <= b;
end
• Use blocking assignment “= ” to describe
combinational assignment
always_comb begin
b = a;
c = b;
end
Spring 2018 :: CSE 502
Non-Blocking vs. Blocking (2)
• Blocking models flow of values in wires and through
gates in a combinational circuit
– Output of multiplier is input to
always_comb begin
adder (1) temp = b * c;
– That’s why with blocking, (2) f = a + temp;
(2) is evaluated after (1) end
• Non-blocking assignments model relation between
input and output of flip-flops
– All FFs clocked together → all outputs take new values
together
– That’s why (3) and (4) are always_ff @(posedge clk) begin
evaluated in parallel (3) b <= a;
(4) c <= b;
end
Spring 2018 :: CSE 502
Non-Blocking vs. Blocking (3)
• Do not mix blocking and non-blocking assignments
• Use only blocking assignments in always_comb
• Use only non-blocking assignments in always_ff
• And keep their differences in mind
Spring 2018 :: CSE 502
Design Example — Sequential
• Recall our previous example: f = a + b*c
– b and c are 4 bits, a is 8 bits, and f is 9 bits
– We built it as a combinational circuit
• Now, let’s add registers at its inputs and outputs
Spring 2018 :: CSE 502
Finite State Machines (1) reset
• State names 0
• Output values A/00
1
• Transition values
0
• Reset (initial) state D/10 B/00
0 1
1
1
0
C/11
Spring 2018 :: CSE 502
Finite State Machines (2)
• What does an FSM look like when implemented in HW?
• Combinational logic and registers (things we already
know how to do!)
Spring 2018 :: CSE 502
Full FSM Example (1)
reset
module fsm(clk, rst, x, y);
0
input clk, rst, x;
output logic [1:0] y;
enum { STATEA=2'b00, STATEB=2'b01, STATEC=2'b10, A/00
1
STATED=2'b11 } state, next_state;
0
// next state logic D/10 B/00
always_comb begin
case(state) 1
0 1
STATEA: next_state = x ? STATEB : STATEA; 1
0
STATEB: next_state = x ? STATEC : STATED; C/11
STATEC: next_state = x ? STATED : STATEA;
STATED: next_state = x ? STATEC : STATEB;
endcase
end
// ... continued on next slide
Spring 2018 :: CSE 502
Full FSM Example (2)
reset
// ... continued from previous slide
0
// register
always_ff @(posedge clk) begin
if (rst) A/00
1
state <= STATEA;
else
state <= next_state; 0
D/10 B/00
end
// Output logic 1
0 1
always_comb begin 1
case(state) 0
C/11
STATEA: y = 2'b00;
STATEB: y = 2'b00;
STATEC: y = 2'b11;
STATED: y = 2'b10;
endcase
end
endmodule
Spring 2018 :: CSE 502
Huffman Partitioning
• In my experience, for anything other than memories
(SRAM arrays), you should code according to Huffman
Partitioning of your module
input output
Combinational
Logic always_comb
blocks
next state present state
(n_state) (p_state)
always_ff
in out (usually, one is
Registers enough)
clk reset
Spring 2018 :: CSE 502
Arrays
module multidimarraytest();
logic [3:0] myarray [2:0];
assign myarray[0] = 4'b0010;
assign myarray[1][3:2] = 2'b01;
assign myarray[1][1] = 1'b1; display
assign myarray[1][0] = 1'b0; (SystemVerilog’s
assign myarray[2][3:0] = 4'hC; printf)
initial begin
$display("myarray == %b", myarray);
$display("myarray[2:0] == %b", myarray[2:0]);
$display("myarray[1:0] == %b", myarray[1:0];
$display("myarray[1] == %b", myarray[1]);
$display("myarray[1][2] == %b", myarray[1][2]);
$display("myarray[2][1:0] == %b", myarray[2][1:0]);
end
endmodule
Spring 2018 :: CSE 502
Memory (Combinational read)
module mymemory(clk, data_in, data_out,
r_addr, w_addr, wr_en);
parameter WIDTH=16, LOGSIZE=8;
localparam SIZE=2**LOGSIZE;
input [WIDTH-1:0] data_in;
output logic [WIDTH-1:0] data_out;
input clk, wr_en;
input [LOGSIZE-1:0] r_addr, w_addr;
Combinational read
logic [WIDTH-1:0] mem [SIZE-1:0];
assign data_out = mem[r_addr];
always_ff @(posedge clk) begin
if (wr_en)
mem[w_addr] <= data_in;
end
endmodule Synchronous write
Spring 2018 :: CSE 502
Memory (Synchronous read)
module mymemory2(clk, data_in, data_out,
r_addr, w_addr, wr_en);
parameter WIDTH=16, LOGSIZE=8;
localparam SIZE=2**LOGSIZE;
input [WIDTH-1:0] data_in;
output logic [WIDTH-1:0] data_out;
input clk, wr_en;
input [LOGSIZE-1:0] r_addr, w_addr;
logic [WIDTH-1:0] mem [SIZE-1:0];
Synchronous read
always_ff @(posedge clk) begin
data_out <= mem[r_addr]; What happens if we
try to read and write
if (wr_en) the same address?
mem[w_addr] <= data_in;
end
endmodule
Spring 2018 :: CSE 502
Assertions
• Assertions are test constructs
– Automatically validated as design is simulated
– Written for properties that must always be true
• Makes it easier to test designs
– Don’t have to manually check for these conditions
Spring 2018 :: CSE 502
Example: A Good Place for Assertions
• Imagine you have a FIFO queue
– When queue is full, it sets status_full to true
– When queue is empty, it sets status_empty to true
data_in data_out
wr_en FIFO status_full
rd_en status_empty
• When status_full is true, wr_en must be false
• When status_empty is true, rd_en must be false
Spring 2018 :: CSE 502
Assertions
• A procedural statement that checks an expression when
statement is executed
// general form
Use $error assertion_name: assert(expression) pass_code;
to print error, else fail_code;
or $fatal to
print and halt // example
always @(posedge clk) begin
simulation
assert((status_full == 0) || (wr_en == 0))
else $error("Tried to write to FIFO when full.");
end
• SV also has Concurrent Assertions that are continuously
monitored and can express temporal conditions
– Complex but very powerful
– See http://www.doulos.com/knowhow/sysverilog/tutorial/assertions/
for an introduction
Spring 2018 :: CSE 502
DOs and DON’Ts to Keep in Mind (1)
1) Always try to picture the hardware that corresponds to
your Verilog code (especially, always blocks)
– If you can’t, you’re probably doing something wrong
– Each hardware component is simple; the power is in their
connection and parallelism
2) Have a reset signal that is connected to all your flip-flops
– Do not make any assumptions about the initial state of your flip-
flops
– Instead, reset them explicitly
3) Avoid using loops to implement hardware functionality
– Okay to use them for display or assert statements
– But not for hardware functionality
Spring 2018 :: CSE 502
DOs and DON’Ts to Keep in Mind (2)
4) Do not mix blocking and non-blocking assignments
– Only use blocking assignments in always_comb
– Only use non-blocking assignments in always_ff
– And keep their differences in mind
5) Do not put any combinational logic in always_ff
– always_ff should only model flip flops
– Follow Huffman Partitioning rules
Spring 2018 :: CSE 502
DOs and DON’Ts to Keep in Mind (3)
6) Big modules and always blocks are sign of bad
design
– Just like big functions
– Keep each module simple to make it easy to test individually
7) Test, Test, Test
– Test each module independently before connecting it to
others
– If a module’s functionality is not independently-testable, it is
probably a bad design