Combinational Template

Let's jump in and see that combinational template in the game.  This is the Verilog you will see when you open any intersection for the first time.  Note that many of the comments included in the actual file in the game have been removed for viewing (these are wrapped with /* and */ and are ignored as human comments about the code).

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 [2:0]outN;
16. reg [2:0]outS;
17. reg [2:0]outE;
18. reg [2:0]outW;

19. assign debug_port = sensor_light;

20. always @(*)
21. begin
22.     if ((sensor_light[0] == 1'b0) && (sensor_light[1] == 1'b0) && (sensor_light[2] == 1'b0) && (sensor_light[3] == 1'b0))
23.    begin
24.        if (sensor_light[6] == 1'b1)
25.        begin
26.            outN = Go;
27.            outS = Stop;
28.            outE = Stop;
29.            outW = Stop;
30.        end
31.        else if (sensor_light[4] == 1'b1)
32.        begin
33.            outN = Stop;
34.            outS = Go;
35.            outE = Stop;
36.            outW = Stop;
37.        end
38.        else if (sensor_light[5] == 1'b1)
39.        begin
40.            outN = Stop;
41.            outS = Stop;
42.            outE = Go;
43.            outW = Stop;
44.        end
45.        else if (sensor_light[7] == 1'b1)
46.        begin
47.            outN = Stop;
48.            outS = Stop;
49.            outE = Stop;
50.            outW = Go;
51.        end
52.        else
53.        begin
54.            outN = Go;
55.            outS = Go;
56.            outE = Go;
57.            outW = Go;
58.        end
59.    end
60.    else
61.    begin
62.        outN = Stop;
63.        outS = Stop;
64.        outE = Stop;
65.        outW = Stop;
66.    end
67. end

68. endmodule

Lines 1 through 14

These lines in RED should not be changed in verilogTown as they are used to simulate the game.  However, we will describe what they do.

Line 1 is the header for the circuit.  It describes the inputs and outputs of a module just by name.  The syntax (how the grammar should be written) is "module {name of the module} ( signals , signals, ... );".  The word "module" and the punctuations (),; are a keyword and grammatical indicators that are restricted in use.  {name of the module} can be any name and signals also can be any non-keyword that are start with a letter and are alpha numerical names that can include the "_" punctuation without spaces.  For example, the following are legal names: "hello", "hell0", "hel_L0", and "H_3_L_l_0_".  This naming convention is used for any designer created names.

Once the module has been described the next few lines describe if a signal is an input or output and how many bits it can hold. Line 2, for example, says that the signals "clk" and "rst" are inputs (going into the circuit) and are 1 bit wide (can only hold the value of 0 or 1 also known as False and True, respectively). Line 3 through 9 are similar to line 2, but they describe signals that are either input or outputs to the design and can hold multiple bits. Line 4 for example describes a signal named "outN" that can hold 3 bits of data. We would call this a binary number of 3 bits which means it can represent the following positive decimal decimal digits: 0, 1, 2, 3, 4, 5, 6, and 7 (see Binary for a better understanding of this idea).

Just so you understand what all these signals are we will describe them:
Lines 10 through 14 describe what are called "parameters".  A parameter allows us to associate a word with a value.  For example, the word Stop will be replaced by the value 3'b000 (see Verilog numbers to understand 3'b000 or what 3'd0 means).  Briefly, 3'b010 means: a 3 bit number (3), written in binary ('b), with binary values "010" from most significant bit to least significant bit; 3'd2 means: a 3 bit number (3), written in decimal ('d), with decimal value 2 (note, 3'd2 is the same value as 3'b010).  We predefine all the traffic parameters so that the game and simulator know what signal you want to control the traffic light with.

Lines 15 through 18

The remainder of the file is written and modified by you.  Lines 15 through 18 describe how the signals 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.

Line 19

This line uses the keyword "assign" which describes a combinational statement.  In this case the signal coming in (sensor_light) is sent out on the "debug_port".  We would say the left-hand-side (LHS) signal "debug_port" has been assigned by the "=" (equal operator) the value of the right-hand-side (RHS).  On the RHS, we could do something more complex such as addition, subtraction, logical AND, bitwise AND, etc.  However, in this case we are just assigning an input to an output.  This is done on the sequential example.

Line 20

Line 20 is the start of what is called an always block.  The word "always" is a keyword in Verilog and can be interpreted as "always evaluate everything in my block".  From our perspective, if the block (a block is surrounded with begin and end keywords) is combinational it will be identified by "always @(*)".  Therefore, this is one of two possible ways to define an always block for verilogTown.  We will see the sequential way of defining an always block later.  Note, verilogTown will only accept combinational always blocks in the form "always @(*)".

Line 21 and 67

These are the "begin" and "end" keywords that wrap the block associated with the always block.

Line 22 and Line 60

Line 22 is the start of what is called an "if" statement.  An "if" statement is a control statement that is used to control whether something should happen.  In this case if the expression described in between the round brackets ( ) is true then the description between line 23 and 59 will be evaluated.  If the expression is false then the statements between lines 61 and 66 will be evaluated.  This combination is called an "if-then-else".

The expression on Line 22 is:
(sensor_light[0] == 1'b0) && (sensor_light[1] == 1'b0) && (sensor_light[2] == 1'b0) && (sensor_light[3] == 1'b0)

Let's look at the first part:
(sensor_light[0] == 1'b0)

This is a sub-expression that is true (equal to 1) if the signal sensor_light[0] is equal to the binary value 0.  In terms of the game, this means that there is no car currently at the top left inner road of this particular traffic light.  This is repeated for each of the portions of the inner traffic light in the following three inner sensors.  Each sub-expression is joined together with the operator &&, which is a logical and operation.  The entire expression might be read as "there is no car at sensor 0 AND there is no car at sensor 1 and there is no sensor at sensor 2 AND there is no car at sensor 3".  If this is true then we'll execute the if portion.  If it is not true (which means false) we execute the else part, which basically turns all the lights to Stop (see below).

How do we know which sensor_light bit corresponds to which traffic light sensor?  It's described in the comments and you can also look at the following:

Lines 24, 31, 38, and 45

Assuming that the if-then-else just described evaluates to true which means there are no cars in the intersection, then we evaluate the embedded if-elseif-elseif-elseif-else structure.  This is called a nested if structure because it is wrapped by the if-then-else control structure.  (In real designs this can result in very long wires which can cause timing problems!  Here, we don't have to worry about this, but keep it in mind as you build real circuits.)  

Line 24 starts this with a the if expression:
if (sensor_light[6] == 1'b1)

This asks if there is a car waiting at the traffic light that wants to go north determined by reading the sensor.  If there is (or it evaluates to true), then lines 26 through 29 are evaluated.  Lines 26 through 29 are similar to the assign statement we saw earlier, but in this case they assign the parameter values to the traffic output signals, and in this case, we set the go North signal to Go and all the other lights to Stop.

If the If statement is false then line 31 is evaluated which is an "else if" which checks if there is a car going south.  If that is true then the South light is set to Go and all the rest are set to Stop.  This process is repeated for each direction.

Note, that the order of if-else if-else means that for this design, the cars going north will have priority over other directions.

Line 68

The key word here is "endmodule" which tells the Verilog compiler that this is the end of the module description.

Discussion of the Combinational Template

By reading the above you should come out with the understanding that the combinational Verilog code looks at a traffic light and if there are no cars currently moving through the traffic light then the a car is allowed to Go in the priority of northbound, southbound, eastbound, and finally, westbound.

One questions you might be asking is, "Why do you need to define what all N, S, E, and W signals in every instance?"  If you are familiar with sequential programming languages such as C or Java then this might appear strange.  In Verilog, you have to understand that you are "describing a circuit" and not writing a series of steps that will be executed one after another.  This means that the code describes a parallel execution (as in everything happens at the same time).  This is a BIG difference, and therefore, in a combinational always block, you need to set the output of every signal in it for all possible situations.  In verilogTown this might not hurt you since the design is simulated, but in a tool such as Quartus (Altera's tool) you will get warnings of "inferred latches".  These are BAD unless you really want such things (you, likely, don't).  To avoid these, in any combinational always block assign the LHS signals in every possible case and use "else" and "default:" statements (default is part of a case statement).

Also, to illustrate the parallel aspect a little more look at the following Verilog:
1. A = 2;
2. B = A + 1;

In sequential programming languages, the value of B would be 3 since statement 1 happens and then statement 2.  This is not the case in Verilog.  Both statements happen simultaneously, and therefore, the value of B depends on previous state.  That means combinational logic is not good for the above statements, and sequential logic will help us in this regard.