Verilog always, start and end assessment

I am trying to learn Verilog using the book Pong P. Chu. I have a question about how the block is always evaluated and implemented. The style in the authors code is confusing.

In this example, it encodes an FSM with two output registers "y1" and "y2". The part I got confused with is in the NEXT STATE LOGIC AND OUTPUT LOGIC always, where after the begin instruction and always@ * y1 and y0 are set to 0. It seems that regardless of the state, y1 and y0 will switch to 0 on each measure and signal change. According to the state diagram in the book, reg y1 should be equal to 1, while in state 0 or 1.

So, y1 switches to 0 every measure, and then returns to what is its value in its current state? I assume this is not the case, and I just got confused about how the block is evaluated. Can someone explain what this part of the code does. 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 
+4
source share
4 answers

Expression

 always @* begin : name_of_my_combinational_logic_block // code end 

describes combinational logic. As a rule, clk and the first signals are not read from within this type of block always, so they do not appear in the sensitivity list, as wisemonkey says. It’s best to use @ * for sensitivity lists of combinational logic so that you don’t forget to turn on a signal that outputs some memory, and this will no longer be combinational logic.

Inside a combinational logic block, you must use what are called lock assignments . They look like regular variable assignments in most programming languages ​​and use one equal. The value that you assign to the variable (reg) inside the combinational logic block immediately occurs with respect to other operators and expressions in the same combinational logic block, but does not extend outside this combinational logic until you reach the end. The block must always reach the end before any changes are visible outside the block. Paul S is right that you want to always assign something to your variables whenever a block is always executed, otherwise you will output memory.

+2
source

I must say that I do not agree with aqua. What he (and wisemonkey) says about @* is right, but everything else is wrong.

These two lines have nothing to do with the idle state. These statements are good coding practices. They ensure that these two outputs are always assigned when this always block is evaluated. Let's see why this is important:

  • Imagine that these two statements are not.
  • Further, suppose that state_reg = S0 and a = b = 0
  • When we always calculate a block, we introduce the operator case, s0 half and assign 1 y1
  • a is zero, so we do not enter an if statement, and we exit it and end the block

At the end of the block, y1 == 1 and y0 == ... erm, hold on to what y0 does? I think he should preserve his old value. This is not new.

This means that perhaps y0 should remember this value from one cycle to another. This would mean that it should have some kind of memory, for example, a register or a latch. In this case, it will be a latch, because it is written in a style that sometimes leads to exit and sometimes holds it.

... but we do not want this. y1 and y0 should have been simple wires. Therefore, we must make sure that each of them is always assigned, no matter what state or source data. We could do this with assignments in all branches of the logic, but it becomes a lot of work. Alternatively, we can have a default assignment, which we will redefine later if necessary.

The reason these instructions do not enter y1 at 0 in s0 or s1 is because everything that happens inside a block always happens without passing time. Mileage between 0 is assigned from above and 1 in s0 or s1 . Everything that is visible is the final state.

You will notice that the code does the same with the state variable. It has a default assignment, the next state of which is the current state, and then overrides its correct conditions.

Nice clean car. Nothing wrong with that.

+4
source

This is a bad example of FSM. I'm not surprised that you are confused. As I understand it, the always block is planned to be launched only when the inputs in the sensitivity list are changed.

So, for the first block always is planned to start each clock transition from 0 to 1, and reset is asynchronous.

The second block always has the @* notation, which basically creates a sensitivity list for you based on the logic inside the block. Recall that in the sensitivity list there is only input data. Therefore, this block will always be scheduled if a , b or state_reg .

In this example

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

tries to simulate the IDLE state, the state in which FSM displays 0. If you quickly learn how FSM works, you will see that as soon as it starts to transition through states (case statements) it will not return.

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

+1
source

I don’t think that other answers directly and correctly solve the question of whether y0 and y1 go to 0 and vice versa for each clock cycle.

Assume that the state of the machine changes from s0 to s1. In both states, the final value of y1 is 1, but when redefining the block y1, it is always assigned 0. First, this switching can occur several times per cycle or not at all on a cycle, depending on how many times a, b and state_reg change. Regardless of whether this switching applies to the wire connected to output y1, it depends on the simulator. Port assignments are considered continuous assignments in Verilog that separately execute threads. For the simulator, it is completely legal to suspend always execution of a block after executing y1 = 0, assign 0 to the wire connected to output y1, and always resume execution of a block subsequently. Practically speaking, it doesn’t matter if good coding styles are used, because the value of y1 will not be fixed in any registers until the next clock cycle, after all switching is completed and the final value of y1 is available.

In the simulation, switching occurs at zero time, but also occurs in real hardware when multiple inputs change. To create logic that is not “buggy” like this, special design practice is required.

+1
source

Source: https://habr.com/ru/post/1391036/


All Articles