Quartus 101 Module B: Creating and Synthesizing Verilog RTL Code

There are many ways to create content for your Amani: schematic diagram entry, Verilog and VHDL coding. In this example we will use the Verilog HDL language to create a simple blinking LED. While I’ll explain the example code in detail, you can find a fantastic Verilog/VHDL resources at fpga4fun.com They also provide fantastic information on CPLDs and FPGAs in general.

We’ll start with the Verilog RTL.

Step 1: You should already have created your AmaniBlink project in Unit A. With the project loaded, go to File: New and select Verilog HDL File, press OK.

A text editor will then be open in the workspace.

Step 2: Verilog RTL entry.

Cut and paste the following Verilog code into the text editor:

module AmaniBlink(clk_32, LED);

input clk_32;
output LED;

reg LED;
reg [23:0] counter;

always @(posedge clk_32)
    if (counter == 16000000)
        counter <= 0;
        LED <= ~LED;
        counter <= counter + 1;
        LED <= LED;


Save this file as AmaniBlink.v I’ll explain the code later in this tutorial.

Step 3: Define AmaniBilnk.v as the Top-Level Entity

Previous versions of Quartus II 10.0 required you to define the top-level entity of the project manually. Version 10.0 automatically correlates this if you save your verilog file named as the top-level entity that you defined during the New Project Wizard phase.

You can assign this module or other design elements you create the top-level entity by going to Assignments: Set as Top-Level Entity with the AmaniBlink.v file active in the workspace. If you are using an older version than 10.0, or suspect Quartus II has not automatically defined the top-level entity, you need to manually define the top-level entity.

CTRL+SHIFT+J sets the design file currently active in the workspace as the top-level entity.

Step 4: Unused Pins Considerations

If you take anything from this module, You Must Learn to Make a Habit of Assigning Unused Pins As Tri-Stated Inputs. Your Amani will thank you, your Arduino will thank you, your future self who went down an alternate and unfortunate path of reality will thank you. This will prevent your Amani and other devices from trying to drive the same connection at different logic states. Things get rather hot when configured otherwise.

Under the Assignments Menu select Device. The familiar Device Selection pop-up will appear. While you may use this menu to select a different device to design for, we are going to use it to configure our unused pins. Click the Device and Pin Options… button.

Under Categories select Unused Pins and in the Reserve All Unused Pins dialogue box to the right select As Input Tri-Stated.

You can set this configuration during the New Design Wizard phase of the project. As you become an advanced user of Quartus II, you will learn to use TCL scripts to be used for the compilation process which can setup configurations such as this automatically. For Amani-sized projects this is not necessary.

Press OK on this menu and the previous menu and you’re good to go.

Step 5: Compiling the Project

After you are satisfied with your Verilog code and have set it as the top level entity, and have set unused pins as tri-stated inputs, you are ready to begin the compilation process. The simplest way to initiate compilation is to click the Start Compilation button (next to the Stop Sign) on the tool bar. You may also use menu Processing: Start Compilation or CTRL-L.

You will see messages begin to scroll in the Message Window as well as status bars incrementing in the Tasks Window.

The default compilation process in Quartus II iterates through four stages: Synthesis, Fitting, Assembly and Timing Analysis. The Synthesis stage is the actual compilation of your HDL code and other design files into logic elements to fit into the CPLD. The Fitter takes these logic elements finds the best “fit” into the target device. The Assembler generates the design files needed to program the device, such as the .POF file. The Timing Analysis stage checks the timing of various signal paths through the device and makes sure no signal’s propagation will make it “miss the bus.”

During the design and revision process you can execute any of these stages individually. More detailed explanations will be addressed in later modules as well as being available in the animated Quartus II tutorials available in the Help menu.

Once the compilation completes hopefully a pop-up will say “Full Compilation was Successful” with (4 Warnings). Take time, if you like, to peruse the Messages window took see all that took place during the compilation process. You do not have to understand everything at this point. Warnings are in blue, and generally should be noted. Warning explanations will come in later modules.

No errors occurred which would have halted the compilation process. If curious, try deleting a parentheses from the Verilog code and rerun the compilation. Double click the first error in the message window and you will be taken to the faulty line of code. Replace the parentheses and compile again.

In the workspace you will see the Flow Summary. Notice that we have used 32 of our available 64 macrocells, or half the chip’s resources. Why so much for such a simple code? The answer lies in the size of the counter register we are using, 24-bits. CPLD’s are better suited for high-resolution, macro-timing applications. I have created a VGA driver on the Amani that uses the same amount of macrocells as AmaniBlink! Making an LED blink at one second using a 32MHz clock is taxing on CPLD logic resources. The easiest solution to reducing AmaniBlink resource usage is to use a much lower frequency clock connected to another I/O pin and using a far smaller counter register.

Congratulations! You have successfully entered your design and compiled it. You’re almost there, you must now Assign input/output pins and load the design onto your Amani.

Module C: Assigning Pins and Programming the CPLD

Appendix A: AmaniBlink.v Verilog Description

The purpose of AmaniBlink.v is simple; make an LED blink at a one second interval. This is accomplished by counting the on-board 32MHz clock pulses and toggling the LED pin every half-second. 0.5 seconds ON, 0.5 seconds off. Thus the device must toggle the LED pin status every 16 million clock pulses.

Code breakdown:

module AmaniBlink(clk_32, LED); This line defines the module that will consist of all code following until endmodule. It defines two signals inherent to the module: clk_32 which is to be our 32MHz clock, and LED which will be our LED driving output.

input clk_32;
output LED;
These two lines define the two declared signals as input or output, setting their data direction.

reg LED; Creates a register for the LED output. A register is a logic element with “memory.” Think of a register as a logic element that changes state only when given permission. The output state of the register can be set, the output of which will remain constant while the various input drivers may change state. These input drivers will only affect the the output state once a clock or setting signal will enable the input to propagate to the output.

reg [23:0] counter; Creates a 24-bit register called “counter.” This will be the register that counts to 16 million, 24-bit binary equivalent 111101000010010000000000. That’s one large counter!

always @(posedge clk_32) This statement forces the subsequent nested logic to occur at every leading or positive edge of our system clock, clk_32. In other words, every tick.

if (counter == 16000000) Here we define an if statement, the entry conditions of which being that our counter register must equal 16 million, or 0.5 seconds.

If the entry conditions of the above if statement are met, the following two nested actions occur. Keep in mind they occur simultaneously at the same clock tick!

counter <= 0; Resets our counter to zero. This occurs because 16 million ticks have passed.
LED <= ~LED; Toggles the LED driver to its opposite state. From OFF to ON or ON to OFF.

else counter <= counter + 1; If the entry conditions of the above if statement were not met, IE counter does not equal 16 million, then we simply allow the counter to increment by one this clock cycle. This is the engine that drives the timer which is reset above every 16 million clock ticks.

endmodule The defines the end of module AmaniBlink.

As you can see Verilog HDL can be simple to use. RTL (register transfer level) programming is rather different than sequential processor-based languages such as C or Processing in that all lines of code have the potential to occur simultaneously.