Cosimulation output port conflict (X) (original) (raw)

October 2, 2024, 6:54pm 1

Hello,

I have a very simple blink module as follows:

@block
def Blink(clk:SignalType, rst:ResetSignal, blink, enable, period):

    count = Signal(modbv(0)[20:])

    @always(clk.posedge)
    def logic():
        if enable:
            if count == period:
                count.next = 0
                blink.next = not blink
            else:
                count.next = count + 1
        if rst:
            count.next = 0

    return logic

And I am trying to cosimulate it with icarus verilog on windows. I would like to convert the myhdl description and then run the cosimulation on it as part of the same testcase as follows:

from blink import *

@block
def test(cosim=False):

    clk = Signal(bool(0))
    rst = Signal(bool(1))

    io_enable = Signal(bool(0))
    io_blink  = Signal(bool(0))

    # creating the dut
    dut = Blink(clk, rst, io_blink, io_enable, 100)

    # always converting in order to catch possible errors
    dut.convert(hdl='Verilog', trace=True)

    sources = [
        "Blink.v",
        "tb_Blink.v"]

    if cosim:
        cmd = ' '.join(["iverilog", '-o', 'test.o'] + sources)
        if(os.system(cmd) == 0):
            dut = Cosimulation("vvp -m ./myhdl test.o", clk=clk, rst=rst, enable=io_enable, blink=io_blink)

    # clock generation
    @always(delay(10))
    def clkgen():
        clk.next = not clk

    # stimulus generation
    @instance
    def stimulus():
        yield clk.posedge
        rst.next = 0
        io_enable.next = 1

        for i in range(1000):
            yield clk.posedge

        raise StopSimulation

    return clkgen, dut, stimulus

#########################################################

import os
import glob
import subprocess

def run(cosim=False, gui=False):
    os.chdir(get_abs_path("../sim"))

    clean()

    trace = True
    if cosim:
        trace = False

    i = test(cosim)
    i.config_sim(trace=trace, tracebackup=False)
    i.run_sim(quiet=1)

    if gui:
        subprocess.run(["gtkwave", "*.vcd"])


def clean():
    os.chdir(get_abs_path("../sim"))

    # List of extensions you want to delete
    extensions = ['*.vcd', '*.v', '*.o']

    # Loop through each extension and delete matching files
    for ext in extensions:
        for file_path in glob.glob(ext):
            if os.path.isfile(file_path):
                os.remove(file_path)
                print(f"Deleted: {file_path}")


if __name__ == "__main__":
    run(cosim=True, gui=True)

The simulation runs fine but my io_blink signal is in conflicted state, like both the verilog and the testcase were trying to drive it at the same time. Any idea what I might be doing wrong?

Allright I will reply to myself. Of course the root cause was a rookie mistake in my “blink” implementation, because I wasn’t resetting the blink output port. The problem however is that in GTKWAVE I see the signal as “X” (multiple drivers) while usually one would expect a “U” (undefined) in this situation, which was cause of confusion.

I wonder if this has to do with GTKWAVE or with Icarus Verilog, anyway, it all works ok for the rest.

josyb October 4, 2024, 7:51am 3

You can write blink as:

@block
def Blink(clk:SignalType, rst:ResetSignal, blink, enable, period):

    count = Signal(modbv(0)[20:])

    @always_seq(clk.posedge, reset=rst)
    def logic():
        if enable:
            if count == period:
                count.next = 0
                blink.next = not blink
            else:
                count.next = count + 1


    return logic

and declare rst = ResetSignal(0,1, isasync=False) in stead of rst = Signal(bool(1))

All outputs in the `logic()’ section will be nicely reset (to their initial value)