Verilog: simulation gives errors but runs fine on FPGA

413 Views Asked by At

I'm trying to familiarize myself with (sub)modules in verilog and I am running into errors I cannot explain. I have these two files:

top.v:

parameter CLOCK_FREQUENCY = 24'd12_000_000;
parameter TRANSMISSION_LENGTH = 32;

`include "serialtx.v"

module top(
        input clk,
        output txd
    );
    
    reg wr;
    reg [TRANSMISSION_LENGTH - 1:0] data;
    reg busy;
    
    initial wr = 1'b0;
    initial data = 0;
    
    serialtx tx(
        .i_clk(clk),
        .i_wr(wr),
        .i_data(data),
        .o_txd(txd),
        .o_busy(busy)
    );
    
endmodule

serialtx.v:

module serialtx(
        input i_clk,
        input i_wr,
        input [TRANSMISSION_LENGTH - 1:0] i_data,
        output wire o_txd,
        output wire o_busy
    );
    
    initial o_busy = 1'b0;
    initial o_txd = 1'b1;
    
    always @(posedge i_clk)
    begin
        if (i_wr && !o_busy) begin
            o_busy <= 1'b1;
            o_txd <= 1'b0;
        end
    end
    
endmodule

To upload them to my ECP5 I use the following command flow:

yosys -p "synth_ecp5 -json top.json" top.v
nextpnr-ecp5 --json top.json --textcfg top_out.config --um5g-85k --package CABGA381 --lpf ecp5evn.lpf
ecppack --svf top.svf top_out.config top.bit
sudo --preserve-env=PATH env openocd -f ./ecp5.cfg -c "transport select jtag; init; svf top.svf; exit"

It uploads and works fine (there is a led connected to txd and it turns on/off accordingly to the initial o_txd = 1'bx statement in serialtx.v where x can be 1 or 0).

However, when I try to simulate the verilog code I get some errors. I cannot explain these errors since the error messages are chinese to me and the actual implementation works. This is the command I use:

verilator -Wall --trace -cc top.v

And this is the generated error log:

%Error-PROCASSWIRE: serialtx.v:9:10: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o_busy'
                                   : ... In instance top.tx
    9 |  initial o_busy = 1'b0;
      |          ^~~~~~
                    top.v:2:35: ... note: In file included from top.v
                    ... For error description see https://verilator.org/warn/PROCASSWIRE?v=4.215
%Error-PROCASSWIRE: serialtx.v:10:10: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o_txd'
                                    : ... In instance top.tx
   10 |  initial o_txd = 1'b1;
      |          ^~~~~
                    top.v:2:35: ... note: In file included from top.v
%Error-PROCASSWIRE: serialtx.v:15:4: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o_busy'
                                   : ... In instance top.tx
   15 |    o_busy <= 1'b1;
      |    ^~~~~~
                    top.v:2:35: ... note: In file included from top.v
%Error-PROCASSWIRE: serialtx.v:16:4: Procedural assignment to wire, perhaps intended var (IEEE 1800-2017 6.5): 'o_txd'
                                   : ... In instance top.tx
   16 |    o_txd <= 1'b0;
      |    ^~~~~
                    top.v:2:35: ... note: In file included from top.v
%Warning-UNUSED: top.v:13:6: Signal is not used: 'busy'
                           : ... In instance top
   13 |  reg busy;
      |      ^~~~
                 ... Use "/* verilator lint_off UNUSED */" and lint_on around source to disable this message.
%Warning-UNUSED: top.v:1:11: Parameter is not used: 'CLOCK_FREQUENCY'
                           : ... In instance top
    1 | parameter CLOCK_FREQUENCY = 24'd12_000_000;
      |           ^~~~~~~~~~~~~~~
%Warning-UNUSED: serialtx.v:4:37: Signal is not used: 'i_data'
                                : ... In instance top.tx
    4 |   input [TRANSMISSION_LENGTH - 1:0] i_data,
      |                                     ^~~~~~
                 top.v:2:35: ... note: In file included from top.v
%Error: Exiting due to 4 error(s), 3 warning(s)
        ... See the manual at https://verilator.org/verilator_doc.html for more assistance.

[EDIT] As I understand it, a procedural assignment is an update of the value of a register. Also, outputs are by default defined as wires and not as registers. So, it makes sense that the simulation throws an error. But how could this hardware ever run in the implementation then?

1

There are 1 best solutions below

6
On

Signals of type wire cannot be written procedurally (e.g., in always and initial blocks). Your synthesis tool should be throwing an error here (like the simulator does), presumably it just treats the signals as reg.

To solve this, change your output ports from wire to reg, like so:

output reg o_txd,
output reg o_busy