These slides are from older offerings of the course, but might still be useful to you. You are still responsible for material discussed in class and assigned in readings.
3 Other links
6 Example Verilog Designs
State machine (verilog) - this design contains a partial implementation of a MIPS multicycle control unit.
Recall that Lab 4 contains example code of clocked components, continuous components, and connected components built from instantiating subcomponents.
- Remember you can format numbers in Verilog in decimal, binary, or hexadecimal. By default they are assumed to be decimal:
reg [6:0] opcode; initial begin opcode = 33; //base 10 number, opcode will become 100 0001 //specify the bit length before the tick mark //specify the base afterwards d = decimal opcode = 7'd33; //does the same thing as above opcode = 7'h21; //puts the same number into opcode, but specfied in hex opcode 7'b1000001; //same number again, but fully binary end
- Quartus will create instantiation templates for you, which you can use to create larger components out of those you've already made (see the Lab 4 examples).
Create Verilog Instantiation Template Files for Current File:
Here I'm making a template for
Quartus will output some info into the console, and then it is finished. It gives you almost no feedback about this, so it might seem like it did nothing. In your windows file browser go to your project folder, you will see a new file called
<component_name>_inst.v, in my example it is called
You can open this in your text editor of choice, then copy paste the verilog code part that is the template into whatever other component you need it:
In this template you should change the instance name (
registerA_instin the verilog code). Then you should replace the input names (they all end in
_sigin the verilog).
To create an array
fooof multi-bit registers, declare some
regvariable like this example (which makes an array
foowhich is 8 16-bit registers):
reg [15:0] foo [7:0];
Here, the first set of brackets identifies the width of memory (bits per word), and the second identifies the depth (items in set). This is also done in the example memory verilog design above.
readmemhfunction assumes the input
memory.txtfile is in hexadecimal (hence the "h" in the function name). Make sure your input file is in hex, or you can use the similar functions for other formats (e.g.
The following verilog code may be helpful in creating test benches:
// use this if your design contains sequential logic parameter PERIOD = 20; parameter real DUTY_CYCLE = 0.5; initial // Clock process for CLK begin forever begin CLK = 1'b0; #(PERIOD-(PERIOD*DUTY_CYCLE)) CLK = 1'b1; #(PERIOD*DUTY_CYCLE); end end initial begin // Initialize Inputs // Wait one cycle for simulator to finish initializing #(PERIOD); // Enter test values end
To display the simulation time when printing in a test bench, you can use the
$timespecial variable. For example:
$display("At time %t, Q=%d", $time, Q);
You can pause your simulation at the end of a test bench by adding the
$stopkeyword. Put this after your last test:
initial begin //test inputs #(PERIOD); //check outputs $stop; end
You can use multiple of these keywords as breakpoints to pause the simulation after each test.
@function will cause your simulation to run until a specific signal takes on a certain value:
initial begin //test inputs @(OUTPUT == 7); //simulation will keep running until the output signal is correct //check outputs //new inputs @(ALUout != 16'0011); //simulation runs until ALUout is no longer the specific number //check outputs $stop end
If you are missing windows, or they are organized strangely you can always go to
Layout > Resetto move everything back to where it started.
While debugging you often want to change the radix of signals, hex is often easier to read than binary.
Radixoption, and select how you want to display the numbers. Think about when you want signed vs unsigned numbers! This screen shot shows the
osignal being set to hexadecimal.
- By default ModelSim displays the full path name to each signal being simulated, this gets long and clunky and hard to read:
Notice every signal in this image starts with
Note: If your waveform is in a separate window, instead go to
Tools > Window Preferencesto get to the same place.
Display Signal Pathsetting determines how deep the path name should go in the display:
- 0 means "display the full path"
- 1 means "display only the signal name"
- 2 means "display the signal name, and the component it is a part of"
This example sets the variable to a 1 therefore only the signal names show up in the waveform window now:
- When waveforms get full of many signals it can be hard to see individual wires, one thing that can help is changing the color of a particular signal.
Press the "Colors" button and select a color for the signal (I used Yellow in this case):
Then close the Color window, and press OK, the signal you selected will have the new color:
- When debugging it is often useful to investigate internal wires to larger components. DO NOT add extra outputs from components just to see them in the waveform.
In this screenshot the
counter_addercomponent is selected from inside of the
Select the component that contains the signal you are interested in by left clicking. Its wires and reg's will appear in the `Objects` window. You can right click these and add them to the waveform:
In this screenshot the
rwire from inside the
counter_addercomponent is being added to the waveform:
- It can be helpful to group signals in the waveform so you can hide signals you don't need during debugging.
there is a group for the
addersignals which is expanded, the
muxsignals are grouped but currently hidden, and the
registercomponent's signals are currently selected and about to be added to a group.
- You often will need to work with the same waveform on several sessions or want to share your waveform with teammates.
File > Load > Macro File...:
Select the ".do" file you want to load, you may need to change the "Files of type" setting to make it visible:
Press Open, and then run the simulation, your waveform should now have all the settings appropriately:
- You can change the Radix for memory, when you have the memory window open, right click in the window then select
Properties>Data Radixset it to hexadecimal.
8 Merge Conflicts (on Quartus Project files)
Merge conflicts will happen during development, they are not a bad thing, they are a sign of active and healthy work! This section will walk you through how to discard local changes to files you dont care about so that you can successfully pull from the repo.
NOTE: Doing this to any files totally DISCARDS local changes, with no way to get them back, so you should be careful about this with your verilog files. You can still follow these steps, just stop and think before you do so.
There is no danger of really harming the quartus project though, and conflicts on these files can be really annoying. A conflict can happen when two different users both change the same file. So, when do the project files change? There are 3 main times:
- You add new files to the project.
- You change the top-level entity on the project.
- You change some project settings.
These are really all trivial changes that can be reproduced, so no worry about "losing" any work if we did one of these and it caused a conflict.
If you do any of these things you should add, commit, and push the quartus project files to your repo.
NOTE: you really dont need to change the top-level entity, since we are only compiling in ModelSim for most of the quarter, just dont change it. In fact, you should not bother hitting the compile button in Quartus unless you absolutely have no other choice. Use ModelSim for debugging, not the very slow compile in Quartus.
So, I set up a quartus project called 'testing_gitignore'. I cloned this repo onto two different computers. On computer A I changed the top-level entity and then pushed my modified project files. On computer B I changed the top-level entity and then tried to pull, this caused this merge conflict:
Note the error in the red box.
I realize this is not a big deal, I can simply discard my computer B changes to the project file and change the top-level entity again later, if I want to.
So, I will 'checkout' the last version of the project files from the repo. This essentially 'undoes' all the changes to the files that I made since the last time I pulled:
git checkout HEAD -- the/file/name/to/revert.txt
If I did this to Verilog files which I had edited, then those changes I had made since my last successful pull are lost forever. But in this case, I dont care about my changes to the project file.
Next, I pull as usual:
The project files updated and I can now open the quartus project and edit it as usual.