Sequential Template
With a basic understanding of combinational Verilog, we can move on to a much more powerful circuit which includes sequential logic. The sequential template has the same starting as the combinational one, so we'll skip the early part.This circuit uses a counter to count clock ticks and switch the light after a certain amount of time.
1. module light1 (clk, rst, outN, outS, outE, outW, sensor_light, general_sensors);
2. input clk, rst;
3. output [29:0]debug_port;
4. output [2:0]outN; /* For cars going north */
5. output [2:0]outS; /* For cars going south */
6. output [2:0]outE; /* For cars going east */
7. output [2:0]outW; /* For cars going west */
8. input [7:0] sensor_light;
9. input [29:0] general_sensors;
10. parameter Stop = 3'b000,
11. Forward_only = 3'b001,
12. Left_only = 3'b010,
13. Right_only = 3'b011,
14. Go = 3'b100;
15. reg [7:0] count;
16. reg [2:0]outN;
17. reg [2:0]outS;
18. reg [2:0]outE;
19. reg [2:0]outW;
20. assign debug_port = count;
21. always @(posedge clk or negedge rst)
22. begin
23. if (rst == 1'b0)
24. begin
25. count <= 8'd0;
26. outN <= Go;
27. outS <= Stop;
28. outE <= Stop;
29. outW <= Stop;
30. end
31. else
32. begin
33. count <= count + 1'b1;
34. case (count)
35. 8'd0 :
36. begin
37. outN <= Stop;
38. outE <= Go;
39. end
40. 8'd64:
41. begin
42. outE <= Stop;
43. outS <= Go;
44. end
45. 8'd128:
46. begin
47. outS <= Stop;
48. outW <= Go;
49. end
50. 8'd192:
51. begin
52. outW <= Stop;
53. outN <= Go;
54. end
55. endcase
56. end
57. end
58. endmodule
Lines 15 through 19
Lines 15 through 19 describe how the signals count, outN, outS, outE, and outW are used. The keyword "reg" tells us that these signals will be used on the left-hand-side of statements in an always block. See golden rule 1 for a better understanding of this.
Note, count is an internal signal that is neither an input nor an output signal. Instead, we use count as an internal memory to remember how many ticks have gone by of the clock.
Line 20
This line uses the keyword "assign" which describes a combinational statement. In this case the signal coming in (count) is sent out on the "debug_port". This will allow us to see the values held in count while simulating.
Line 21
Line 20 is the start of a sequential always block. Note, verilogTown will only accept sequential always blocks in the form "always @(posedge clk or negedge rst)". So what does this mean? The posedge clk means that the values in the always blocks on the LHS are memory devices that will store new information (waiting at the dam) when the clk ticks. These memory devices will also be reset (initialized) when the rst signal goes to 0. Therefore, the circuit will only operate in normal mode when rst is kept as 1. Both the game and the simulator automatically do the resetting (control the rst signal) of the circuit for you.
You as the designer only have to make sure that you initialize your sequential logic properly. This is next.
Line 23 and Line 31
This is an if-then-else control structure for controlling the rst signal and initializing the circuit. Basically, when the "if" part is true we are resetting the circuit. This reset condition is very specific and should be (rst == 1'b0) since that matches the negedge rst defined in the always statement. We call this an active-low reset.
Lines 25 through 29
When the reset (or initialize) is true, lines 25 through 29 initialize the count to 0 and the lights to a Stop except outN. This is how we decided to initialize the sequential circuit, and all 5 of these signals are memory structures called registers. Note, that this is not because they were defined as reg up on lines 15 though 19, but it is because they are on the LHS of statements in a sequential always block. This is confusing for many Verilog learners and I refer you to golden rule 1.
The other thing to notice about lines 25 through 29 is that they are using a strange assignment operator "<=" instead of what we saw in the combinational design "=". This is golden rule 2 for synthesizable Verilog, which states that all assignments in a sequential always block should use the <= operator. In combinational blocks you should use the "=" operator.
Line 33
Line 33 is a statement that is more complex then most of the simple assignment statements we've already seen. First, it is evaluated in the else part of the if-then-else reset statement. Second, it follows golden rule 2. Third, the RHS of the statement adds the previous value of count with 1.
On line 15, count was defined as an 8bit number. That means that count can have a maximum positive size of 2 to the power of 8 minus 1 or the decimal value of 255 (this is equivalent to 8'b11111111). We might write this as 8'd255 in Verilog. Therefore, when count has a value of 255, the next time this operation happens it will have a value of 0. This is because the binary value of the addition is 9'b100000000, which the count register can't hold, and instead, count holds the value 8'b00000000. We did this on purpose so that every 256 ticks of the clock, count will go back to 0, and we can repeat the light changing sequence.
Line 34, 35, 40, 45, 50, and 55
This is a new Verilog structure we haven't seen yet. It is called a case structure and it operates very similar to an if-elseif-else structure. First, on line 34 the case statement says that it will check the control based on the signal count. This is defined by case ( signal ), where signal can be any signal (in our case it is count). Also, the case structure is wrapped and defined by the endcase at line 55.
Next, the lines 35, 40, 45, and 50 define the different cases that could happen. Line 35 says that when count equal 0 then lines 37 and 38 will be evaluated (outN will be Stop and outE will be Go). You might ask, why aren't outS and outW also set like in the combinational template? This is because we are using registers in the sequential code and a register keeps it's old value from the previous clock cycle when we don't change it. In this case, both outS and outW were previously equal to Stop and will be again.
Similarly, lines 40, 45, and 50 define other cases for when count is equal to 64, 128, and 192, respectively.
One thing to note about case statements is you can also include a default: case state. The default is evaluated if all other cases do not evaluate to true. For example, in this case statement when count is equal to 1, none of the cases are true, and if there was a default case then it would happen. In this design, we didn't need a default, but it is something to consider, especially, in combinational case statements since if you don't define the behaviour of every signal in every state then you can infer latches!
Finally, case statements can be written as if-elseif-else structures. For example:
if (count == 8'd0)
begin
end
else if (count == 8'd64)
begin
end
else if (...
The case structure, however, is a more efficient way of writing the design sometimes since it requires less text to convey the same functionality.
Description of this design
Now that we've discussed the new pieces of our sequential circuit, you might have figured out what this design does. Basically, the count counts each clock cycle in the decimal range 0 to 255. As each count is recorded the case structure switches the current light that is Go to Stop and makes a new light Go. This results in the lights going in a counter-clockwise Go in the simulation (try it by loading and saving sequential templates at one light). Each light is on for 64 clock cycles which equals 2.56 seconds. (64 ticks divided by 25Mhz).
Parallelism Revisited
At the end of the combinational template discussion we discussed how things all happen at once, which is different than sequential programming languages many of you are familiar with. This discussion makes more sense here.
For example, imagine the reset has just finished and count has a value of 0. Now, the clock ticks again and Line 33 sets the value of clock to 1. The question is, will Line 35 of the case statement be true? The answer is yes because the case statement is evaluated at the same time that Line 35 is happening. This means that the following statements will all happen:
outN <= Stop;
count <= count + 1'b1;
outE <= Go;
We put the count statement in the middle to emphasize that they all happen at the same time (parallel).