miles.sherman
miles.sherman

Reputation: 171

verilog / systemverilog -- What is the behavior of blocking statements across two always blocks?

I am wondering about the behavior of the below code. There are two always blocks, one is combinational to calculate the next_state signal, the other is sequential which will perform some logic and determine whether or not to shutdown the system. It does this by setting the shutdown_now signal high and then calling state <= next_state.

My question is if the conditions become true that the shutdown_now signal is set (during clock cycle n) in a blocking manner before the state <= next_state line, will the state during clock cycle n+1 be SHUTDOWN or RUNNING? In other words, does the shutdown_now = 1'b1 line block across both state machines since the state signal is dependent on it through the next_state determination?

 enum {IDLE, RUNNING, SHUTDOWN} state, next_state;
 logic shutdown_now;

 // State machine (combinational)
 always_comb begin
    case (state)
       IDLE: next_state <= RUNNING;
       RUNNING: next_state <= shutdown_now ? SHUTDOWN : RUNNING;
       SHUTDOWN: next_state <= SHUTDOWN;
       default: next_state <= SHUTDOWN;
    endcase
 end

 // Sequential Behavior
 always_ff @ (posedge clk) begin
    // Some code here
    if (/*some condition*/) begin
       shutdown_now = 1'b0;
    end else begin
       shutdown_now = 1'b1;
    end
    state <= next_state;
 end

Upvotes: 0

Views: 916

Answers (3)

Jonathan Mayer
Jonathan Mayer

Reputation: 1482

Here is how I would expect that code to perform:

You have two registers: a "shutdown_now" register and a "state" register.

On posedge of clk, the state of both of these registers is updated atomically. That is: when a blocking assignment to shutdown_now takes place, the current process isn't interrupted while state_next gets updated. Instead, for the purposes of the always_ff process, state_next is whatever value it held at the beginning of the posedge clk simulation "tick."

So:

  1. on the first posedge clock tick: shutdown_now will switch from 0 to 1.

  2. Once the "posedge clk" process has completed, the "always_comb" block will notice that it has work to do, and will update state_next (ie. a combinational decode from the new state of the 2 registers).

  3. on the second posedge clock tick: state gets latched with the updated state_next.

So, it will take 2 cycles to shut down your system, not 1.

Upvotes: 0

Ciano
Ciano

Reputation: 554

Miles, you really only have one state machine, that's the code in your always_comb block. The always_ff just creates a register to hold your state.

The way your code is written now, you will perform a shutdown in the following sequence:

  • cycle n: the logic in your always_ff block will determine if a shutdown should happen, and will SCHEDULE the shutdown_now signal to assert in the next clock tick.
  • cycle n+1: shutdown_now asserts, and the state machine (currently in RUNNING) will set the next_state to SHUTDOWN.
  • cycle n+2: now your state machine will be in the SHUTDOWN state.

Not sure that you need to have your shutdown logic in an always_ff block. If you move that code to a always_comb block, you could leave the rest of your code the same and your state machine would move to the SHUTDOWN state in cycle n+1.

Upvotes: 0

Greg
Greg

Reputation: 19094

First off, you are not following property coding. The always_comb should only use blocking (=) assignments, never non-blocking (<=). And always_ff is the reverse, only non-blocking (<=) assignments, never blocking (=).

With the code as is, state will go RUNNING. This is because the assignment to next_state is non-blocking and thereby next_state will not be updated until later in the scheduler.

Hypothetically, if next_state and shutdown_now were both blocking assignments, then the simulator will have a race condition. Both next_state could be evaluated and updated before or after state is evaluated. This is why it is not a good idea to mix blocking and non-blocking in the same always block.

If properly coded, ie next_state = ... and shutdown_now <= ..., then state will also go to RUNNING. This is because shutdown_now update happens after all scheduled evaluations are complete. So next_state will not see the 1'b1 until after state is evaluated.

Upvotes: 1

Related Questions