From 31abe537a0c34d4e7605bcf3a460928e7afd40e6 Mon Sep 17 00:00:00 2001 From: Geza Lore Date: Thu, 21 Jul 2022 17:34:12 +0100 Subject: [PATCH] Fix DPI export trigger sensitivity in 'nba' Fixes #3508 --- src/V3Sched.cpp | 48 +++++++++++++------------ test_regress/t/t_order_dpi_export_8.cpp | 16 +++++++++ test_regress/t/t_order_dpi_export_8.pl | 22 ++++++++++++ test_regress/t/t_order_dpi_export_8.v | 48 +++++++++++++++++++++++++ 4 files changed, 112 insertions(+), 22 deletions(-) create mode 100644 test_regress/t/t_order_dpi_export_8.cpp create mode 100755 test_regress/t/t_order_dpi_export_8.pl create mode 100644 test_regress/t/t_order_dpi_export_8.v diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index a65cdd008..c795426fd 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -416,21 +416,6 @@ struct TriggerKit { VL_UNCOPYABLE(TriggerKit); - // Create an AstSenTree that is sensitive to the given trigger index. Must not exist yet! - AstSenTree* createTriggerSenTree(AstNetlist* netlistp, uint32_t index) const { - AstTopScope* const topScopep = netlistp->topScopep(); - FileLine* const flp = topScopep->fileline(); - AstVarRef* const vrefp = new AstVarRef{flp, m_vscp, VAccess::READ}; - AstCMethodHard* const callp - = new AstCMethodHard{flp, vrefp, "at", new AstConst{flp, index}}; - callp->dtypeSetBit(); - callp->pure(true); - AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_TRUE, callp}; - AstSenTree* const resultp = new AstSenTree{flp, senItemp}; - topScopep->addSenTreep(resultp); - return resultp; - } - // Utility that assigns the given index trigger to fire when the given variable is zero void addFirstIterationTriggerAssignment(AstVarScope* counterp, uint32_t index) const { FileLine* const flp = counterp->fileline(); @@ -459,6 +444,20 @@ struct TriggerKit { } }; +// Create an AstSenTree that is sensitive to the given trigger index. Must not exist yet! +AstSenTree* createTriggerSenTree(AstNetlist* netlistp, AstVarScope* const vscp, uint32_t index) { + AstTopScope* const topScopep = netlistp->topScopep(); + FileLine* const flp = topScopep->fileline(); + AstVarRef* const vrefp = new AstVarRef{flp, vscp, VAccess::READ}; + AstCMethodHard* const callp = new AstCMethodHard{flp, vrefp, "at", new AstConst{flp, index}}; + callp->dtypeSetBit(); + callp->pure(true); + AstSenItem* const senItemp = new AstSenItem{flp, VEdgeType::ET_TRUE, callp}; + AstSenTree* const resultp = new AstSenTree{flp, senItemp}; + topScopep->addSenTreep(resultp); + return resultp; +} + //============================================================================ // Utility for extra trigger allocation @@ -727,7 +726,8 @@ void createSettle(AstNetlist* netlistp, SenExprBuilder& senExprBulider, invertAndMergeSenTreeMap(trigToSen, trig.m_map); // First trigger is for pure combinational triggers (first iteration) - AstSenTree* const inputChanged = trig.createTriggerSenTree(netlistp, firstIterationTrigger); + AstSenTree* const inputChanged + = createTriggerSenTree(netlistp, trig.m_vscp, firstIterationTrigger); // Create and the body function AstCFunc* const stlFuncp = V3Order::order( @@ -800,11 +800,12 @@ AstNode* createInputCombLoop(AstNetlist* netlistp, SenExprBuilder& senExprBuilde invertAndMergeSenTreeMap(trigToSen, trig.m_map); // The trigger top level inputs (first iteration) - AstSenTree* const inputChanged = trig.createTriggerSenTree(netlistp, firstIterationTrigger); + AstSenTree* const inputChanged + = createTriggerSenTree(netlistp, trig.m_vscp, firstIterationTrigger); // The DPI Export trigger AstSenTree* const dpiExportTriggered - = trig.createTriggerSenTree(netlistp, dpiExportTriggerIndex); + = createTriggerSenTree(netlistp, trig.m_vscp, dpiExportTriggerIndex); // Create and Order the body function AstCFunc* const icoFuncp @@ -1077,13 +1078,13 @@ void schedule(AstNetlist* netlistp) { invertAndMergeSenTreeMap(trigToSenAct, actTrigMap); // The DPI Export trigger AstSenTree - AstSenTree* const dpiExportTriggered - = actTrig.createTriggerSenTree(netlistp, dpiExportTriggerIndex); + AstSenTree* const dpiExportTriggeredAct + = createTriggerSenTree(netlistp, actTrig.m_vscp, dpiExportTriggerIndex); AstCFunc* const actFuncp = V3Order::order( netlistp, {&logicRegions.m_pre, &logicRegions.m_act, &logicReplicas.m_act}, trigToSenAct, "act", false, false, [=](const AstVarScope* vscp, std::vector& out) { - if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggered); + if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggeredAct); }); splitCheck(actFuncp); if (v3Global.opt.stats()) V3Stats::statsStage("sched-create-act"); @@ -1098,10 +1099,13 @@ void schedule(AstNetlist* netlistp) { std::unordered_map trigToSenNba; invertAndMergeSenTreeMap(trigToSenNba, nbaTrigMap); + AstSenTree* const dpiExportTriggeredNba + = createTriggerSenTree(netlistp, nbaTrigVscp, dpiExportTriggerIndex); + AstCFunc* const nbaFuncp = V3Order::order( netlistp, {&logicRegions.m_nba, &logicReplicas.m_nba}, trigToSenNba, "nba", v3Global.opt.mtasks(), false, [=](const AstVarScope* vscp, std::vector& out) { - if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggered); + if (vscp->varp()->isWrittenByDpi()) out.push_back(dpiExportTriggeredNba); }); splitCheck(nbaFuncp); netlistp->evalNbap(nbaFuncp); // Remember for V3LifePost diff --git a/test_regress/t/t_order_dpi_export_8.cpp b/test_regress/t/t_order_dpi_export_8.cpp new file mode 100644 index 000000000..9cf6361c7 --- /dev/null +++ b/test_regress/t/t_order_dpi_export_8.cpp @@ -0,0 +1,16 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2022 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 +// +//************************************************************************* + +#include + +#include + +void call_set_x(svBit val) { set_x(val); } diff --git a/test_regress/t/t_order_dpi_export_8.pl b/test_regress/t/t_order_dpi_export_8.pl new file mode 100755 index 000000000..2c9b6e9f0 --- /dev/null +++ b/test_regress/t/t_order_dpi_export_8.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +compile( + verilator_flags2 => ["--exe", "$Self->{t_dir}/$Self->{name}.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_order_dpi_export_8.v b/test_regress/t/t_order_dpi_export_8.v new file mode 100644 index 000000000..2df1a3e9b --- /dev/null +++ b/test_regress/t/t_order_dpi_export_8.v @@ -0,0 +1,48 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2022 by Geza Lore. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +module testbench( + /*AUTOARG*/ + // Inputs + clk + ); + + input clk; // Top level input clock + + bit x = 0; + + wire y = x & $c(1); + + export "DPI-C" function set_x; + function void set_x(bit val); + x = val; + endfunction; + + import "DPI-C" context function void call_set_x(bit val); + + bit q = 0; + always @(posedge clk) q <= ~q; + + always @(edge q) call_set_x(q); + + int n = 0; + + always @(edge clk) begin + // This always block needs to evaluate before the NBA to even_other + // above is committed, as setting clocks via the set_other_clk uses + // blocking assignment. + $display("t=%t q=%d x=%d y=%d", $time, q, x, y); + if (y !== q) $stop; + if (n == 20) begin + $write("*-* All Finished *-*\n"); + $finish; + end + n += 1; + end + +endmodule