In this lab, you will learn the basics of creating Verilog modules with the WebFPGA to control the RSLK robotics kit. When you write Verilog, you’re not creating a program, you’re creating hardware. Verilog is, after all, a HDL (Hardware Description Language). This lab will teach you what that means and how to correctly write Verilog code.
Modules and WiresWARNING: In this lab, you will be running code on the TI RSLK Max Robotics kit with the WebFPGA attached. Power your FPGA through USB Power ONLY, not through battery power.
The basic building block of Verilog is a module. Modules can be equivalent to a single logic gate (like AND or OR), or can be as complex as an entire discrete design. When creating verilog code, your entire design will be contained within a module; this is called the top-level module. Let's look at an example of a top level module.
module example_top_level(input A, output B);
assign B=A;
endmodule;
The entirety of a given module will be sandwiched between the module and endmodule statements. The first one names the module and gives the names of the inputs and outputs to the module. The last one tells the compiler where the end of the module is. Every module has to begin and end like the one above. Between the beginning and end are the guts of the module. This module defines A as it’s input, and B as it’s output. It then assigns the value of B to the value of A.
This module isn’t super useful, but one of the ways we can make it more useful is by using another module within it! Let’s look at an example:
module example_top_level(input A, input B, output C);
and U1 (C, A, B);
endmodule;
This module now calls another module, and, within it. These modules - called gate level primitives - come pre-built into Verilog. They simulate most common logic gates. With them, our module example_top_level now sets its output, C, to the values of A AND B together. We named this instance of the “AND” module “U1”. It helps in more complex examples requiring the use of multiple modules:
module example_top_level(input A, input B, input C, output D);
wire inbetween;
and U1 (inbetween, A, B);
and U2 (D, inbetween, C)
endmodule;
Note how in this example, we defined a new variable in the module; a “wire”. Wires are used to connect modules together. In this case, I assumed the output of the U1 AND module to a wire. That wire is then used as an input to the U2 AND module. This creates the following logic: (A & B) & C. We can also just save time, and actually use that exact statement in Verilog to create that logic. See below:
module example_top_level(input A, input B, input C, output D);
assign D = (A & B) & C;
endmodule;
Depending on the application/your preference, using gate level primitives may be easier than using the above style, referred to as dataflow. If your logic can be recreated with dataflow, feel free to use it! Just be sure to use the assign operation to set the values of wires/outputs.
Speaking of wires, inputs, and outputs, up until this point, we’ve been dealing in single bit versions of all those.
Refer to the module below to see a two bit version (intro to Endian-ness) of the module from before. Not that when you define a bit range, you start at the 0th bit, then the 1st bit, and so on and so forth.
Be sure to keep your bit ranges consistent; trying to assign a 13 bit value to a 2 bit wire will result in you losing the 11 most significant bits.
module example_top_level(input [1:0] A, input [1:0] B, input [1:0] C, output [1:0] D);
assign D = (A & B) & C;
endmodule;
You can also reference specific bits in an input/output/wire, like you would reference specific elements of an array; see the module below for an example which takes in a two bit value A, logically ORs each bit, and outputs it to B, while also adding A to itself and setting it to C. Notice how I made C large enough to hold any potential combinations of addition of a 2 bit number like A.
module example_top_level(input [1:0] A, output B, output [2:0] C);
assign B = A[1] | A[0];
assign C = A + A;
endmodule;
Knowing what you know about Verilog modules, can you write modules that do the following?
You may find this list of logical Verilog operators useful. You can also use basic math signs (without the parenthesis) like add (+), subtract (-), multiply (*), and divide (/)
- Take two 5 bit numbers, XOR them, and output the new number out of the module.
- Take in two 5 bit numbers, square both of them, add them together, then output the resultant sum (make sure your wires are large to hold the largest possible result of a 5 bit number being squared).
- Take in a 32 bit number, and output two 1 bit numbers, one which is all the odd input bit’s XOR’ together, and one with all the even bits XNOR’d together
So, we’ve learned how to write Verilog modules on their own, but how do we use them to control our RSLK-Max Robotics Kit? To do that, we need to define inputs and outputs into our module that correspond to physical components of the WebFPGA. As a simple example, there are inputs and outputs that the WebFPGA will automatically recognize if you use them as inputs and outputs. These are WF_LED and WF_BUTTON. Using WF_LED as an output wire, we can control the LED on the WebFPGA. When WF_LED is 0, the LED on the WebFPGA is On. Assign when it is 1, it is off. See the module below for an example:
module fpga_top(output wire WF_LED);
assign WF_LED = 0;
endmodule
Also, note that my module is named fpga_top. In order for your module to be recognized by the WebFPGA, the top level module (ie, the module you call all other modules from and contains all your logic) must be named fpga_top. If you flashed the above code onto your WebFPGA, the yellow LED on your WebFPGA should stay on continuously. Similarly, if you set it to 1, the LED will be off continuously.
Now, on to WF_BUTTON. When you set this as an input wire, it’s value will be 1 as long as the button is not pressed, and will be 0 when the button is pressed. Knowing this, here’s a quick assignment for you.
- Write (and test) a verilog module that turns on the WebFPGA’s onboard LED when you press the WebFPGA’s button. Keep in mind that you’re writing hardware when you write Verilog, not software. Assigning wires in Verilog is not equivalent to assigning a value to a variable in a sequential programming language.
Controlling LEDs on the Web FPGA is one thing, but what about LEDs (or other components, eventually) on the RSLK itself? To do that, we have to define the General Purpose Input Output ports (henceforth called GPIO ports) as inputs and outputs to our module. These allow your module to both read digital input signals from pins attached to the WebFPGA, as well as output digital signals through those same pins, all depending on how you define them in your module. To actually name them, though, you need to define their name/pin number in the comments before the module. See below for an example module with no logic.
//Pin Map
// @MAP_IO ledFL 17
// @MAP_IO ledFR 18
// @MAP_IO ledBL 19
// @MAP_IO ledBR 20
module fpga_top(
input wire WF_BUTTON,
output wire ledFL,
output wire ledFR,
output wire ledBL,
output wire ledBR
);
endmodule
Those 4 pin maps above correspond to the front left, front right, back left, and back right LEDs on the RSLK, and the numbers correspond to the connections between the WebFPGA and RSLK on the PCB. With the above pin definition, you can now control the LEDs using your Verilog module. We will gradually introduce more peripherals over the course of the labs, all controlled through these GPIO pins. The LEDs on board go high when assigned to 1, and go low when assigned to 0. Now, for another assignment.
- Can you write a module to turn the LEDs on the RSLK on when you press the button, but off when you release it?
Congratulations! You have learned how to write basic Verilog modules, and how to use those modules to control simple functions on your car. These concepts will form the basis of all the logic programming you’ll learn over the course of the lab. Eventually, you’ll be using modules to control the motors of the car, and using advanced logic to make the car follow a black line on the ground using IR sensor
Comments