From f0da5a6fa21c867e565187f833049997c1637266 Mon Sep 17 00:00:00 2001 From: chiplukes <34627158+chiplukes@users.noreply.github.com> Date: Sat, 5 Oct 2024 02:07:42 -0600 Subject: [PATCH] Fix Icarus cosimulation vpi bug for static signals (#444) * created a test that shows the cosimulation bug * fix icarus vpi so that all to_myhdl signals are updated at least once even if they are static --- cosimulation/icarus/myhdl.c | 4 +- cosimulation/icarus/test/const_1.py | 12 +++ .../icarus/test/test_initial_value_bug.py | 46 +++++++++++ cosimulation/test/test_const_1.py | 80 +++++++++++++++++++ cosimulation/test/verilog/const_1.v | 8 ++ cosimulation/test/verilog/dut_const_1.v | 13 +++ 6 files changed, 162 insertions(+), 1 deletion(-) create mode 100644 cosimulation/icarus/test/const_1.py create mode 100644 cosimulation/icarus/test/test_initial_value_bug.py create mode 100644 cosimulation/test/test_const_1.py create mode 100644 cosimulation/test/verilog/const_1.v create mode 100644 cosimulation/test/verilog/dut_const_1.v diff --git a/cosimulation/icarus/myhdl.c b/cosimulation/icarus/myhdl.c index 80a24366..89192a83 100644 --- a/cosimulation/icarus/myhdl.c +++ b/cosimulation/icarus/myhdl.c @@ -201,7 +201,9 @@ static PLI_INT32 to_myhdl_calltf(PLI_BYTE8 *user_data) { strcat(buf, " "); sprintf(s, "%d ", vpi_get(vpiSize, net_handle)); strcat(buf, s); - changeFlag[i] = 0; + // initialize this to one such that Verilog signals that never + // change at least update the connected MyHDL Signal once + changeFlag[i] = 1; id = malloc(sizeof(int)); *id = i; cb_data_s.user_data = (PLI_BYTE8 *) id; diff --git a/cosimulation/icarus/test/const_1.py b/cosimulation/icarus/test/const_1.py new file mode 100644 index 00000000..0518139d --- /dev/null +++ b/cosimulation/icarus/test/const_1.py @@ -0,0 +1,12 @@ +import os + +from myhdl import Cosimulation + +cmd = "iverilog -o const_1.o " + \ + "../../test/verilog/const_1.v " + \ + "../../test/verilog/dut_const_1.v " + +def const_1(q, clk): + os.system(cmd) + return Cosimulation("vvp -m ../myhdl.vpi const_1.o", **locals()) + diff --git a/cosimulation/icarus/test/test_initial_value_bug.py b/cosimulation/icarus/test/test_initial_value_bug.py new file mode 100644 index 00000000..62fd1057 --- /dev/null +++ b/cosimulation/icarus/test/test_initial_value_bug.py @@ -0,0 +1,46 @@ +# This file is part of the myhdl library, a Python package for using +# Python as a Hardware Description Language. +# +# Copyright (C) 2003-2008 Jan Decaluwe +# +# The myhdl library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation; either version 2.1 of the +# License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. + +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +""" Run cosimulation unit tests. """ + + +import sys + +sys.path.append("../../test") +#sys.path.append("../../../example/manual") + +import test_const_1 + +modules = (test_const_1 ) + +import unittest + +tl = unittest.defaultTestLoader +def suite(): + alltests = unittest.TestSuite() + alltests.addTest(tl.loadTestsFromModule(test_const_1)) + return alltests + +def main(): + unittest.main(defaultTest='suite', + testRunner=unittest.TextTestRunner(verbosity=2)) + + +if __name__ == '__main__': + main() diff --git a/cosimulation/test/test_const_1.py b/cosimulation/test/test_const_1.py new file mode 100644 index 00000000..475018ba --- /dev/null +++ b/cosimulation/test/test_const_1.py @@ -0,0 +1,80 @@ +import unittest +from unittest import TestCase +import random +from random import randrange +random.seed(2) + +from myhdl import Simulation, StopSimulation, Signal, \ + delay, intbv, negedge, posedge, now + +from const_1 import const_1 + +ACTIVE_LOW, INACTIVE_HIGH = 0, 1 + +class TestConst(TestCase): + + vals = [randrange(2) for i in range(1000)] + + def clkGen(self, clk): + while 1: + yield delay(10) + clk.next = not clk + + + def stimulus(self, clk): + for v in self.vals: + yield negedge(clk) + raise StopSimulation + + + def check(self, q, clk): + for v in self.vals: + yield posedge(clk) + self.assertEqual(q, 1) + + + def bench(self): + + # Note: when this is initialized different (ie: 0) than the constant value of q (1) + # the cosimulation never updates the signal q and the assertion in check fails + q, clk = [Signal(intbv(0)) for i in range(2)] + + CONST_1 = const_1(q, clk) + CLK_1 = self.clkGen(clk) + ST_1 = self.stimulus(clk) + CH_1 = self.check(q, clk) + + sim = Simulation(CONST_1, CLK_1, ST_1, CH_1) + return sim + + + def test1(self): + """ const test """ + sim = self.bench() + sim.run(quiet=1) + + + def test2(self): + """ const test with simulation suspends """ + sim = self.bench() + while sim.run(duration=randrange(1,5), quiet=1): + pass + + +if __name__ == '__main__': + unittest.main() + + + + + + + + + + + + + + + diff --git a/cosimulation/test/verilog/const_1.v b/cosimulation/test/verilog/const_1.v new file mode 100644 index 00000000..2bade8c8 --- /dev/null +++ b/cosimulation/test/verilog/const_1.v @@ -0,0 +1,8 @@ +module const_1(q, clk); + + input clk; + output q; + + wire q = 1; + +endmodule // inc diff --git a/cosimulation/test/verilog/dut_const_1.v b/cosimulation/test/verilog/dut_const_1.v new file mode 100644 index 00000000..631e271e --- /dev/null +++ b/cosimulation/test/verilog/dut_const_1.v @@ -0,0 +1,13 @@ +module dut_const_1; + + reg clk; + wire q; + + initial begin + $from_myhdl(clk); + $to_myhdl(q); + end + + const_1 dut (.q(q), .clk(clk) ); + +endmodule // inc