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:

Verilog HDL syntax error at <file_name>.v(<line_number>) near text: “<random_word>”... Check for and fix any syntax errors that appear immediately before or at the specified keyword.

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:

Verilog HDL syntax error at <file_name>.v(<line_number>) near text: “<random_word>”: expecting “;”. 

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.

module MAJ(a, b, c, m);
    input a, b, c;
    output m;

    and a1(ab, a, b);
    and a2(ac, a, c);
    and a3(bc, b, c);
    or o(m, ab, ac, bc);
endmodule

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

Error (10170): Verilog HDL syntax error at [file_name.v] line [line_number] near text: "[port_name]";  expecting "[expected_type]". Check that the port widths match between the module definition and the instantiation.

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.

module CLA(
    input [3:0] a,      // 4-bit input a
    input [3:0] b,      // 4-bit input b
    input cin,          // Carry input
    output [3:0] sum,   // 4-bit sum output
    output cout         // Carry output
);

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

reg [1:0] a;
reg [3:0] b;
reg cin;
wire [3:0] sum;
wire cout;

CLA dut(.a(a),
        .b(b),
        .cin(cin),
        .sum(sum),
        .cout(cout));

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

Error: [file_name.v]: Line [line_number]: Cannot connect ports by both name and order in instantiation of '[module_name]'

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:

// By Name
CLA dut1(.b(y),
        .a(x),
        .cin(bin),
        .sum(bum),
        .cout(dout));
        
// By Order
CLA dut2(x, 
        y,
        bin,
        bum,
        dout);

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.

CLA dut1(x,
        .b(y),
        bin,
        .sum(bum),
        .cout(dout));

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

Error (10028): [file_name.v](line_number): Object "[object_name]" on the left-hand side of assignment must be a variable type (reg, integer, time, real, etc.)

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.

always@(*) begin 
    a = b * 4 + c;
end

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

Error (10028): Can't resolve multiple constant drivers for net "[net_name]" at [file_name.v](line_number)

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