ET5080E
Digital Design Using Verilog
HDL
Fall ‘21
Counters are Common
Shifters/Rotators
Parameters
Proper SM Coding
Random Misc Stuff
Administrative Matters
Readings
• Cummings paramdesign paper for hdlcon (posted on class website)
2
What Have We Learned?
1) Sequential elements (flops & latches) should be inferred
using non-blocking “<=“ assignments
2) Combinational logic should be inferred using blocking “=“
statements.
3) Blocking and non-Blocking statements should not be mixed
in the same always block.
4) Plus 5 other guidelines of good coding outlined in the
Cummings SNUG paper.
3
Engineers are paid to think,
Pharmacists are paid to follow rules
Counters are commonly needed blocks.
rst_n
Increment logic & mux are
combinational blocking
0 R
+1 cnt[7:0] Flop is seqential. non-blocking
comb 1
en clk
8-bit counter with reset & enable
4
Pill Counter
module pill_cnt(clk,rst_n,en,cnt); Nothing wrong with this code
input clk,rst_n; Just a little verbose. Use DF?
output [7:0] cnt; module pill_cnt(clk,rst_n,en,cnt);
reg [7:0] nxt_cnt,cnt; input clk,rst_n;
output [7:0] cnt;
always @(posedge clk, negedge rst_n)
if (!rst_n) reg [7:0] cnt;
cnt <= 8’h00; wire [7:0] nxt_cnt;
else
cnt <= nxt_cnt; always @(posedge clk, negedge rst_n)
if (!rst_n)
always @(en or cnt) cnt <= 8’h00;
if (en) else
nxt_cnt = cnt + 1; // combinational cnt <= nxt_cnt;
else
nxt_cnt = cnt; // so use blocking assign nxt_cnt (en) ? cnt+1 : cnt;
endmodule endmodule
5
I.Q. Counter (the rebel engineer)
module iq_cnt(clk,rst_n,en,cnt); What 2 rules are broken
here?
input clk,rst_n;
output [7:0] cnt; 1) Code infers
reg [7:0] cnt; combinational using a
non-blocking
always @(posedge clk or negedge rst_n) assignment
if (!rst_n)
cnt <= 8’h00; 2) We are using an if
else if (en) statement without a
cnt <= cnt + 1; // combinational pure else clause
endmodule
Is this OK?
6
Ring Counter
module ring_counter (count, enable, clock, reset);
output reg [7: 0] count;
input enable, reset, clock;
always @ (posedge clock or posedge reset)
if (reset == 1'b1) count <= 8'b0000_0001;
else if (enable == 1’b1) begin
case (count)
8’b0000_0001: count <= 8’b0000_0010;
8’b0000_0010: count <= 8’b0000_0100;
…
8’b1000_0000: count <= 8’b0000_0001;
default: count <= 8’bxxxx_xxxx;
endcase
end
endmodule
7
Ring Counter (a better way)
module ring_counter (count, enable, clock, reset_n);
output reg [7: 0] count;
input enable, reset, clock;
always @ (posedge clock or negedge reset_n)
if (!reset_n) count <= 8'b0000_0001;
else if (enable == 1'b1) count <= {count[6:0], count[7]};
endmodule
Use vector concatenation in this example to be more explicit
about desired behavior/implementation
• More concise
• Does not rely on synthesis tool to be smart and reduce your logic for
you.
8
Rotator
module rotator (Data_out, Data_in, load, clk, rst_n);
output reg [7: 0] Data_out;
input [7: 0] Data_in;
input load, clk, rst_n;
always @ (posedge clk or negedge rst_n)
if (!rst_n) Data_out <= 8'b0;
else if (load) Data_out <= Data_in;
else if (en) Data_out <= {Data_out[6: 0], Data_out[7]};
else Data_out <= Data_out
endmodule
• Think what this code implies…How will it synthesize?
• What would such a block be used for?
9
Shifter
always @ (posedge clk) begin
if (rst) Data_Out <= 0;
else case (select[1:0])
2’b00: Data_Out <= Data_Out; // Hold
2’b01: Data_Out <= {Data_Out[3], Data_Out[3:1]}; // ‚ by 2
2’b10: Data_Out <= {Data_Out[2:0], 1’b0}; // X by 2
2’b11: Data_Out <= Data_In; // Parallel Load
endcase
end
endmodule
• Think what this code implies…How will it synthesize?
• Is the reset synchronous or asynchronous? • There is no default to the case, is
this bad?
• Why was the MSB replicated on the ‚ by 2
10
Aside (a quick intro to parameters)
parameter like a local `define
• Defined locally to the module
• Can be overridden (passed a value in an instantiation)
• There is another method called defparam (don’t ever use
it) that can override them
localparam even more local than parameter
• Can’t be passed a value
• defparam does not modify
• Only available in Verilog 2001
11
Aside (a quick intro to parameters)
module adder(a,b,cin,sum,cout);
parameter WIDTH = 8; // default is 8
module alu(src1,src2,dst,cin,cout);
input [WIDTH-1:0] a,b; input [15:0] src1,src2;
input cin; …
output [WIDTH-1:0] sum; //////////////////////////////////
output cout; // Instantiate 16-bit adder //
////////////////////////////////
assign {cout,sum} = a + b + cin
adder #(16) add1(.a(src1),.b(src2),
endmodule .cin(cin),.cout(cout),
.sum(dst));
Instantiation of module can
override a parameter. …
endmodule
12
Aside (a quick intro to parameters)
Examples:
parameter Clk2q = 1.5, parameter IDLE = 2’b00;
Tsu = 1, parameter CONV = 2’b01;
Thd = 0; parameter ACCM = 2’b10;
module register2001 #(parameter SIZE=8)
(output reg [SIZE-1:0] q, input [SIZE-1:0] d,
• Read Cummings
input clk, rst_n);
paramdesign paper
always @(posedge clk, negedge rst_n) for hdlcon posted on
if (!rst_n) q <= 0; class website
else q <= d;
Verilog 2001 allows
definition in module header
endmodule
13
State Machines
State Machines:
• Next State and output
logic are combinational
blocks, which have
outputs dependent on the
current state.
• The current state is, of
course, stored by a FF.
• What is the best way to code State Machines?:
Best to separate combinational (blocking) from sequential (non-blocking)
Output logic and state transition logic can be coded in same always block
since they have the same inputs
Output logic and state transition logic are ideally suited for a case statement
14
State Diagrams
b=0 / Y=1
Inputs, a and b are 0,
a=0 / Y=1
unless specified otherwise
a=0 a=1 / Y=1
Outputs Y and Z are 0,
unless specified otherwise.
S0 a = 1/ S1
• Is this Mealy or Moore?
Z=1
rst = 1 b = 1/ Z = 1, Y=1
Lets code this
S2
15
always @ (state,a,b)
SM Coding case (state)
S0 : if (a) begin
module fsm(clk,rst,a,b,Y,Z); nxt_state = S1;
Z = 1; end
input clk,rst,a,b;
else
output Y,Z;
What problems do nxt_state = S0;
parameter S0 = 2’b00, we have here? S1 : begin
S1 = 2’b01, Y=1;
S2 = 2’b10; if (b) begin
nxt_state = S2;
reg [1:0] state,nxt_state;
Z=1; end
always @(posedge clk, posedge rst) else
if (rst) nxt_state = S1;
state <= S0; end
else S2 : nxt_state = S0;
state <= nxt_state; endcase
endmodule
16
SM Coding (2nd try of combinational)
always @ (state,a,b) S1 : begin
nxt_state = S0; // default to reset Y=1;
Z = 0; // default outputs if (b) begin
Y = 0; // to avoid latches nxt_state = S2;
Z=1; end
case (state) else nxt_state = S1;
S0 : if (a) begin end
nxt_state = S1; default : nxt_state = S0;
Z = 1; endcase
end endmodule
Defaulting of assignments and having a default
to the case is highly recommended!
17
SM Coding Guidlines
1) Keep state assignment in separate always block using non-
blocking “<=“ assignment
2) Code state transition logic and output logic together in a
always block using blocking assignments
3) Assign default values to all outputs, and the nxt_state
registers. This helps avoid unintended latches
4) Remember to have a default to the case statement.
• Default should be (if possible) a state that transitions to the same state
as reset would take the SM to.
• Avoids latches
• Makes design more robust to spurious electrical/cosmic events.
18
SM Interacting with SM
• A very common case is a state that needs to be held for a certain time.
The state machine in this case may interact with a timer (counter).
BUS
Cycle
IDLE ChrgPmp clr_tm
Enable
tm_eq_3ms/
wrt_done R tm_eq_3ms
+1 0
tm_eq_3ms/inc_tm comb 1
Multiple levels of interaction between SM’s inc_tm clk
19
EEPROM Write SM Example [1]
module eeprom_sm(clk,por_n,wrt_eep, //// implement 3ms timer below ////
wrt_data,eep_r_w_n,eep_cs_n, always @(posedge clk or
eep_bus,chrg_pmp_en,wrt_done); posedge clr_tm)
if (clr_tm) tm <= 14’h0000;
parameter IDLE = 2’b00, else if (inc_tm) tm <= tm+1;
BUS = 2’b01,
CHRG = 2’b10; //// @4MHZ cnt of 2EE0 => 3ms ////
assign tm_eq_3ms = (tm==14’h2EE0) ?
input clk,por_n,wrt_eep; 1’b1 : 1’b0;
input [11:0] wrt_data; // data to write
output eep_r_w_n,eep_cs_n; //// implement state register below ////
output chrg_pmp_en; // hold for 3ms always @(posedge clk or
inout [11:0] eep_bus; negedge por_n)
if (!rst_n) state <= IDLE;
reg [13:0] tm; // 3ms => 14-bit timer else state <= nxtState;
reg clr_tm,inc_tm,bus_wrt;
reg [1:0] state,nxtState;
20
EEPROM Write SM Example [2]
default : begin // is CHRG
//// state transition logic & ////
inc_tm = 1;
//// output logic ////
chrg_pmp_en=1;
always @(state,wrt_eep,tm_eq_3ms)
if (tm_eq_3ms)
begin
begin
nxtState = IDLE; // default all
wrt_done = 1;
bus_wrt = 0; // to avoid
nxtState = IDLE;
clr_tm = 0; // unintended
end
inc_tm = 0; // latches
else nxtState = CHRG;
chrg_pmp_en = 0;
end
case (state) endcase
IDLE : if (wrt_eep) end
nxtState = BUS;
BUS : begin assign eep_r_w_n = ~bus_wrt;
clr_tm = 1; assign eep_cs_n = ~bus_wrt;
bus_wrt = 1; assign eep_bus = (bus_wrt) ?
nxtState = CHRG; wrt_data : 12’bzzz;
end endmodule
21
USART (RS232) Example
LSB MSB
Start
Bit
(fixed period low) Payload goes out must have at least 1
(like 57600 baud) little endian period of high at end
(stop bit)
Assume we have a 4MHz clock running our digital system
We want to make a RS232 transmitter with a baud rate of 57,600
How many clock cycles do we hold each bit?
4MHz
Cycles 69 69 = 7’b1000101
57600 baud
22
USART Example
module usart_tx(clk,rst_n,strt_tx,tx_data,tx_done,TX);
input clk, rst_n, strt_tx; // start_tx comes from Master SM
input [7:0] tx_data; // data to transmit
output TX; // TX is the serial line
output tx_done; // tx_done asserted back to Master SM
.
.
.
endmodule;
1) Go over HW3 problem statement
23
Random Misc Topics
24
Mux With case
module Mux_4_32_(output [31:0] mux_out, input [31:0] data_3,
data_2, data_1, data_0, input [1:0] select, input enable);
reg [31: 0] mux_int;
// choose between the four inputs
always @ ( data_3 or data_2 or data_1 or data_0 or select)
case (select) (* synthesis parallel_case *)
2’b00: mux_int = data_0; Synthesis directive:
2’b01: mux_int = data_1; Lets the synthesis tool know
2’b10: mux_int = data_2; to use parallel (mux) scheme
2’b11: mux_int = data_3; when synthesizing instead of
endcase priority encoding. Called an
// add the enable functionality attribute in the IEEE spec
assign mux_out = enable ? mux_int : 32'bz;
endmodule
Case statement implies priority unless use parallel_case pragma
25
Encoder With case
module encoder (output reg [2:0] Code, input [7:0] Data);
always @ (Data)
// encode the data
case (Data)
8'b00000001 : Code = 3’d0;
8'b00000010 : Code = 3’d1;
8'b00000100 : Code = 3’d2;
8'b00001000 : Code = 3’d3;
8'b00010000 : Code = 3’d4;
8'b00100000 : Code = 3’d5;
8'b01000000 : Code = 3’d6;
8'b10000000 : Code = 3’d7;
default : Code = 3‘bxxx; // invalid, so don’t care
endcase
endmodule
26
Priority Encoder With casex
module priority_encoder (output reg [2:0] Code, output valid_data,
input [7:0] Data);
assign valid_data = |Data; // "reduction or" operator
always @ (Data)
// encode the data
casex (Data)
8'b1xxxxxxx : Code = 7;
8'b01xxxxxx : Code = 6;
8'b001xxxxx : Code = 5;
8'b0001xxxx : Code = 4;
8'b00001xxx : Code = 3;
8'b000001xx : Code = 2;
8'b0000001x : Code = 1;
8'b00000001 : Code = 0;
default : Code = 3'bxxx; // should be at least one 1, don’t care
endcase
endmodule
27
Seven Segment Display
module Seven_Seg_Display (Display, BCD, Blanking);
output reg [6: 0] Display; // abc_defg
input [3: 0] BCD;
input Blanking;
parameter BLANK = 7'b111_1111; // active low
parameter ZERO = 7'b000_0001; // h01
parameter ONE = 7'b100_1111; // h4f
parameter TWO = 7'b001_0010; // h12
parameter THREE = 7'b000_0110; // h06
parameter FOUR = 7'b100_1100; // h4c a
parameter FIVE = 7'b010_0100; // h24 f b
parameter SIX = 7'b010_0000; // h20 g
parameter SEVEN = 7'b000_1111; // h0f c
e
parameter EIGHT = 7'b000_0000; // h00
parameter NINE = 7'b000_0100; // h04 d
Defined constants – can make code more understandable!
28
Seven Segment Display [2]
always @ (BCD or Blanking)
if (Blanking) Display = BLANK;
else
case (BCD)
4’d0: Display = ZERO;
4’d1: Display = ONE; Using the
4’d2: Display = TWO; defined
4’d3: Display = THREE; constants!
4’d4: Display = FOUR;
4’d5: Display = FIVE;
4’d6: Display = SIX;
4’d7: Display = SEVEN;
4’d8: Display = EIGHT;
4’d9: Display = NINE;
default: Display = BLANK;
endcase
endmodule
29
Inter vs Intra Statement Delays
Inter-assignment delays block both evaluation and assignment
• #4 c = d;
• #8 e = f;
Intra-assignment delays block assignment but not evaluation
• c = #4 d;
• e = #8 f;
Blocking statement is still blocking though, so evaluation of
next statements RHS still does not occur until after the
assignment of the previous expression LHS.
• What?? How is it any different then? Your confusing me!
30
Inter vs Intra Statement Delays
(Blocking Statements)
module inter(); module intra();
integer a,b; integer a,b;
initial begin initial begin
Compare these two
a=3; a=3;
modules
#6 b = a + a; b = #6 a + a;
#4 a = b + a; a = #4 b + a;
end end
endmodule endmodule
Yaa, Like I said, they Time Event
Time Event
are the same!
0 a=3 0 a=3
6 b=6 Or are they? 6 b=6
10 a=9 10 a=9
31
Intra Statement Delays (Blocking
Statements)
module inter2(); module inter2();
integer a,b; integer a,b;
initial begin Time Event initial begin Time Eval Assign
a=3; a=3; Event Event
#6 b = a + a; 0 a=3 b = #6 a + a; 0 nxt_b= 6 a=3
#4 a = b + a; a = #4 b + a;
end 3 a=1 end 3 -- a=1
initial begin 6 b=2 initial begin 6 nxt_a=7 b=6
#3 a=1; #3 a=1;
#5 b=3; 8 b=3 #5 b=3; 8 -- b=3
end end
10 a=4 10 -- a=7
endmodule endmodule
32
Non-Blocking: Inter-Assignment Delay
Delays both the evaluation and the update
always @(posedge clk) begin
b <= a + a; Time Event
# 5 c <= b + a;
0 clk pos edge
# 2 d <= c + a;
end 0 b=6
5 c=9
initial begin
a = 3; b = 2; c = 1; 7 c=12
end
33
Non-Blocking: Inter-Assignment Delay
Delays both the evaluation and the update
always @(posedge clk) begin
b <= a + a; Time Event
c <= #5 b + a;
0 clk pos edge
d <= #2 c + a;
end 0 b=6
2 d=4
initial begin
a = 3; b = 2; c = 1; 5 c=5
end
This is more like modeling the Clk2Q delay of a Flop
(it captures on rising edge, but has a delay till output)
34
Intra-Assignment Review
module bnb;
reg a, b, c, d, e, f;
Note: In testbenches I
initial begin // blocking assignments
mainly find blocking inter-
a = #10 1; // a will be assigned 1 at time 10 assignment delays to be the
b = #2 0; // b will be assigned 0 at time 12 most useful. Delays really
c = #4 1; // c will be assigned 1 at time 16 not used outside of
end testbenches that much
during the design process.
initial begin // non-blocking assignments
d <= #10 1; // d will be assigned 1 at time 10
e <= #2 0; // e will be assigned 0 at time 2
f <= #4 1; // f will be assigned 1 at time 4
end
endmodule
35