Very Simple Quick Quartus: Verilog

Please contact me if you find any errors or other problems (e.g., something is unclearly stated) in this web page

This document presents a (very) quick introduction to the use of Quartus to design a system using verilog.

The Basics
Running on hardware.
Adding a counter

The Basics

  1. Create a folder on your desktop for the files for this lab.
  2. Start Quartus (There should be an icon on the desktop, if not go to (Start Menu→All Programs→Intel FPGA...→Quartus (Quartus Prime 17.0)) and select "New Project Wizard". It may take some time to open.
  3. On the next page ("Directory, Name, Top-Level Entit]") choose the directory you just created and name the project "lab0" and hit "Next >". It is a good idea to have the name of the project the same as that of the top level entity, which you will create below). In the example below I used a directory called E15Lab2 in my GoogleDrive, and called the project (and top level entity) "cylon".

  4. Select "Empty Project" and hit "Next >" (from "Project Type").
  5. Hit "Next >" (from "Add Files").
  6. On the next page ("Family, Device & Board Settings"):
    1. Choose the "Board" tab.
    2. Choose "DE0-CV Development Board"

    3. hit "Next >"
  7. On the next page ("EDA Tool Settings"), under "Tool Type→Simulation" pick "ModelSim-Altera" for the "Tool name" and "Verilog HDL" for format.  Then hit "Next >".  (Note: this is only necessary for projects that you will be simulating; if you don't expect to simulate, you don't need to do this.  Also, if you only want to simulate, you can use ModelSim without doing a full compilation (that process is much faster).).
  8. Hit "Finish" ("Summary"). This may take a minute or two.
  9. From the Quartus main menu choose "File→New→Design Files→Verilog HDL File" then "OK"
  10. Create a file and call it "cylon.v" (module name is the same as file name).  This file is shown below.  It implements a half adder; it adds the bits labelled A and B into a sum (S) and carry out (cout). Don't worry if you don't understnad the syntax completely, you'll learn that soon. It is useful to think of the half adder module as a black box as shown at the left with inputs (A,B) at the top, and output (S, cout) at the bottom. We will write Verilog code for each module, and then connect modules together to form more complex functions. The "top level entity" is denoted by a pink box.
    Block Diagram Code
    module cylon(b, c, d, x);  // Implement a 'cylon' circuit
    input b, c, d;             // 3 bit input
    output [3:0]x;	            // 4 bit output(in a vector)
    assign x[0]= ~b & ~c & ~d;         // create logic for four led's
    assign x[1]= ~c & d;               //   as determined by karnaugh
    assign x[2]= (c & ~d) | (b & ~d);  //   maps.
    assign x[3]= c & d;                // 
  11. Note, this implements the same functionality as the circuit you designed last week.
    b c d   x[3] x[2] x[1] x[0]
    0 0 0   0 0 0 1
    0 0 1   0 0 1 0
    0 1 0   0 1 0 0
    0 1 1   1 0 0 0
    1 0 0   0 1 0 0
    1 0 1   0 0 1 0
  12. Add the file to your project. Go to Project→Add/Remove Files in Project... and add cylon.v and remove some extraneous files that we don't need (everything but DE0_CV_Default.sdc - if the .sdc file isn't there download it from the link and put it in the directory). The window should look like the one shown.

  13. Before moving forward we need to make the "cylon" module our top level entity - i.e., that part of the design with which we interact directly. To do this make sure that the "cylon.v" file is in the editing window and then go to Project→Set as Top Level Entity. Your window should look a bit like the one below.

  14. Go to Processing→Start→Analysis and Synthesis (or type ctrl-k).  This takes your code and generates a circuit that implements the desired functionality. After  a little wait you should get an message announcing success. You may get a warning like "Warning (18236): Number of processors has not been specified which may cause overloading on shared machines. Set the global assignment NUM_PARALLEL_PROCESSORS in your QSF to an appropriate value for best performance."


Note: Before simulation you must perform Analysis and Synthesis (previous section).

  1. First make sure the location of the simulator is properly set. Go to Tools→Options→EDA Tool Options and set the ModelSim directory.
  2. Go to File→New→Verification/Debugging Files→University Program VWF  (VWF = vector waveform file).
  3. When the "Simulation Waveform Editor" window appears click Edit→Insert→Node or Bus.
  4. When the "Insert Node or Bus" window  appears, click on Node Finder...
  5. When the "Node Finder" window appears, click on List
  6. Hit the ">>" button to move all nodes to selected nodes.  Hit OK.
  7. Hit OK to close "Insert Node or Bus".
  8. You should get a window like the one below.  It shows the inputs as 0, and the outputs as undefined (since we have not run the simulation). Note I hit the arrow near "x" in the "name" column to expand the vector.
  9. We first define the inputs.  Select the variable "b" on the left side of the window and then choose "Overwrite clock" () from the menu above the timing diagram.  Choose a 50 ns period and 50% duty cycle clock.  Hit OK.
  10. Now do the same for "c" but make it a 25 ns period (twice as fast as before). Also repeat for "d" at 12.5 ns. The variables b,c, d, are now set to count in binary.
  11. The resulting graph shows many more oscillations of the inputs than is necessary, so go to Edit→Set End Time and set the end time to 100 nS (0r 0.1 μS).

  12. Go to Simulation→Run Functional Simulation.  After some time the output should look like below.  Recall that we are using b,c,d, to represent a binary input to implement the table
    b c d   x[3] x[2] x[1] x[0]
    0 0 0   0 0 0 1
    0 0 1   0 0 1 0
    0 1 0   0 1 0 0
    0 1 1   1 0 0 0
    1 0 0   0 1 0 0
    1 0 1   0 0 1 0
    the cases where b,c,d = 1,1,0 and b,c,d = 1,1,1 were implemented as "don't cares" so we can ingnore them in the resulting simulation.

Running on Hardware

Now that we have simulated the circuit to verify that it operates properly, we want to actually create the circuit on the DE0 board. Download the E15DE0.qsf file into your working directory. (Note: Right-click on the link and choose "Save Link As..." If you open it and then save it, you will save the file in a format that cannot be properly read. This file has all the information needed to connect the internal circuitry of the FPGA to the hardware on the board.

Our new block diagram will like the one shown in the table below. The "top level entity now connect to the real world (inputs are switches "SW[0]" and "SW[1]", and outputs are "LEDR[0]" and "LEDR[1]". The switches are connected to the inputs of the module we just created, and the outputs of the module are connected to two LED's. In this case the connections are trivial. In general there can be multiple modules withing the "top level entity" and the connections will be more complicated.

  1. Go to File→New→Design Files→Verilog HDL File. Enter the text below into the file and save in a file "cySwitch.v". There are no rules about indenting - but be neat and be consistent. The names SW and LEDR must be entered exactly as shown since they correspond to physical locations on the DE0 board. The top level entity is a pink box. The black box is a module defined inside the top level module.
    Block Diagram Code
    module cySwitch(SW,LEDR);
    input [2:0]SW;     // SW[2], SW[1] and SW[0] are inputs
    output [3:0]LEDR;  // LED's are outputs 
    // instantiate the "cylon" circuit
    // inputs are SW[2], SW[1] and SW[0] (b, c, d)
    // outputs are the Red LED's (LEDR[3:0])
    	cylon myCy(SW[2], SW[1], SW[0], LEDR);
  2. To do this, go to Project→Add/Remove Files in Project...and add the "cySwitch.v" file to your project.
  3. Now make the "cySwitch" module the top level entity (i.e., the module with which we, as users, interact). To do this, go to Project→Set as Top Level Entity.
  4. Go to "Assignment→Import Assignments..." and choose the E15DE0.qsf file.  This should automatically assign the proper pins on the FPGA.
  5. Go to "ProcessingStart Compilation" (or hit the triangular "play" icon at the top of the window).  This may take a few minutes. You will get several warnings - ignore these for now.
  6. Make sure the DE0 board is turned on and connected to the computer through the USB port labeled "Blaster". Go to "Tools→Programmer" or choose the "Programmer" icon (). The "Hardware Setup" should show "USB-Blaster". 
  7. Your window should now look something like the one shown below.  If  so, hit "Start".  If the "USB-Blaster" is not listed by the "Hardware Setup" button,  you'll have to start by  setting up the hardware and follow the directions for "JTAG programming"
  8. If no file is listed we have to choose the file to be download.  Click on "Add File..." and and choose the .sof (SRAM Object File) file (this may be in a subdirectory named "output_files."  You'll also have to delete any lines without file.  When the dialog box resembles the one above,  hit "Start".  When finished, close the programmer window (and save the configuration - you'll be able to reuse this configuration later if desired).
  9. Your design is now running, with the inputs connected to SW[2], SW[1] and SW[0], and the output to LEDR[3] through LEDR[1]. Try all six pertinent positions for the switches and verify that you get the expected result.

Using a counter

Instead of using the switches as an input, you can add a counter to generate all possible inputs. At this point you don't have to worry about how the counter works (you'll do that in class soon).

  1. Now add the file "E15Counter1HzB.v" to your working directory There are 3 connections - a 50 MHz clock input, a four bit terminal count input and a four bit count number output. The counter output increments once a second starting from 0. After it counts to the terminal count it resets to zero. The count value is indicated by the 4 bit output.
  2. Create a file called "cyCount.v" file to look like the one below. A block diagram is also shown - multibit "buses" are shown as thick arrows. As implemented, the counter counts from 0 to 5. The signal "CLOCK_50" at the top of the board is a 50 MHz clock on the DE0 board.
    module cyCount(CLOCK_50,LEDR);
    input  CLOCK_50;   // 50 MHz clock input
    output [9:0]LEDR;  // LED's show input and output from "cylon"
    wire [3:0]Q;       // output from counter and input to cylon
       assign LEDR[9:7] = Q[2:0];    // output from counter and input to cylon
       assign LEDR[6:4] = 3'b0;      // turn off these LED's
       // Instantiate counter, max count = 5, output to Q.
       E15Counter1HzB myCounter(CLOCK_50, 4'd5, Q);  // count from 0 to 5.
       // "cylon" has input from Q[2:0], output to LEDR[3:0]
       cylon myCy(Q[2], Q[1], Q[0], LEDR[3:0]);

    Examine the code and the block diagram carefully and make sure you can explain how they are related.
  3. Add "E15Counter1HzB.v" and "cyCount.v" to your project, and set "cyCount.v" as the top level entity.
  4. Compile the file, download to the DE0 board and make sure it operates as expected.

Please contact me if you find any errors or other problems (e.g., something is unclearly stated) in this web page