Syntax Errors
Helping you 'register' the same errors as the synthesiser. Haha.
Verilog syntax errors may seem cryptic, so it is important to understand what the compiler/synthesizer is trying to indicate. A syntax error thrown by Quartus Prime typically has the following format:
In your specific error, <file_name>
would be the name of the file wherein the error occurred, <line_number>
would indicate the line number of the error in <file_name>
, and <random_word>
would point out the specific location of the error within line <line_number>
.
Here are some typical errors you may encounter, along with fixes for the same. This is not a comprehensive list, but covers most common cases. (Note that fixing one error may cause many more to appear—the compiler parses the file line by line so that is expected behavior.)
Expecting a character or word
One of the most common types of syntax errors is a missing character or word. For example, a missing semi colon would result in a error of the following form:
Adding a ‘;
’ in <random_line> of <file_name> should fix the above error.
Similar errors can occur for missing closing brackets, endmodules etc. To fix such errors, identify where the missing character or word needs to be added.
Missing module name in instantiation
Verilog modules describe pieces of hardware. Hence, whenever instantiating a module (analogous to instantiating a software class in many ways), we need to specify an instance name.
For example, let's review the code for a majority module MAJ with 3 inputs and 1 output.
Each of the and
gates is a module, which has to be given a unique name so that the compiler knows how to distinguish them. When only 1 instance of a module is called in a program, some compilers do not throw an error. However, it is good practice to name every module instantiation regardless.
Name the module instance specified by the error message to resolve the error.
Mismatched Port Width
Whenever a module is declared, the widths of its ports are also described. For example, below is the description of the ports of a 4-bit carry-lookahead adder.
Ports a,
b
and sum
are each 4 bits wide , while cin
and cout
are each 1 bit wide. Hence, when CLA
is instantiated, the wires
The above instantiation would likely throw an error because a 2 bit register a
has been connected to a 4 bit wide port. Editing the code to reg [1:0] a;
should fix the error.
Sometimes, mismatched port widths only trigger warnings (typically if the connected element is larger than the port width, in which case the MSB of the element is usually taken). These can result in undesired behaviour and should be avoided as well.
Ensure declared port widths of modules match widths of connected nets.
Referencing Ports by Name and Order
Now, there are two broad ways of connecting ports when instantiating modules: by name, and by order. Consider the CLA module declared above. Here's how one could instantiate it:
When instantiating a module by name, we explicitly state which port each element is connected to. For example, in dut1
, x
and y
are explicitly connected to ports a
and b
respectively.
Whereas in dut2
, the connection is implicit—because ports a
, b
, cin
, sum
, and cout
were declared in that specific order, they are connected to x
, y
, bin
, bum
, and dout
, respectively.
Instantiating ports by name is better practice due to improved readability and less chance of making an error. Nevertheless, both are valid.
The issue arises when an instantiation uses both methods of connecting ports.
This isn't allowed because it creates a lot of ambiguity. Hence, the above error is thrown. Fixing the instantiation to connect ports by either name or order should resolve it.
Connect ports by either name or order—not both!
Object on the left hand side must be a variable type
The object types we deal with in EECS 270 are reg
and wire
. A reg
is an object that can store its value across multiple 'time steps'. It is not equivalent to a hardware register, but can be understood to have 'memory' of some form. A wire
, on the other hand, has no memory, and is constantly assigned a value. It gets this value by either being an output of a module, or on the LHS of an assign
statement.
This means a reg
can be assigned a value inside an always block (or task or function, but those are outside the scope of this course), while a wire
cannot. The reason—an always block contains code that is run whenever some variable(s) is/are changed.
For example, the code in the above block will be executed whenever any value on the RHS (i.e. b
or c
) changes. This requires a
to retain its value, which it cannot do if it is a wire
.
Hence, in order to resolve the above error, the offending object should be modified to be declared as a reg
.
When assigning values to an object in an always
block, make sure it declared as a reg.
Cannot resolve multiple constant drivers
An object can only be assigned one value at any point in time.
Ensure net_name
is not assigned multiple values (either through assign statements or as the output of a module).
This also means a net can't be assigned a value in more than 1 always
block.
Illegal Assignment
This means you have selected the wrong board to synthesise the program for. Selecting the correct one should resolve the error.
Top Level Not Found
Ensure the top level module name matches the name of the module you intend to have as the top level. The name of the file does not matter—only the module name does.
Last updated