Author Topic: FSM Case Statements  (Read 1616 times)

0 Members and 1 Guest are viewing this topic.

Offline FoxxzTopic starter

  • Regular Contributor
  • *
  • Posts: 122
  • Country: us
FSM Case Statements
« on: June 02, 2022, 01:40:21 am »
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: [Select]
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) begin
if (divider != 0)
divider <= divider - 1;
else
case ({wait_ans, dv})
3'b000 : begin
we <= 1;
wait_ans <= 2'b11;
end
3'b100 : begin
x <= 2;
y <= 6;
wait_ans <= 2'b00;
end
3'b111 : begin
wait_ans <= 2'b00;
we <= 0;
divider <= 3000000;
end
endcase
end
endmodule
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9890
  • Country: us
Re: FSM Case Statements
« Reply #1 on: June 02, 2022, 02:00:57 am »
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.
 

Offline FoxxzTopic starter

  • Regular Contributor
  • *
  • Posts: 122
  • Country: us
Re: FSM Case Statements
« Reply #2 on: June 02, 2022, 02:08:36 am »
Right. I thought of that too. This is only test code and I have done this with the same effect.

Code: [Select]
always @(posedge CLKHF) begin
case ({wait_ans, dv})
3'b000 : begin
wait_ans <= 2'b11;
we <= 1;
x <= x;
y <= y;
end
3'b100 : begin
wait_ans <= 2'b00;
we <= 0;
x <= 2;
y <= 6;
end
3'b111 : begin
wait_ans <= 2'b00;
we <= 0;
x <= x;
y <= y;
end
default : begin
wait_ans <= wait_ans;
we <= we;
x <= x;
y <= y;
end
endcase
end
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: FSM Case Statements
« Reply #3 on: June 02, 2022, 02:35:17 am »
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.sv

Go to lines 1025 -> 1224...  Pay attention to trick #1 at line 1027.

This should help you re-code what you are trying to do...
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14470
  • Country: fr
Re: FSM Case Statements
« Reply #4 on: June 02, 2022, 02:43:54 am »
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.

Well, 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.
 
The following users thanked this post: Bassman59

Offline FoxxzTopic starter

  • Regular Contributor
  • *
  • Posts: 122
  • Country: us
Re: FSM Case Statements
« Reply #5 on: June 02, 2022, 02:48:11 am »
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.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: FSM Case Statements
« Reply #6 on: June 02, 2022, 02:56:13 am »
I would write the case only on wait_ans, which is your state signal here, and check dv inside each case with a if.
:-+
 

Online SiliconWizard

  • Super Contributor
  • ***
  • Posts: 14470
  • Country: fr
Re: FSM Case Statements
« Reply #7 on: June 02, 2022, 03:01:51 am »
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.

That 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.
 

Online BrianHG

  • Super Contributor
  • ***
  • Posts: 7733
  • Country: ca
Re: FSM Case Statements
« Reply #8 on: June 02, 2022, 03:02:36 am »
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.
You 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.
 

Offline FoxxzTopic starter

  • Regular Contributor
  • *
  • Posts: 122
  • Country: us
Re: FSM Case Statements
« Reply #9 on: June 02, 2022, 04:02:05 am »
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.

That 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.

I am using an ICE40UP and the Radiant tools. I am basing this on
1. 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
 

Offline Bassman59

  • Super Contributor
  • ***
  • Posts: 2501
  • Country: us
  • Yes, I do this for a living
Re: FSM Case Statements
« Reply #10 on: June 06, 2022, 05:34:11 pm »
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.

That 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.

Data 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.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf