Title: Computer Logic Design
1COMP211 Computer Logic Design
Lecture 6. Verilog HDL Sequential Logic
Prof. Taeweon Suh Computer Science
Education Korea University
2Sequential Logic
- Verilog provides certain syntax, which turns into
sequential circuits - In always statements, signals keep their old
value until an event in the sensitivity list
takes place - Statement inside always is executed only when the
event specified in the sensitivity list occurs - Note that always statement could generate
combinational logic, depending on your
description
always _at_ (sensitivity list) begin statement sta
tement end
3D Flip-Flop
- As studied, flip-flop samples input at the edge
of the clock - always _at_(posedge clk) samples the input at the
rising edge of the clock (clk) - always _at_(negedge clk) samples the input at the
falling edge of the clock (clk) - Any output assigned in an always statement must
be declared reg - Note that a variable declared reg is not
necessarily to be a registered output - Well see it later
- lt or can be used inside the always statement
- lt is called nonblocking assignment
- is called blocking assignment
- We are going to discuss about this later
- module flipflop(input clk,
- input 30 d,
- output reg 30 q)
- always _at_ (posedge clk)
- begin
- q lt d // pronounced q gets d
- end
- endmodule
4D Flip-Flop Simulation
testbench
timescale 1ns / 1ns module Dflipflop_tb()
reg clock reg 30 data wire
30 q parameter clk_period 10
Dflipflop dut(.clk(clock), .d(data), .q (q)
) always begin clock 1
forever (clk_period/2) clock clock
end initial begin data
4'h0 3 data 4'h3
(clk_period2) data 4'h5
(clk_period3) data 4'hA
(clk_period3) data 4'hC
(clk_period2) end endmodule
module Dflipflop(input clk,
input 30 d,
output reg 30 q) always _at_(posedge clk)
begin q lt d end endmodule
5D Flip-Flop with Sync and Async Reset
DFF with Synchronous Reset
DFF with Asynchronous Reset
- module ff_asyncR(input clk,
- input reset,
- input 30 d,
- output reg 30 q)
-
- // asynchronous reset
- // sensitivity list has both clk and reset
- always _at_ (posedge clk, posedge reset)
- begin
- if (reset) q lt 4'b0
- else q lt d
- end
- endmodule
module ff_syncR(input clk,
input reset,
input 30 d, output reg
30 q) // synchronous reset // sensitively
list has only clk always _at_(posedge clk)
begin if (reset) q lt 4'b0 else
q lt d end endmodule
6D Flip-Flop with Sync Reset
timescale 1ns / 1ns module ff_syncR_tb( )
reg clk reg reset reg
30 d wire 30 q parameter
clk_period 10 ff_syncR dut(clk, reset,
d, q) always begin clk 1 forever
(clk_period/2) clk clk end initial
begin reset 1 3 reset 1
(clk_period2) reset 0 (clk_period3) r
eset 1 (clk_period2) reset 0
(clk_period3) end initial begin d
4'h0 3 d 4'h3 (clk_period2) d
4'h5 (clk_period3) d 4'hA
(clk_period3) d 4'hC (clk_period2)
end endmodule
module ff_syncR(input clk,
input reset, input
30 d, output reg 30
q) // synchronous reset always _at_(posedge
clk) begin if (reset) q lt 4'b0
else q lt d end endmodule
7D Flip-Flop with Enable
timescale 1ns / 1ns module ff_en_tb() reg
clk reg reset reg en reg
30 d wire 30 q parameter
clk_period 10 ff_en dut(clk, reset, en,
d, q) always begin clk 1
forever (clk_period/2) clk clk
end initial begin reset 1
3 reset 1 (clk_period2)
reset 0 end initial begin
en 1 3 en 1
(clk_period5) en 0
(clk_period) en 1 end
initial begin d 4'h0 3
d 4'h3 (clk_period2) d
4'h5 (clk_period3) d 4'hA
(clk_period3) d 4'hC
(clk_period2) end endmodule
module ff_en(input clk,
input reset, input
en, input 30 d,
output reg 30 q) // asynchronous
reset and enable always _at_(posedge clk, posedge
reset) begin if (reset) q lt 4'b0 else
if (en) q lt d end endmodule
8D Latch
- As studied, a D-latch is
- transparent when the clock is high
- opaque when the clock is low (retaining its old
value) - Try to avoid using latches unless you have a good
reason to use them because latches may transfer
unwanted input to output like glitches - Instead, use flip-flops
- module latch(input clk,
- input 30 d,
- output reg 30 q)
- always _at_ (clk, d)
- begin
- if (clk) q lt d
- end
- endmodule
9D Latch Simulation
timescale 1ns / 1ns module latch_tb( ) reg
clk reg 30 d wire 30
q parameter clk_period 10 latch
latch_dut(clk, d, q) always begin
clk 1 forever (clk_period/2) clk
clk end initial begin d
4'h0 3 d 4'h3 (clk_period2)
d 4'h4 (clk_period/5) d
4'h5 (clk_period/5) d 4'h6
(clk_period/5) d 4'h7
(clk_period/5) d 4'h8
(clk_period/5) d 4'h9
(clk_period3) d 4'hA
(clk_period3) d 4'hC
(clk_period2) end endmodule
module latch(input clk,
input 30 d, output reg
30 q) always _at_(clk, d) begin if
(clk) q lt d end endmodule
10Useful Behavioral Statements
- Keywords that must be inside always statements
- if / else
- case, casez
- Again, variables assigned in an always statement
must be declared as reg even if theyre not
actually intended to be registers - In other words, all signals on the left side of
lt and inside always should be declared as reg
11Combinational Logic using always
- The always statement can also describe
combinational logic (not generating flip-flops)
- // combinational logic using an always statement
- module gates(input 30 a, b,
- output reg 30 y1, y2, y3, y4,
y5) - always _at_ () // need begin/end because
there is - begin // more than one statement
in always - y1 a b // AND
- y2 a b // OR
- y3 a b // XOR
- y4 (a b) // NAND
- y5 (a b) // NOR
- end
- endmodule
- This hardware could be described with assign
statements using fewer lines of code, so its
better to use assign statements in this case.
12Combinational Logic using case
module sevenseg(input 30 data, output reg
60 segments) always _at_() begin case
(data) // abc_defg
0 segments 7'b111_1110 1 segments
7'b011_0000 2 segments 7'b110_1101
3 segments 7'b111_1001 4 segments
7'b011_0011 5 segments 7'b101_1011
6 segments 7'b101_1111 7 segments
7'b111_0000 8 segments 7'b111_1111
9 segments 7'b111_1011 default
segments lt 7'b000_0000 // required endcase
end endmodule
- What kind of circuit would it generate?
13Combinational Logic using case
- In order for a case statement to imply
combinational logic, all possible input
combinations must be described by the HDL - Remember to use a default statement when
necessary, that is, when all the possible
combinations are not listed in the body of the
case statement - Otherwise, what kind of circuit do you think the
statement would generate?
14Combinational Logic using casez
- The casez statement is used to describe truth
tables with dont cares - dont cares are indicated with ? in the casez
statement
- module priority_casez(input 30 a,
- output reg 30 y)
- always _at_()
- begin
- casez(a)
- 4'b1??? y 4'b1000 // ? dont care
- 4'b01?? y 4'b0100
- 4'b001? y 4'b0010
- 4'b0001 y 4'b0001
- default y 4'b0000
- endcase
- end
- endmodule
15Priority Circuit Simulation
module priority_casez(input 30 a,
output reg 30 y) always
_at_() begin casez(a) 4'b1??? y
4'b1000 4'b01?? y 4'b0100
4'b001? y 4'b0010 4'b0001 y
4'b0001 default y 4'b0000 endcase
end endmodule
timescale 1ns / 1ns module priority_casez_tb()
reg 30 a wire 30 y parameter
clk_period 10 priority_casez dut(a, y)
initial begin a 4'b0110
(clk_period2) a 4'b1110
(clk_period2) a 4'b0101
(clk_period2) a 4'b0011
(clk_period2) a 4'b0001
(clk_period2) a 4'b0000
(clk_period2) end endmodule
16Parameterized Modules
- HDLs permit variable bit widths using
parameterized modules - So far, all of our modules have had fixed-width
inputs and outputs - Verilog allows a (parameter )statement to
define parameters before the inputs and outputs
module mux2 (parameter width 8) // name and
default value (input width-10 d0, d1,
input s, output width-10 y)
assign y s ? d1 d0 endmodule
Instance with 8-bit bus width (uses default)
mux2 mux1(d0, d1, s, out) Instance with 12-bit
bus width mux2 (12) lowmux(d0, d1, s, out)
17Blocking and Nonblocking Statements
- In the always statement,
- indicates blocking statement
- lt indicates nonblocking statement
- Blocking statements are evaluated in the order in
which they appear in the code - Like one would expect in a standard programming
language such as C language - Nonblocking statements are evaluated concurrently
- All of the statements are evaluated concurrently
before any of the signals on the left hand sides
are updated
18Blocking vs Nonblocking Example
- What kinds of circuit would be generated?
module sync_nonblocking (input
clk, input d,
output reg q) reg n1 always _at_(posedge
clk) begin n1 lt d // nonblocking
q lt n1 // nonblocking end endmodule
module sync_blocking (input clk,
input d, output reg q)
reg n1 always _at_(posedge clk) begin
n1 d // blocking q n1 // blocking
end endmodule
19Blocking vs Nonblocking Example
Cout AB (A B)Cin
G PCin
20Full Adder with Blocking Statements
module fulladder(input a, b, cin,
output reg s, cout) reg p,
g always _at_() begin p a b
// blocking g a b // blocking
s p cin // blocking cout g
(p cin) // blocking end endmodule
- Like a high-level language, the blocking
statements are evaluated in the order they appear
in the body of the module - Suppose that all the inputs and internal nodes
are initially 0 - At some time later, a changes to 1
- p ? 1 0 1
- g ? 1 0 0
- s ? 1 0 1
- cout ? 0 1 0 0
21Full Adder with Nonblocking Statements
module fulladder(input a, b, cin,
output reg s, cout) reg
p, g always _at_() begin p lt a b
// nonblocking g lt a b //
nonblocking s lt p cin //
nonblocking cout lt g (p cin) //
nonblocking end endmodule
- Nonblocking statements are evaluated concurrently
- Suppose that all the inputs and internal nodes
are initially 0 - At some time later, a changes to 1
- p ? 1 0 1, g ? 1 0 0, s ? 0
0 0, cout ? 0 0 0 0 - p ? 1 0 1, g ? 1 0 0, s ? 1
0 1, cout ? 0 1 0 0
- It makes simulation slow though it synthesizes to
the same hardware - Also kind of hard to figure out what the circuit
is doing This kinds of coding should be avoided
22Blocking and Nonblocking Recap
- Some statements implies (generates) completely
different logic as shown in the flip-flop case - Some statements implies (generates) the same
logic no matter which statement you use as we
have seen in the full-adder case - But, it affects the simulation time
- So, choose wisely which statement you have to use
23Rules for Signal Assignment
- Use always _at_(posedge clk) and nonblocking
assignments to model synchronous sequential logic - always _at_(posedge clk)
- q lt d // nonblocking statement
- Use continuous assignment statements to model
simple combinational logic - assign y a b
- Use always _at_() and blocking assignments to model
more complicated combinational logic where the
always statement is helpful - Do not make assignments to the same signal in
more than one always statement or continuous
assignment statement
24FSM Revisit
- Synchronous sequential circuit can be drawn like
below - These are called FSMs
- Super-important in digital circuit design and
very straightforward to understand - FSM is composed of
- State register
- Combinational logic that
- Computes the next state based on current state
and input - Computes the outputs based on current state (and
input)
25Traffic Light Revisit
- A simplified traffic light controller
- Traffic sensors TA, TB
- Each sensor becomes TRUE if students are present
- Each sensor becomes FALSE if the street is empty
- Lights LA, LB
- Each light receives digital inputs specifying
whether it should be green, yellow, or red
26Moore FSM in Verilog
// next state logic always _at_ () case
(state) S0 if (TA) nextstate lt S1
else nextstate lt S0 S1
nextstate lt S2 S2 if (TB) nextstate
lt S3 else nextstate lt S2
S3 nextstate lt S0
default nextstate lt S0 endcase //
output logic always _at_ () if (state S0)
begin LA green LB
red end else if (state S1)
begin LA yellow LB
red end else if (state S2)
begin LA red LB green
end else begin LA red
LB yellow end endmodule
module moore_traffic_light (input
clk, reset, TA, TB, output reg 10 LA,
LB) reg 10 state, nextstate
parameter S0 2b00 parameter S1 2b01
parameter S2 2b10 parameter S3 2b11
parameter green 2b00 parameter yellow
2b01 parameter red 2b10 // state
register always _at_ (posedge clk, posedge
reset) if (reset) state lt S0 else
state lt nextstate
27Testbench for Traffic Light FSM
timescale 1ns/1ps module moore_traffic_light_tb
() reg clk, reset reg TA, TB wire
10 LA, LB parameter clk_period 10
moore_traffic_light dut(.clk (clk),
.reset (reset),
.TA (TA),
.TB (TB), .LA
(LA), .LB (LB)
) initial begin reset 1 13
reset 0 end
always begin clk 1
forever (clk_period/2) clk clk end
initial begin TA 0 TB 0 3
TA 0 TB 0 (clk_period) TA
1 TB 1 (clk_period5) TA 0 TB
1 (clk_period4) TA 0 TB 0
(clk_period4) TA 1 TB 0
end endmodule
28Simulation with ModelSim
- Useful tips in using ModelSim
- To display state information as described in
Verilog code - Format radix define name .
- Example radix define mystate 2b00 S0 ,
2b01 S1 , 2b10 S2 , 2b11 S3 - radix define mylight 2'b00
"green , 2'b01 "yellow , 2'b10 "red" - Save the display information for the use in the
future - File-gtSave Format, Then click on OK
- By default, it will save the waveform format to
wave.do
29Snail FSM Revisit
- There is a snail
- The snail crawls down a paper tape with 1s and
0s on it - The snail smiles whenever the last four digits it
has crawled over are 1101
30Moore FSM in Verilog
// Next State Logic always _at_() begin case
(state) S0 if (bnum) delay nextstate lt
S1 else delay nextstate lt S0
S1 if (bnum) delay nextstate lt S2
else delay nextstate lt S0 S2 if
(bnum) delay nextstate lt S2 else
delay nextstate lt S3 S3 if (bnum) delay
nextstate lt S4 else delay
nextstate lt S0 S4 if (bnum) delay
nextstate lt S2 else delay
nextstate lt S0 default delay
nextstate lt S0 endcase end // Output
Logic always _at_() begin if (state
S4) smile lt 1'b1 else smile
lt 1'b0 end endmodule
module moore_snail(input clk, reset, bnum,
output reg smile) reg 20
state, nextstate parameter S0 3'b000
parameter S1 3'b001 parameter S2 3'b010
parameter S3 3'b011 parameter S4 3'b100
parameter delay 1 // state register
always _at_(posedge reset, posedge clk) begin
if (reset) delay state lt S0 else
delay state lt nextstate end
31Mealy FSM in Verilog
// Next State and Output Logic always
_at_() begin case (state) S0 begin
delay smile lt 1'b0 if (bnum) delay
nextstate lt S1 else delay
nextstate lt S0 end S1 begin
delay smile lt 1'b0 if (bnum) delay
nextstate lt S2 else delay
nextstate lt S0 end S2 begin
delay smile lt 1'b0 if (bnum) delay
nextstate lt S2 else delay
nextstate lt S3 end S3 begin
if (bnum) delay smile lt 1'b1 else
delay smile lt 1'b0 if (bnum) delay
nextstate lt S1 else delay
nextstate lt S0 end default begin
delay smile lt 1'b0 delay
nextstate lt S0 end endcase
end endmodule
Mealy FSM arcs indicate input/output
module mealy_snail(input clk, reset, bnum,
output reg smile) reg
10 state, nextstate parameter S0 2'b00
parameter S1 2'b01 parameter S2 2'b10
parameter S3 2'b11 parameter delay 1
// state register always _at_(posedge reset,
posedge clk) begin if (reset) delay
state lt S0 else delay state lt
nextstate end
32Testbench for Snail FSM
timescale 1ns/1ps module fsm_snail_tb( )
reg clk, reset, bnum wire smile_moore
wire smile_mealy parameter clk_period 10
moore_snail moore_snail_uut (clk,
reset, bnum, smile_moore) mealy_snail
mealy_snail_uut (clk, reset, bnum,
smile_mealy) initial begin reset
1 13 reset 0 end
always begin clk 1 forever
(clk_period/2) clk clk end
initial begin bnum 0 3
bnum 0 clk_period bnum 1
clk_period bnum 0 clk_period bnum
0 clk_period bnum 0 clk_period
bnum 1 clk_period bnum 1
clk_period bnum 0 clk_period bnum
1 clk_period // Smile bnum 1
clk_period bnum 0 clk_period bnum
1 clk_period // Smile bnum 0
end endmodule
33Simulation with ModelSim
- Use radices below for display purpose
- radix define moore_state 3'b000 "S0 , 3'b001
"S1 , 3'b010 "S2 , 3'b011 "S3 , 3'b100 "S4" - radix define mealy_state 2'b00 "S0 , 2'b01
"S1 , 2'b10 "S2 , 2'b11 "S3"
34Testbench and TestVector
- Testbench
- HDL code written to test another HDL module, the
device under test (dut) (also called the unit
under test (uut)) - Testbench contains statements to apply input to
the DUT and ideally to check the correct outputs
are produced - Testvectors
- Inputs to DUT and desired output patterns from
DUT - Types of testbenches
- Simple testbench
- Self-checking testbench
- Self-checking testbench with testvectors
35Simple Testbench Revisit
testbench
- timescale 1ns/1ps
- module testbench1()
- reg a, b, c
- wire y
- // instantiate device under test
- sillyfunction dut(a, b, c, y)
- // apply inputs one at a time
- initial begin
- a 0 b 0 c 0 10
- c 1 10
- b 1 c 0 10
- c 1 10
- a 1 b 0 c 0 10
- c 1 10
- b 1 c 0 10
- c 1 10
module sillyfunction (input a, b, c,
output y) assign y a b c
a b c a b c endmodule
testvectors
36Self-checking Testbench Revisit
- module testbench2()
- reg a, b, c
- wire y
- // instantiate device under test
- sillyfunction dut(a, b, c, y)
- // apply inputs one at a time
- // checking results
- initial begin
- a 0 b 0 c 0 10
- if (y ! 1) display("000 failed.")
- c 1 10
- if (y ! 0) display("001 failed.")
- b 1 c 0 10
- if (y ! 0) display("010 failed.")
- c 1 10
- if (y ! 0) display("011 failed.")
a 1 b 0 c 0 10 if (y ! 1)
display("100 failed.") c 1 10 if
(y ! 1) display("101 failed.") b 1 c
0 10 if (y ! 0) display("110
failed.") c 1 10 if (y ! 0)
display("111 failed.") end endmodule
testvectors
37Self-Checking Testbench with Testvectors
- Writing code for each test vector is tedious,
especially for modules that require a large
number of vectors - A better approach is to place the test vectors in
a separate file - Then, testbench reads the file, applies input to
DUT and compares the DUTs outputs with expected
outputs - Generate clock for assigning inputs, reading
outputs - Read testvectors file into array
- Assign inputs and expected outputs to signals
- Compare outputs to expected outputs and report
errors if there is discrepancy
38Testbench with Testvectors
- Testbench clock is used to assign inputs (on the
rising edge) and compare outputs with expected
outputs (on the falling edge) - The testbench clock may also be used as the clock
source for synchronous sequential circuits
39Testvector File Example
- example.tv contains vectors of abc_yexpected
- 000_1
- 001_0
- 010_0
- 011_0
- 100_1
- 101_1
- 110_0
- 111_0
module sillyfunction(input a, b, c,
output y) assign y a b c
a b c a b c endmodule
40Self-Checking Testbench with Testvectors
- Generate clock for assigning inputs, reading
outputs - Read testvectors file into array
- Assign inputs and expected outputs to signals
// at start of test, load vectors // and pulse
reset initial begin readmemb("example.tv"
, testvectors) vectornum 0 errors
0 reset 1 27 reset
0 end // Note readmemh reads testvector
files written in // hexadecimal // apply test
vectors on rising edge of clk always _at_(posedge
clk) begin 1 a, b, c, yexpected
testvectorsvectornum end
- module testbench3()
- reg clk, reset
- reg a, b, c, yexpected
- wire y
- reg 310 vectornum, errors
- reg 30 testvectors100000
- // array of testvectors
-
- // instantiate device under test
- sillyfunction dut(a, b, c, y)
-
- // generate clock
- always
- begin
- clk 1 5 clk 0 5
- end
41Self-Checking Testbench with Testvectors
4. Compare outputs to expected outputs and report
errors if there is discrepancy
- // check results on falling edge of clk
- always _at_(negedge clk)
- begin
- if (reset)
- begin // skip during reset
- if (y ! yexpected) begin
- display("Error inputs b, a, b,
c) - display(" outputs b (b expected),
y, yexpected) - errors errors 1
- end
-
- // increment array index and read next
testvector - vectornum vectornum 1
- if (testvectorsvectornum 4'bx) begin
- display("d tests completed with d
errors, vectornum, errors) - finish
- end
- end
42HDL Summary
- HDLs are extremely important tools for modern
digital designers - Once you have learned Verilog-HDL or VHDL, you
will be able to design digital systems much
faster than drawing schematics - Debug cycle is also often much faster because
modifications require code changes instead of
tedious schematic rewriting - However, the debug cycle can be much longer with
HDLs if you dont have a good idea of the
hardware your code implies
43HDL Summary
- The most important thing to remember when you are
writing HDL code is that you are describing real
hardware! (not writing a software program) - The most common beginners mistake is to write
HDL code without thinking about the hardware you
intend to produce - If you dont know what hardware your code is
implying, you are almost certain not to get what
you want - So, probably sketch a block diagram of your
system - Identify which portions are combinational logic,
sequential logic, FSMs and so on, so forth - Write HDL code for each portion and then merge
together
44 45N 2N Decoder Example
module decoder (parameter N 3)
(input N-10 a,
output reg 2N-10 y) always _at_()
begin y 0 ya 1 end endmodule