"delay state" in verilog FSM - Page 1
Forum section: electronics / general

author: gus789
author_rank: Contributor
timestamp: August 14, 2014, 01:28:40 am
content: Noob question here - I am trying to implement a delay state in a FSM in verilog. The idea is for the delay state to work as an intermediate state between the other states and to return to the appropriate state after the delay elapses. The code seems to work correctly in simulation (using iverilog and gtkwave) but when it comes to the synthesis, the Xilinx ISE Webpack doesn't seem to like the nextNextState construct and generates warnings about latches.There must be a better way to implement this - so any suggestions are welcome!PS I've also tried writing the FSM entirely inside a sequential always block, but I don't seem to be able to get away from having to define a "next-Next-State". The other alternative I can see is to write separate delay states, but that would seem too convoluted.Code:`timescale 1ns/1psmodule ledfsm(clk, rst, LED_1, LED_2);input clk, rst;output LED_1, LED_2;reg [2:0] currState, nextState,nextNextState;reg LED_1, LED_2;reg [23:0] counter;`define SYMM // comment out for synthesis`ifdef SYMMlocalparam DLY_COUNT = 24'd10;`elselocalparam DLY_COUNT = 24'd4000000;`endiflocalparamST_IDLE = 3'd0,ST_1ON = 3'd1,ST_2ON = 3'd2,ST_ALLON = 3'd3,ST_DELAY_1S = 3'd4,ST_NDEF_1 = 3'd5, // unused stateST_NDEF_2 = 3'd6, // unused stateST_NDEF_3 = 3'd7; // unused stateinitialbeginLED_1 = 1'b0;LED_2 = 1'b0;currState = ST_IDLE;counter = 3'd0;nextState = ST_IDLE;nextNextState = ST_IDLE;endalways @(posedge clk or posedge rst)beginif (rst)begincounter <= 24'd0;endelse if (currState == ST_DELAY_1S)begincounter <= counter + 24'd1;endelsebegincounter <= 24'd0;endendalways @(posedge clk or posedge rst)beginif (rst)currState <= ST_IDLE;elsecurrState <= nextState;endalways @(*)beginnextState = currState;case (currState)ST_IDLE:// all LED's are offbeginLED_1 = 1'b0;LED_2 = 1'b0;nextNextState = ST_1ON;nextState = ST_DELAY_1S;endST_1ON:// LED_1 is on, LED_2 is offbeginLED_1 = 1'b1;LED_2 = 1'b0;nextNextState = ST_2ON;nextState = ST_DELAY_1S;endST_2ON:// LED_1 is off, LED_2 is onbeginLED_1 = 1'b0;LED_2 = 1'b1;nextNextState = ST_ALLON;nextState = ST_DELAY_1S;endST_ALLON:// both LED's are onbeginLED_1 = 1'b1;LED_2 = 1'b1;nextNextState = ST_IDLE;nextState = ST_DELAY_1S;endST_DELAY_1S:// Delay of ~1sec. Note that the total delay is one clock cycle more because of the state transition.beginif (counter == DLY_COUNT)beginnextState = nextNextState;nextNextState = nextNextState;endelsebeginnextState = currState;nextNextState = nextNextState;endendST_NDEF_1:beginnextState = ST_IDLE;nextNextState = ST_IDLE;endST_NDEF_2:beginnextState = ST_IDLE;nextNextState = ST_IDLE;endST_NDEF_3:beginnextState = ST_IDLE;nextNextState = ST_IDLE;endendcaseendendmodule//Tester modulemodule tester(clk, rst, LED_1, LED_2);input LED_1, LED_2;output clk, rst;reg clk, rst;//Run the test onceinitialbeginclk=0;$dumpfile("dff.vcd");$dumpvars;rst=0;#3125 rst = 1;#3125 $finish;end//clockalwaysbegin#15.625 clk=!clk;endendmodule//Test benchmodule testbench;wire clk,rst,LED_1,LED_2;ledfsm ff1(clk, rst, LED_1, LED_2);tester tst1(clk, rst, LED_1, LED_2);endmodule

author: marshallh
author_rank: Unknown
timestamp: August 14, 2014, 02:31:50 am
content: 1. Change all your blocking assignemnts to non-blocking2. Insert a default case into each one (very important for stupid XST)

author: free_electron
author_rank: Super Contributor
timestamp: August 14, 2014, 03:14:07 am
content: here is how i make a 'callable delay in a fsmCode:`define rundelay currentstate <=calldelayreg currentstate;reg delay_value;reg nextstate;case (currentstate)blah : begindelay_value <= 50; // tell how many ticks needs waitingnextstate <= blabla; // tell where it needs to go when delay is done`rundelay; // invoke the delayend;blabla : begindelay_value <= 100;nextstate <= toedeloe;`rundelay;endtoedeloe : begin// do some other stuff hereendcalldelay: beginif (!delay_value) delay_value <= delay_value -1 // as long as delay_value is larger than zero ( bitwise or) decrement (decrementing counters synthesize smaller than incrementing counters as no comparator is needed, only a zero check which is a bitwise or.else currentstate <= returnstate; if it hits zero ; throw the target state into currentstate.enddefault : currentstate <=blah;

author: hamster_nz
author_rank: Super Contributor
timestamp: August 14, 2014, 03:43:21 am
content: 'Callable delay?' Who needs a callable delay?Which is better - a generic delay state, or a "delay before moving to new state" in a FSM?.ie.Code:if rising_edge(clk) thenif counter = 0 thenstate <= nextState;counter <= stateHoldTime;elsecounter <= counter-1;end if;end if'andCode:stateHoldTime <= 0;case state iswhen "STATE_A"nextState <= STATE_B;stateHoldTime <= 999;when "STATE_B"nextState <= STATE_C;...end case;Horses for courses I guess.Benefits:* No need for extra 'return state' registers* When you are simulating you know what state you are in.* It also helps with the FSM state encoding (e.g. can use one hot encoding, and then generate output signals from the state bits - can't do that with a generic delay state)....* Most likely runs quicker (based on 'feel' of the code, not actually running the code up and looking at timing).Pros:* Not very software-like.

author: gus789
author_rank: Contributor
timestamp: August 14, 2014, 03:44:32 am
content: Thanks marshallh and free_electron.I haven't tried the synthesis yet as I am away from the computer with ISE installed. I tried marshallh's suggestions in simulation and it looks correct only if all but the first assignment in the always @(*) are non-blocking - i.e. nextState = currState; is still blocking. I am trying to wrap my head around the idea of blocking vs non-blocking mixed in the always (*) construct, and puzzled as to how exactly this is working.I will try simulating free_electron's solution as I think that looks pretty clean.Thanks again!Code:module ledfsm(clk, rst, LED_1, LED_2);input clk, rst;output LED_1, LED_2;reg [2:0] currState, nextState,nextNextState;reg LED_1, LED_2;reg [23:0] counter;`define SYMM // comment out for synthesis`ifdef SYMMlocalparam DLY_COUNT = 24'd10;`elselocalparam DLY_COUNT = 24'd4000000;`endiflocalparamST_IDLE = 3'd0,ST_1ON = 3'd1,ST_2ON = 3'd2,ST_ALLON = 3'd3,ST_DELAY_1S = 3'd4,ST_NDEF_1 = 3'd5, // unused stateST_NDEF_2 = 3'd6, // unused stateST_NDEF_3 = 3'd7; // unused stateinitialbeginLED_1 = 1'b0;LED_2 = 1'b0;currState = ST_IDLE;counter = 24'd0;nextState = ST_IDLE;nextNextState = ST_IDLE;endalways @(posedge clk or posedge rst)beginif (rst)begincounter <= 24'd0;endelse if (currState == ST_DELAY_1S)begincounter <= counter + 24'd1;endelsebegincounter <= 24'd0;endendalways @(posedge clk or posedge rst)beginif (rst)currState <= ST_IDLE;elsecurrState <= nextState;endalways @(*)beginnextState = currState;case (currState)ST_IDLE:// all LED's are offbeginLED_1 <= 1'b0;LED_2 <= 1'b0;nextNextState <= ST_1ON;nextState <= ST_DELAY_1S;endST_1ON:// LED_1 is on, LED_2 is offbeginLED_1 <= 1'b1;LED_2 <= 1'b0;nextNextState = ST_2ON;nextState = ST_DELAY_1S;endST_2ON:// LED_1 is off, LED_2 is onbeginLED_1 <= 1'b0;LED_2 <= 1'b1;nextNextState <= ST_ALLON;nextState <= ST_DELAY_1S;endST_ALLON:// both LED's are onbeginLED_1 <= 1'b1;LED_2 <= 1'b1;nextNextState <= ST_IDLE;nextState <= ST_DELAY_1S;endST_DELAY_1S:// Delay of ~1sec. Note that the total delay is one clock cycle more because of the state transition.beginif (counter == DLY_COUNT)beginnextState <= nextNextState;nextNextState <= nextNextState;endelsebeginnextState <= currState;nextNextState <= nextNextState;endendST_NDEF_1:beginnextState <= ST_IDLE;nextNextState <= ST_IDLE;endST_NDEF_2:beginnextState <= ST_IDLE;nextNextState <= ST_IDLE;endST_NDEF_3:beginnextState <= ST_IDLE;nextNextState <= ST_IDLE;enddefault:beginnextState <= ST_IDLE;nextNextState <= ST_IDLE;endendcaseendendmodule

author: gus789
author_rank: Contributor
timestamp: August 14, 2014, 03:52:02 am
content: Thanks hamster_nz ... was typing the other post when yours came in. Will try this too!

author: bwat
author_rank: Frequent Contributor
timestamp: August 14, 2014, 05:51:19 am
content: Quote from: gus789 on August 14, 2014, 01:28:40 amInstead of a delay state, have delay states, i.e. instead of an explicit register holding the "return_to_state" information, have this information implicit in the state ID.With this in mind you can build analgorithmic state machinewhich will give you all you need to build a control unit and datatpath for this problem. Here are two examples of just such a design process used to build a Euclidean greatest common divisor machine:hardwired control unit example,microprogrammed control unit example.

author: Bassman59
author_rank: Super Contributor
timestamp: August 14, 2014, 06:19:22 pm
content: Quote from: gus789 on August 14, 2014, 03:44:32 amOh, dear God, another two-process state machine ...Please. Use one synchronous always block for your state machine. The two-process idiom must die.

author: c4757p
author_rank: Super Contributor
timestamp: August 14, 2014, 06:20:43 pm
content: Quote from: Bassman59 on August 14, 2014, 06:19:22 pmI rather like that idiom. Why do you hate it so much?

author: hamster_nz
author_rank: Super Contributor
timestamp: August 14, 2014, 09:26:56 pm
content: Quote from: Bassman59 on August 14, 2014, 06:19:22 pmDue to the async nature Mealy FSMs are more naturally aligned with using two processes, one with the sensitivity list is all the inputs, the other one that updates registers is sensitive to just the clock.Due to all outputs changing with the clock edge, pure Moore FSMs suit the single process implementation (the sensitivity list is just the clock). They are slower - as they can't respond to immediately a changing input, but have to wait for a clock tick, for example when handshaking a data transfer.What's your problem again?

author: free_electron
author_rank: Super Contributor
timestamp: August 14, 2014, 10:08:01 pm
content: Quote from: hamster_nz on August 14, 2014, 03:43:21 ammove to next state means you can't do if then else like jumps...Code:delay_time = 7;if ( sample == 1 ) next_state <= getbit else next_state <= abort_state;`delay;i like to keep my options openi can even create 'subroutines' using such constructs. simple store the 'return_vector' and call the subroutine.you can create a stack of return vectors. so now you can create nested calls.you can also do for-next loops`define call current_state <=` define return_from_loop loopreturn_state <=` define loop loop_routine <=some_state :beginloopcount <=7;`return_from_loop some_otherstate;`loop blort_routine;`call looper;some_other_state :blah ....// every subroutine here needs to set the 'current state to the content of exit vector.blort_routine :blah ....current_state <= exit_vector;looper :if (|loopcount ) begincurrent_state <= blort_routine;exit_vector <= looper;loopcount <= loopcount -1;endelse current_state <= return_from_loop;i use such constructions to make micro machines.for example an adaptable bit splittera stream of bits comes in. depending on the first two bits in the stream different operations need to be done.00 means , next packet is 5 bits long , 01 means next packet is 7 bits long , 10 means next packet is 12 bits long.after this first operand 4 bits need to be read that tell what needs to be done with these packets.this stream essentially packs data in arbitrary length blocks. data needs parsins as it streams in.so i have 'routine that can sample 2 bits and decode it . it loads the number of bits to be sampled and 'calls' a routine that now takes that required number of bits , shoves that in a dual port ram somewhere and then returns to another 'subroutine' reading four more bits and decide what needs to be done next. the handler then returns to the routine that reads 2 bits and decodes this again.i don't need a cpu , i don't need a stack. the routines have their own flip flops and the flow is defined by simp'y telling the called subroutine what it needs to call in turn.i have done I2C slave controllers like that.one subroutine detects a start , there is a subroutine that samples 8 bits. one subroutine compares adress and read write bit another one can send a byte and so on.the state handler dispatches the calls and passes the return _vector.

author: gus789
author_rank: Contributor
timestamp: August 14, 2014, 10:20:13 pm
content: Thanks all for the valuable input. As an update, I managed to get the code below, which follows the suggestion given by free_electron earlier, to compile successfully in ISE. Only warnings were about the unused bits of nextState being always zero. But I think I can live with those. Still puzzled as to why the previous "two process" FSM generates warnings about latches and clock skew though.Code:`timescale 1ns/1psmodule ledfsm(clk, rst, LED_1, LED_2);input clk, rst;output LED_1, LED_2;reg [2:0] currState, nextState;reg LED_1, LED_2;reg [24:0] delay_value;//`define SYMM // comment out for synthesis`ifdef SYMMlocalparam DLY_COUNT = 25'd10;`elselocalparam DLY_COUNT = 25'd32000000;`endiflocalparamST_IDLE = 3'd0,ST_1ON = 3'd1,ST_2ON = 3'd2,ST_ALLON = 3'd3,ST_DELAY_1S = 3'd4,ST_NDEF_1 = 3'd5, // unused stateST_NDEF_2 = 3'd6, // unused stateST_NDEF_3 = 3'd7; // unused stateinitialbeginLED_1 = 1'b0;LED_2 = 1'b0;currState = ST_IDLE;delay_value = 25'd0;nextState = ST_IDLE;end`define rundelay currState <= ST_DELAY_1S`define returndelay currState <= nextStatealways @(posedge clk or posedge rst)beginif (rst)currState <= ST_IDLE;elsebegincurrState <= nextState;case (currState)ST_IDLE:// all LED's are offbeginLED_1 <= 1'b0;LED_2 <= 1'b0;delay_value <= DLY_COUNT;nextState <= ST_1ON;`rundelay;endST_1ON:// LED_1 is on, LED_2 is offbeginLED_1 <= 1'b1;LED_2 <= 1'b0;delay_value <= DLY_COUNT;nextState <= ST_2ON;`rundelay;endST_2ON:// LED_1 is off, LED_2 is onbeginLED_1 <= 1'b0;LED_2 <= 1'b1;delay_value <= DLY_COUNT;nextState <= ST_ALLON;`rundelay;endST_ALLON:// both LED's are onbeginLED_1 <= 1'b1;LED_2 <= 1'b1;delay_value <= DLY_COUNT;nextState <= ST_IDLE;`rundelay;endST_DELAY_1S:// Delay of ~1sec. Note that the total delay is one clock cycle more because of the state transition.beginif (delay_value)begindelay_value <= delay_value -1;// as long as delay_value is larger than zero ( bitwise or)// decrement (decrementing counters synthesize smaller than// incrementing counters as no comparator is needed, only a// zero check which is a bitwise or.currState <= currState;endelsebegin//currState <= nextState;// if it hits zero ; throw the target state into currentstate.`returndelay;endendST_NDEF_1:beginnextState <= ST_IDLE;endST_NDEF_2:beginnextState <= ST_IDLE;endST_NDEF_3:beginnextState <= ST_IDLE;enddefault:beginnextState <= ST_IDLE;endendcaseendendendmodule

author: marshallh
author_rank: Unknown
timestamp: August 15, 2014, 02:27:58 am
content: Yes in always (*) blocks you can only use = assignments, however it just means "assign" rather than "load this register" as it would in a clocked always block.Combinational : = only,Synchronous: <= or = (where = has a different effect than above)I'm not sure why teh benefit of the two-always block FSM is, its more verbose and involves more legwork, which in verilog increases your chance for screwing up. Always used 1-always myself (heh)

author: gus789
author_rank: Contributor
timestamp: August 15, 2014, 03:57:54 am
content: Yes - in this case the always(*) construct seems to complicate things. In retrospect I think the trouble was in trying to mix up sequential (i.e. the delay) with combinatorial all in the same combinatorial always (*) block.I have been following the book "Verilog by Example". There they implement FSM with only sequential always blocks. The always @(*) construct was something I picked up from searching online and wanted to try it out. I think conceptually it does look neat - you have a sequential block that advances the machine and the another combinatorial block that executes the states. But it really is about what ISE is happy with in the end of the day!Cheers!

author: Bassman59
author_rank: Super Contributor
timestamp: August 15, 2014, 08:54:30 pm
content: Quote from: gus789 on August 14, 2014, 10:20:13 pmIt is exactly that problem -- that if you forget to assign to each machine output in every state in the combinatorial always block, you get a latch -- which is why most FPGA guys don't use the two-process state machine idiom.

author: Bassman59
author_rank: Super Contributor
timestamp: August 15, 2014, 08:57:17 pm
content: Quote from: hamster_nz on August 14, 2014, 09:26:56 pmThe distinction between Mealy and Moore state machines is purely academic; in the real world, we design state machines based on actual requirements and don't try to force things into one of two pigeonholes.

author: bwat
author_rank: Frequent Contributor
timestamp: August 15, 2014, 09:37:09 pm
content: Quote from: Bassman59 on August 15, 2014, 08:57:17 pmIn the real world most of us are forcing into pigeonholes. It makes life so much easier.Quote from: Robertson,Bundy,Muetzfeldt,Haggith,Uschold