Frank Dejay
Frank Dejay

Reputation: 739

verilog always, begin and end evaluation

I'm trying to learn Verilog using Pong P. Chu's book. I have a question about how an always block is evaluated and implemented. A style in the authors code is confusing me.

In this example he codes an FSM with two output registers 'y1' and 'y2'. The part I'm confused about is in the NEXT STATE LOGIC AND OUTPUT LOGIC always block, where after the begin statement and always@* y1 and y0 are set to 0. I seems that regardless of state, y1 and y0 will toggle to 0 on every clock cycle and signal change. According to state diagram in the book reg y1 should be equal to 1 while in state 0 or 1.

So does y1 toggle to 0 every clock cycle then back to what ever its value at the present state?? I assume that's not the case and that I'm just confused about how the block is evaluated. Can someone explain what that part of the code is doing. I'm lost. Thanks

module fsm_eg_2_seg
    (
     input wire clk, reset, a, b,
     output reg y0, y1
    );

    //STATE DECLARATION
    localparam [1:0]    s0 =2'b00, 
                    s1=2'b01, 
                    s2=2'b10;

    // SIGNAL DECLARATION
    reg [1:0] state_reg, state_next ;

    //STATE REGISTER
    always @(posedge clk, posedge reset)
        if (reset)
            state_reg <= s0;
        else
            state_reg <= state_next;

    //NEXT STATE LOGIC AND OUTPUT LOGIC
    always @*
    begin
        state_next = state_reg; // default next state: the same
        y1 = 1'b0;              // default output:  0
        y0 = 1'b0;              // default output:  0
        case (state_reg)
            s0:  begin
                y1 = 1'b1;
                if (a)
                    if(b)
                        begin
                            state_next = s2;
                            y0 = 1'b1;
                        end
                    else
                        state_next = s1;
                end
            s1:  begin
                    y1 = 1'b1;
                    if (a) 
                        state_next = s0;
                    end
            s2: state_next = s0;
            default: state_next = s0;
        endcase
    end
endmodule

Upvotes: 5

Views: 21567

Answers (4)

Steve K
Steve K

Reputation: 2202

I don't think other answers directly and correctly addresses the question of whether y0 and y1 toggle to 0 and back on every clock cycle.

Let's say that the state machine changes from s0 to s1. In both states the end value of y1 is 1 but in re-evaluating the always block y1 is first assigned 0. This toggling may happen multiple times per clock, or not at all on a clock cycle depending how many times a, b, and state_reg change. Whether this toggling propagates to the wire attached to output y1 is simulator dependent. Port assignments are treated as continuous assignments in Verilog, which are separately running threads of execution. It is perfectly legal for the simulator to suspend execution of the always block after the y1=0 assignment is made, assign 0 to the wire attached to output y1, and resume execution of the always block afterwards. Practically speaking, it doesn't matter IF good coding styles are practiced because the value of y1 won't get latched into any registers until the next clock cycle, long after all the toggling is done and the final value of y1 is available.

In simulation the toggling happens in zero time but it also happens in real hardware when multiple inputs change. It takes special design practices to build logic that doesn't "glitch" like this.

Upvotes: 1

Nathan Farrington
Nathan Farrington

Reputation: 1970

The expression

always @* begin : name_of_my_combinational_logic_block
    // code
end

describes combinational logic. Typically the clk and rst signals are not read from inside of this type of always block, so they don't appear in the sensitivity list like wisemonkey says. It is best practice to use @* for the sensitivity lists of combinational logic so that you don't forget to include a signal, which would infer some memory and it would no longer be combinational logic.

Inside a combinational logic block, you should use what are called blocking assignments. These look like regular variable assignments in most programming languages and use a single equals. The value that you assign to a variable (a reg) inside of a combinational logic block happens immediately with respect to other statements and expressions in that same combinational logic block, but does not propagate outside of this combinational logic block until you reach the end. The always block must reach the end before any changes are seen outside of the block. Paul S is right that you want to always assign something to your variables whenever the always block is executed, otherwise you will infer memory.

Upvotes: 4

Paul S
Paul S

Reputation: 7755

Have to say I disagree with aqua. What he (and wisemonkey) says about @* is right, but the rest is wrong.

Those two lines have nothing to do with an idle state. Those statements are there as good coding practise. They ensure that those two outputs are always assigned to when that always block is evaluated. Let's see why this is important:

  • Imagine that those two statements aren't there.
  • Next suppose that state_reg = S0, and a = b = 0
  • As we evaluate the always block, we enter the case statement, s0 half, and assign 1 to y1
  • a is zero so we don't enter the if statement, and we drop out of the case, and end the block

At the end of the block y1 == 1 and y0 == ... erm, hang on what does y0 get? I guess it has to keep it's old value. It didn't get a new one.

That means it's possible y0 has to remember it's value from one cycle to the next. That would mean it needs to have some kind of memory involved, like a register or a latch. In this case it would be a latch as it's written in a style that sometimes drives the output and sometimes holds it.

...but we don't want that. y1 and y0 were meant to be simple wires. Therefore we must make sure each of them are always assigned to, no matter what the state or inputs are. We could do that by having assignments in all the branches of the logic, but that becomes a lot of work. Alternatively we can have a default assignment which we later override if necessary.

The reason these statements don't introduce y1 going to 0 in s0 or s1 is because everything that happens inside an always block happens with no time passing. No time passes between the 0 being assigned at the top and the 1 in s0 or s1. All that's visible is the final state.

You'll note the code does exactly the same thing with the state variable. It has a default assignment that the next state is the current state, and then overrides that it the correct conditions are met.

Nice clean state machine. Nothing wrong with it.

Upvotes: 4

aqua
aqua

Reputation: 3375

This is a poor example of an FSM. I'm not surprised that you are confused. The way I understand it, an always block is scheduled to run only when the inputs in its sensitivity list change.

So for the first always block, it is scheduled to run every clock transition from 0 to 1, and reset is asynchronous.

The second always block has the @* notation, which basically creates a sensitivity list for you based on the logic within the block. Recall that only inputs matter in a sensitivity list. Therefore, this always block will be scheduled if a, b, or state_reg change.

In this example, the

    y1 = 1'b0;              // default output:  0
    y0 = 1'b0;              // default output:  0

is trying to model an IDLE state, a state where the FSM is outputting 0. If you do a quick study of how the FSM operates, you'll see that once it starts transitioning through the states, (the case statements) it won't come back out.

Ideally you want your IDLE information within a state of its own, not floating outside the state logic, but I suppose this works as a trivial example.

Upvotes: 1

Related Questions