FSM Case Statements - Page 1
Forum section: electronics / general

author: Foxxz
author_rank: Regular Contributor
timestamp: June 02, 2022, 01:40:21 am
content: I'm having trouble with a verilog case statement executing strangely and I don't know why.The basics below... I'm sending X/Y coordinates to a module, setting write enable (we), and then waiting for it to strobe data valid (dv) for a clock cycle.X and Y start off at 0. WE gets set to 1 and then wait for the dv flag to be set. And this should happen forever. The clock divider is there to pause between sending X/Y coordinates.The problem I'm having is that middle case expression is getting executed at some point and I don't understand why. wait_ans never gets set to 2'b10 at any point. I have changed that middle expression to be 3'b010 and it still executes.Do verilog case statements "fall through" to the next case expression unless you call "break" like they do in some programming languages? I haven't seen anything to indicate that they do.Is my concatenation of {wait_ans, dv} wrong?Code:module top_framebuffer_seven(output [0:8] out_matrix);wire CLKHF, dv;wire [1:0] dout_a;reg we = 0;reg [1:0] din_a = 3;reg [2:0] x = 0;reg [3:0] y = 0;reg [1:0] wait_ans = 2'b00;reg [31:0] divider = 3000000;framebuffer_seven fb(32'b11111111_10000000_01000000_00000000, CLKHF, we, 0, 1, din_a, dout_a, 6'b0, x, y, dv, out_matrix);HSOSC #(.CLKHF_DIV ("0b11")) OSCInst0 (.CLKHFEN (1), .CLKHFPU (1), .CLKHF (CLKHF));always @(posedge CLKHF) beginif (divider != 0)divider <= divider - 1;elsecase ({wait_ans, dv})3'b000 :beginwe <= 1;wait_ans <= 2'b11;end3'b100 :beginx <= 2;y <= 6;wait_ans <= 2'b00;end3'b111 :beginwait_ans <= 2'b00;we <= 0;divider <= 3000000;endendcaseendendmodule

author: rstofer
author_rank: Super Contributor
timestamp: June 02, 2022, 02:00:57 am
content: I don't know anything about Verilog but I do know VHDL and, in that language, every output from a FSM must be defined in every condition. You have we=1 in state 3'b000 but it isn't defined in state 3'b100 and this will infer a latch in VHDL.In VHDL, the solution is to assign default values to EVERY output signal at the top of the FSM, ahead of the case statement. The last assignment is the one used so in state 3'b100 it would probably use the default value which you would code as we = 0; somewhere ahead of the case statement.Every signal must be defined, one way or another, in every state and under all conditions. Hence the use of default values.

author: Foxxz
author_rank: Regular Contributor
timestamp: June 02, 2022, 02:08:36 am
content: Right. I thought of that too. This is only test code and I have done this with the same effect.Code:always @(posedge CLKHF) begincase ({wait_ans, dv})3'b000 :beginwait_ans <= 2'b11;we <= 1;x <= x;y <= y;end3'b100 :beginwait_ans <= 2'b00;we <= 0;x <= 2;y <= 6;end3'b111 :beginwait_ans <= 2'b00;we <= 0;x <= x;y <= y;enddefault :beginwait_ans <= wait_ans;we <= we;x <= x;y <= y;endendcaseend

author: BrianHG
author_rank: Super Contributor
timestamp: June 02, 2022, 02:35:17 am
content: You can learn a few tricks from my state machine here:https://github.com/BrianHGinc/BrianHG-DDR3-Controller/blob/main/BrianHG_DDR3/BrianHG_DDR3_PHY_SEQ.svGo to lines 1025 -> 1224... Pay attention to trick #1 at line 1027.This should help you re-code what you are trying to do...

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 02, 2022, 02:43:54 am
content: Quote from: rstofer on June 02, 2022, 02:00:57 amWell, unless I haven't fully understood what you said, I don't think this is true *if the process is clocked*. It is if the process isn't clocked.For a clocked process implementing a FSM, any signal not assigned in a particular state will retain its state with a flip-flop. Adding things such as 'x <= x' brings nothing to the table. Any assigned signal in a clocked process goes through a flip-flop. No latch. You can get a latch if your process isn't clocked, and this is what can happen when you typically write FSMs using 2 or more processes, one that is clocked and that handles setting the next state, and one or more that is combinatorial.In the OP's case, the process is clocked, so the problem is not there. I'm no Verilog user either, but the part that the OP posted is pretty simple.If I get it right (OP: please correct me if I'm wrong), your FSM seem to be getting in the '3'b100' state while wait_ans is never set to '10'. I do find the case fishy though. The state is defined from two separate signals instead of one (wait_ans, dv). I suppose dv is set outside of the module altogether? I'd be guessing that it might confuse synthesis, and I would say that this looks like a pretty odd FSM.Again, I don't write Verilog (but VHDL), so I may be missing something in Verilog, but I wouldn't write the FSM this way.I would write the case only on wait_ans, which is your state signal here, and check dv inside each case with a if.

author: Foxxz
author_rank: Regular Contributor
timestamp: June 02, 2022, 02:48:11 am
content: So I think I found the issue after digging through the synthesis output. The tools ignore register initialization and they need to be handled via global reset. Because of this the toolset is setting x <= 2 and y<=6 right out of the gate since its the only assignment it sees.I will need to look for a global power on reset and initialize the registers that way.

author: BrianHG
author_rank: Super Contributor
timestamp: June 02, 2022, 02:56:13 am
content: Quote from: SiliconWizard on June 02, 2022, 02:43:54 am

author: SiliconWizard
author_rank: Super Contributor
timestamp: June 02, 2022, 03:01:51 am
content: Quote from: Foxxz on June 02, 2022, 02:48:11 amThat is odd. Is this an FPGA? What vendor? Initialization does work with all FPGAs that I've worked with, due to their structure and how they are configured. But of course it won't work for general-purpose synthesis, in particular direct for silicon.

author: BrianHG
author_rank: Super Contributor
timestamp: June 02, 2022, 03:02:36 am
content: Quote from: Foxxz on June 02, 2022, 02:48:11 amYou only need to make your case (xxx), make the xxx reset to 0 and in state 0, perform all the other necessary resets if you so please.You can also have an if(reset), blahh, blahh, blahh, else begin case (xxx)...There are just so many possible ways to approach this.also:reg [3:0] xxx = 0;would make your sim begin to run with case 0, where I said you should place your reset condition.If you looked at my example code from my DDR3, you can see I use 'xxx', or in my case 'init_pc' just as if it were a program counter and the case positions are executed like lines of code.

author: Foxxz
author_rank: Regular Contributor
timestamp: June 02, 2022, 04:02:05 am
content: Quote from: SiliconWizard on June 02, 2022, 03:01:51 amI am using an ICE40UP and the Radiant tools. I am basing this on1. The tools stating the X register is stuck at 2 and the Y register is stuck at 6 even though they should both be stuck, or at least start, at 0.2. This conversation here:https://github.com/YosysHQ/yosys/issues/103

author: Bassman59
author_rank: Super Contributor
timestamp: June 06, 2022, 05:34:11 pm
content: Quote from: SiliconWizard on June 02, 2022, 03:01:51 amData point: initialization of signals (as part of the signal declaration) doesn't work in either Microsemichip FPGAs or Lattice MachXO2 (I've not used other Lattice parts). An explicit preset/reset is required.