Buttons and Debouncing Finite State Machine Lab 6 Buttons and Debouncing Finite State Machine
Lab Preview: Buttons and Debouncing Mechanical switches “bounce” vibrations cause them to go to 1 and 0 a number of times called “chatter” hundreds of times! We want to do 2 things: “Debounce”: Any ideas? Synchronize with clock i.e., only need to look at it at the next +ve edge of clock Think about (for Lab): What does it mean to “press the button”? Think carefully!! What if button is held down for a long time?
Verilog design patterns for sequential logic
wire vs. logic a signal of type wire must be continuously assigned since it cannot have memory wire z; assign z = a&b | c&d; // combinational func wire zz = a&b | c&d; // shorter form
wire vs. logic logic can be intermittently updated holds its value between updates must specify the discrete events when updates occur Example 1: counter logic [3:0] z = 0; always_ff @(posedge clock) z <= z + 1; // sequential func Example 2: stimulus in tester logic [31:0] A = 0; initial begin #10 A = 1; // discrete time instants #10 A = 2; … end
wire vs. logic As a special case: “intermittent” includes “continuous” logic can also be assigned logic zz; assign zz = a&b | c&d; // zz becomes a wire update instants are implicitly defined whenever a or b or c or d changes value update zz since updates occur whenever inputs change, SystemVerilog infers a combinational circuit with no need for latches/flipflops
Always Block Example always_ff @ ( sensitivity list ) statement; Sensitivity list determines when statements are evaluated Could think of it as “statement is evaluated whenever one of values in sensitivity list changes”
Blocking vs. Non-blocking Assignment Blocking assignments: Equal sign indicates blocking statements occur in text order B = A; C = B; Result: new contents of B are in C, so all have contents of A Non-blocking assignments: RHS of all <= lines within a begin-end block are evaluated in parallel, then assigned to LHS signals in parallel B <= A; C <= B; Result: new B is the value of A, but new C is the old B!
This is Not Software! Don’t assign to same signal in more than one always_ff block The always_ff blocks are concurrent Doesn’t make sense to set a flipflop from two different inputs For sequential logic: Use only non-blocking assignments you usually don’t mean one-by-one execution anyway yields the design pattern that is recognized by the compiler each logic on the LHS becomes a flip-flop/register each RHS becomes the input D to the flipflop sensitivity list (posedge clock) determines the clock signal enables/resets are also inferred if described But for testers: Blocking assignments are more convenient!
SystemVerilog Syntax: Initialization Can initialize flipflops/registers at declaration logic onebit = 1’b 0; logic [3:0] fourbits = 4’b 1011; logic [23:0] cnt = 0; // widths default to 32 bits // and are padded // or truncated (keep LSBs) DO NOT initialize combinational logic! initial values of a combinational circuit are determined solely by the initial values of its inputs logic z = 1’b 0; // should NOT initialize! assign z = x & y; // a combinational func
SystemVerilog Syntax: Initialization Do not confuse initialization with shorter form of assignment wire A = B | C; // short form is equivalent to: wire A; // type declaration AND assign A = B | C; // continuous assignment But… logic A = B | C; // is initialization ONLY update behavior still needs to be described, e.g.: always_ff @(posedge clock) A <= D^E;
Finite State Machines (FSMs)
Finite State Machines “FSMs” How to design machines that go through a sequence of events “sequential machines” Basically: Close the feedback loop in this picture:
Synchronous Sequential Logic Flip-flops/registers contain the system’s state state changes only at clock edge so system is synchronized to the clock all flip-flops receive the same clock signal (important!) every cyclic path must contain a flip-flop
Finite State Machine (FSM) Consists of: State register that holds the current state updates it to the “next state” at clock edge Combinational logic (CL) that computes the next state using current state and inputs computes the outputs using current state (and maybe inputs)
More and Mealy FSMs Two types of finite state machines differ in the output logic: Moore FSM: outputs depend only on the current state Mealy FSM: outputs depend on the current state and the inputs can convert from one form to the other Mealy is more general, more expressive In Both: Next state is determined by current state and inputs
Moore and Mealy FSMs
Verilog coding: procedural style
Verilog procedural statements All variables/signals assigned in an always statement must be declared as logic Why? Because always allows intermittent updates to a signal So, the signal could turn out to be combinational or sequential… … depending on the actual description
Verilog procedural statements These statements are often convenient: if / else case, casez more convenient than “? : ” conditional expressions especially when deeply nested But: these must be used only inside always blocks some genius decided that! Result: designers often want to use if-else/case for describing combinational logic for convenience/readability … instead of being limited to just “? : ” expressions so SystemVerilog introduced a new construct: always_comb the compiler will try to check to see that the description is indeed a combinational function
Example: Comb. Logic using case module decto7seg(input wire [3:0] data, output logic [7:0] segments); // no flipflops actually always_comb // used -> combinational case (data) 0: segments <= 8’b 11111100; 1: segments <= 8’b 01100000; 2: segments <= 8’b 11011010; 3: segments <= 8’b 11110010; 4: segments <= 8’b 01100110; 5: segments <= 8’b 10110110; 6: segments <= 8’b 10111110; 7: segments <= 8’b 11100000; 8: segments <= 8’b 11111110; 9: segments <= 8’b 11110110; default: segments <= 8’b 0000001; // required!! endcase endmodule Note the “comb”: it means that the compiler will check to make sure that the output is combinational.
Example: Comb. Logic using case module decto7seg(input wire [3:0] data, output logic [7:0] segments); // no flipflops actually always_comb // used -> combinational case (data) 0: segments <= 8’b 11111100; 1: segments <= 8’b 01100000; 2: segments <= 8’b 11011010; 3: segments <= 8’b 11110010; 4: segments <= 8’b 01100110; 5: segments <= 8’b 10110110; 6: segments <= 8’b 10111110; 7: segments <= 8’b 11100000; 8: segments <= 8’b 11111110; 9: segments <= 8’b 11110110; default: segments <= 8’b 0000001; // required!! endcase endmodule Suppose we forget to include the default case. What have we described then? An incomplete case statement would imply that segments should hold its value if no cases match!
Beware the unintended latch! Very easy to unintentionally specify a latch/register in Verilog! how does it arise? you forgot to define output for some input combination in order for a case statement to imply combinational logic, all possible input combinations must be described one of the most common mistakes! one of the biggest sources of headache! you will do it a gazillion times this is yet another result of the hangover of software programming forgetting everything in hardware is parallel, and time is continuous
Cheat Sheet for comb. vs seq. logic Sequential logic: Use always_ff @(posedge clk) Use nonblocking assignments (<=) Do not make assignments to the same signal in more than one always_ff block! e.g.: always_ff @(posedge clk) q <= d; // nonblocking
Cheat Sheet for comb. vs seq. logic Combinational logic: Use continuous assignments (assign …) whenever readable assign y = a & b; OR Use always_comb All variables must be assigned in every situation! must have a default case in case statement must have a closing else in an if statement do not make assignments to the same signal in more than one always_comb or assign statement
FSM Example: Sequence recognizer
A Sequence Recognizer Circuit has input, X, and output, Z Recognizes sequence 1101 on X Specifically: if X has been 110 and next bit is 1, make Z high
How to Design States States remember past history Clearly must remember we have seen 110 when next 1 comes along Tell me one necessary state for this example…?
Beginning State Start state: let’s call it A if 1 appears on input, move to next state B output remains at 0 Input / Output
Second 1 New state, C To reach C, must have seen 11
Next a 0 If 110 has been received, go to D Next 1 will generate a 1 on output Z
What else? What happens to arrow on right? Must go to some state. Where?
What Sequence? Here we have to interpret the problem statement We have just seen 01 Is this beginning of new 1101? Or do we need to start over w/ another 1? Let us say that it is the beginning of a new run…
Cover every possibility Must cover every possibility out of every state For every state: X = 0 or 1 You fill in all the cases
Fill in
Full Answer
Verilog coding styles for FSMs
Sequence recognizer Let us describe this as a Mealy FSM in SystemVerilog
Let’s encode states using enum State encoding: convert symbolic state names to binary values e.g., states = A, B, C, D A=00, B=01, C=10, D=11 SystemVerilog provides enum construct similar to C/Java set of predefined constants aids readability (and type/range checking in Java) enum { A = 2’b 00, B = 2’b 01, C = 2’b 10, D = 2’b 11 } state, next_state; also possible to leave encoding to compiler enum { A, B, C, D } state, next_state;
FSM in SystemVerilog Step 1: State encoding module seq_rec ( input wire CLK, RESET, X, output logic Z); enum { A, B, C, D } state, next_state; // Leaving encoding to compiler
Step 2: Next State logic Next State logic should be combinational always_comb case (state) A: if (X == 1) next_state <= B; else next_state <= A; B: if(X) next_state <= C; else next_state <= A; C: if(X) next_state <= C; else next_state <= D; D: if(X) next_state <= B; else next_state <= A; default: next_state <= A; endcase The last 3 cases do same thing. Just sparse syntax.
Step 3: State Register Register with reset synchronous reset (Lab 3) reset occurs only at clock transition usually prefer synchronous reset always_ff @(posedge CLK) if (RESET == 1) state <= A; else state <= next_state; OR state <= RESET ? A : next_state; asynchronous reset reset occurs whenever RESET goes high always_ff @(posedge CLK, posedge RESET) use asynchronous reset only if you really need it!
Step 4: Output logic Output logic must be combinational always_comb case(state) A: Z <= 0; B: Z <= 0; C: Z <= 0; D: Z <= X ? 1 : 0; // OR: Z <= X default: Z <= 0; endcase
Most common template for Mealy FSM Use 3 always blocks 2 combinational logic one for next state one for outputs 1 state register easy to see everything clearly!
Final FSM in SystemVerilog module seq_rec ( input wire CLK, RESET, X, output logic Z); enum { A, B, C, D } state, next_state; always_comb // Process 1 case (state) A: if (X == 1) next_state <= B; else next_state <= A; B: if(X) next_state <= C; else next_state <= A; C: if(X) next_state <= C; else next_state <= D; D: if(X) next_state <= B; else next_state <= A; default: next_state <= A; endcase always_ff @(posedge CLK) // Process 2 if (RESET == 1) state <= A; else state <= next_state; always_comb // Process 3 case(state) A: Z <= 0; B: Z <= 0; C: Z <= 0; D: Z <= X ? 1 : 0; default: Z <= 0; endcase
Comment on Code Could shorten it somewhat Template helps synthesizer Don’t need three always_ clauses Although it’s clearer to have combinational code be separate Don’t need next_state, for example Can just combine next_state logic with state update Template helps synthesizer Check to see whether your state machines were recognized by compiler (see output log)
Verilog: specifying FSM using 2 blocks Let us divide FSM into two modules one stores and update state another produces outputs
FSM using two always blocks module seq_rec ( input wire CLK, RESET, X, output logic Z); enum { A, B, C, D } state, next_state; always_ff @(posedge CLK) // Process 1 begin if (RESET == 1) state <= A; else case (state) A: if (X == 1) state <= B; else state <= A; // loops can be skipped B: if(X) state <= C; else state <= A; C: if(X) state <= C; else state <= D; D: if(X) state <= B; else state <= A; default: state <= A; endcase // default not required // for sequential logic! end always_comb // Process 2 case(state) A: Z <= 0; B: Z <= 0; C: Z <= 0; D: Z <= X ? 1 : 0; default: Z <= 0; endcase
Incorrect: Putting all in one always Using one always block generally incorrect! (But may work for Moore FSMs) ends up with unintended registers for outputs! AVOID! always_ff @(posedge CLK) // a single process for entire FSM case (state) A: if(X) begin state <= B; Z <= 0; end; B: if(…) begin state <= C; Z <= 1; end; C: if(…) begin state <= …; Z <= …; end; D: if(…) begin state <= …; Z <= …; end; endcase
My Preference The one with 3 always blocks Follow my template Easy to visualize the state transitions For really simple state machines: 2 always blocks is okay too Never put everything into 1 always block! Follow my template lab6_fsm_template.sv (posted on the website)