Support `std::semaphore` and typed `std::mailbox` (#3708)

Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
This commit is contained in:
Krzysztof Bieganski 2022-11-28 16:53:55 +01:00 committed by GitHub
parent 4452a9b10f
commit 68e1b473e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 329 additions and 82 deletions

106
include/std.sv Normal file
View File

@ -0,0 +1,106 @@
// DESCRIPTION: Verilator: built-in packages and classes
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2022 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
//
//*************************************************************************
// verilator lint_off DECLFILENAME
// verilator lint_off TIMESCALEMOD
// verilator lint_off UNUSEDSIGNAL
package std;
class mailbox #(type T);
protected int m_bound;
protected T m_queue[$];
function new(int bound = 0);
m_bound = bound;
endfunction
function int num();
return m_queue.size();
endfunction
task put(T message);
`ifdef VERILATOR_TIMING
if (m_bound != 0)
wait (m_queue.size() < m_bound);
m_queue.push_back(message);
`endif
endtask
function int try_put(T message);
if (num() < m_bound) begin
m_queue.push_back(message);
return 1;
end
return 0;
endfunction
task get(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
message = m_queue.pop_front();
`endif
endtask
function int try_get(ref T message);
if (num() > 0) begin
message = m_queue.pop_front();
return 1;
end
return 0;
endfunction
task peek(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
message = m_queue[0];
`endif
endtask
function int try_peek(ref T message);
if (num() > 0) begin
message = m_queue[0];
return 1;
end
return 0;
endfunction
endclass
class semaphore;
protected int m_keyCount;
function new(int keyCount = 0);
m_keyCount = keyCount;
endfunction
function void put(int keyCount = 1);
m_keyCount += keyCount;
endfunction
task get(int keyCount = 1);
`ifdef VERILATOR_TIMING
wait (m_keyCount >= keyCount);
m_keyCount -= keyCount;
`endif
endtask
function int try_get(int keyCount = 1);
if (m_keyCount >= keyCount) begin
m_keyCount -= keyCount;
return 1;
end
return 0;
endfunction
endclass
endpackage
// verilator lint_off IMPORTSTAR
import std::*;

View File

@ -1086,6 +1086,7 @@ class AstNetlist final : public AstNode {
AstTypeTable* const m_typeTablep; // Reference to top type table, for faster lookup AstTypeTable* const m_typeTablep; // Reference to top type table, for faster lookup
AstConstPool* const m_constPoolp; // Reference to constant pool, for faster lookup AstConstPool* const m_constPoolp; // Reference to constant pool, for faster lookup
AstPackage* m_dollarUnitPkgp = nullptr; // $unit AstPackage* m_dollarUnitPkgp = nullptr; // $unit
AstPackage* m_stdPackagep = nullptr; // SystemVerilog std package
AstCFunc* m_evalp = nullptr; // The '_eval' function AstCFunc* m_evalp = nullptr; // The '_eval' function
AstCFunc* m_evalNbap = nullptr; // The '_eval__nba' function AstCFunc* m_evalNbap = nullptr; // The '_eval__nba' function
AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable AstVarScope* m_dpiExportTriggerp = nullptr; // The DPI export trigger variable
@ -1119,6 +1120,8 @@ public:
void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; } void dpiExportTriggerp(AstVarScope* varScopep) { m_dpiExportTriggerp = varScopep; }
AstVar* delaySchedulerp() const { return m_delaySchedulerp; } AstVar* delaySchedulerp() const { return m_delaySchedulerp; }
void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; } void delaySchedulerp(AstVar* const varScopep) { m_delaySchedulerp = varScopep; }
void stdPackagep(AstPackage* const packagep) { m_stdPackagep = packagep; }
AstPackage* stdPackagep() const { return m_stdPackagep; }
AstTopScope* topScopep() const { return m_topScopep; } AstTopScope* topScopep() const { return m_topScopep; }
void createTopScope(AstScope* scopep); void createTopScope(AstScope* scopep);
VTimescale timeunit() const { return m_timeunit; } VTimescale timeunit() const { return m_timeunit; }

View File

@ -63,6 +63,13 @@ void V3Global::readFiles() {
"Cannot find file containing module: "); "Cannot find file containing module: ");
} }
if (usesStdPackage()) {
// Parse the std package
parser.parseFile(new FileLine{FileLine::commandLineFilename()},
V3Options::getStdPackagePath(), false,
"Cannot find std.sv containing built-in std:: definitions: ");
}
// Read libraries // Read libraries
// To be compatible with other simulators, // To be compatible with other simulators,
// this needs to be done after the top file is read // this needs to be done after the top file is read

View File

@ -107,6 +107,7 @@ class V3Global final {
bool m_dpi = false; // Need __Dpi include files bool m_dpi = false; // Need __Dpi include files
bool m_hasEvents = false; // Design uses SystemVerilog named events bool m_hasEvents = false; // Design uses SystemVerilog named events
bool m_hasClasses = false; // Design uses SystemVerilog classes bool m_hasClasses = false; // Design uses SystemVerilog classes
bool m_usesStdPackage = false; // Design uses the std package
bool m_usesTiming = false; // Design uses timing constructs bool m_usesTiming = false; // Design uses timing constructs
bool m_hasForceableSignals = false; // Need to apply V3Force pass bool m_hasForceableSignals = false; // Need to apply V3Force pass
bool m_hasSCTextSections = false; // Has `systemc_* sections that need to be emitted bool m_hasSCTextSections = false; // Has `systemc_* sections that need to be emitted
@ -152,6 +153,8 @@ public:
void setHasEvents() { m_hasEvents = true; } void setHasEvents() { m_hasEvents = true; }
bool hasClasses() const { return m_hasClasses; } bool hasClasses() const { return m_hasClasses; }
void setHasClasses() { m_hasClasses = true; } void setHasClasses() { m_hasClasses = true; }
bool usesStdPackage() const { return m_usesStdPackage; }
void setUsesStdPackage() { m_usesStdPackage = true; }
bool usesTiming() const { return m_usesTiming; } bool usesTiming() const { return m_usesTiming; }
void setUsesTiming() { m_usesTiming = true; } void setUsesTiming() { m_usesTiming = true; }
bool hasForceableSignals() const { return m_hasForceableSignals; } bool hasForceableSignals() const { return m_hasForceableSignals; }

View File

@ -50,6 +50,7 @@ private:
using ImplTypedefMap = std::map<const std::pair<void*, std::string>, AstTypedef*>; using ImplTypedefMap = std::map<const std::pair<void*, std::string>, AstTypedef*>;
// STATE // STATE
AstPackage* const m_stdPackagep; // SystemVerilog std package
AstVar* m_varp = nullptr; // Variable we're under AstVar* m_varp = nullptr; // Variable we're under
ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name> ImplTypedefMap m_implTypedef; // Created typedefs for each <container,name>
std::unordered_set<FileLine*> m_filelines; // Filelines that have been seen std::unordered_set<FileLine*> m_filelines; // Filelines that have been seen
@ -600,6 +601,11 @@ private:
VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep);
} }
} }
void visit(AstClassOrPackageRef* nodep) override {
if (nodep->name() == "std" && !nodep->classOrPackagep()) {
nodep->classOrPackagep(m_stdPackagep);
}
}
void visit(AstNode* nodep) override { void visit(AstNode* nodep) override {
// Default: Just iterate // Default: Just iterate
@ -609,7 +615,10 @@ private:
public: public:
// CONSTRUCTORS // CONSTRUCTORS
explicit LinkParseVisitor(AstNetlist* rootp) { iterate(rootp); } explicit LinkParseVisitor(AstNetlist* rootp)
: m_stdPackagep{rootp->stdPackagep()} {
iterate(rootp);
}
~LinkParseVisitor() override = default; ~LinkParseVisitor() override = default;
}; };

View File

@ -706,6 +706,8 @@ string V3Options::getenvVERILATOR_ROOT() {
return var; return var;
} }
string V3Options::getStdPackagePath() { return getenvVERILATOR_ROOT() + "/include/std.sv"; }
string V3Options::getSupported(const string& var) { string V3Options::getSupported(const string& var) {
// If update below, also update V3Options::showVersion() // If update below, also update V3Options::showVersion()
if (var == "COROUTINES" && coroutineSupport()) { if (var == "COROUTINES" && coroutineSupport()) {

View File

@ -666,6 +666,7 @@ public:
static string getenvSYSTEMC_INCLUDE(); static string getenvSYSTEMC_INCLUDE();
static string getenvSYSTEMC_LIBDIR(); static string getenvSYSTEMC_LIBDIR();
static string getenvVERILATOR_ROOT(); static string getenvVERILATOR_ROOT();
static string getStdPackagePath();
static string getSupported(const string& var); static string getSupported(const string& var);
static bool systemCSystemWide(); static bool systemCSystemWide();
static bool systemCFound(); // SystemC installed, or environment points to it static bool systemCFound(); // SystemC installed, or environment points to it

View File

@ -532,14 +532,17 @@ void V3ParseImp::tokenPipelineSym() {
&& (*(yylval.strp) == "mailbox" // IEEE-standard class && (*(yylval.strp) == "mailbox" // IEEE-standard class
|| *(yylval.strp) == "process" // IEEE-standard class || *(yylval.strp) == "process" // IEEE-standard class
|| *(yylval.strp) == "semaphore")) { // IEEE-standard class || *(yylval.strp) == "semaphore")) { // IEEE-standard class
v3Global.setUsesStdPackage();
yylval.scp = nullptr; yylval.scp = nullptr;
if (token == yaID__LEX) token = yaID__aTYPE; if (token == yaID__LEX) token = yaID__aTYPE;
} else { // Not found } else { // Not found
yylval.scp = nullptr; yylval.scp = nullptr;
if (token == yaID__CC) { if (token == yaID__CC) {
// IEEE does require this, but we may relax this as UVM breaks it, so allow bbox if (!m_afterColonColon && *(yylval.strp) == "std") {
// for today v3Global.setUsesStdPackage();
if (!v3Global.opt.bboxUnsup()) { } else if (!v3Global.opt.bboxUnsup()) {
// IEEE does require this, but we may relax this as UVM breaks it, so allow
// bbox for today
// We'll get a parser error eventually but might not be obvious // We'll get a parser error eventually but might not be obvious
// is missing package, and this confuses people // is missing package, and this confuses people
static int warned = false; static int warned = false;
@ -554,6 +557,7 @@ void V3ParseImp::tokenPipelineSym() {
} }
} }
} }
m_afterColonColon = token == yP_COLONCOLON;
yylval.token = token; yylval.token = token;
// effectively returns yylval // effectively returns yylval
} }

View File

@ -150,6 +150,7 @@ class V3ParseImp final {
VOptionBool m_unconnectedDrive; // Last unconnected drive VOptionBool m_unconnectedDrive; // Last unconnected drive
int m_lexPrevToken = 0; // previous parsed token (for lexer) int m_lexPrevToken = 0; // previous parsed token (for lexer)
bool m_afterColonColon = false; // The previous token was '::'
std::deque<V3ParseBisonYYSType> m_tokensAhead; // Tokens we parsed ahead of parser std::deque<V3ParseBisonYYSType> m_tokensAhead; // Tokens we parsed ahead of parser
std::deque<string*> m_stringps; // Created strings for later cleanup std::deque<string*> m_stringps; // Created strings for later cleanup

View File

@ -3291,6 +3291,16 @@ private:
VL_DANGLING(index_exprp); // May have been edited VL_DANGLING(index_exprp); // May have been edited
return VN_AS(nodep->pinsp(), Arg)->exprp(); return VN_AS(nodep->pinsp(), Arg)->exprp();
} }
void methodCallWarnTiming(AstMethodCall* const nodep, const std::string& className) {
if (v3Global.opt.timing().isSetFalse()) {
nodep->v3warn(E_NOTIMING,
className << "::" << nodep->name() << "() requires --timing");
} else if (!v3Global.opt.timing().isSetTrue()) {
nodep->v3warn(E_NEEDTIMINGOPT, "Use --timing or --no-timing to specify how "
<< className << "::" << nodep->name()
<< "() should be handled");
}
}
void methodCallClass(AstMethodCall* nodep, AstClassRefDType* adtypep) { void methodCallClass(AstMethodCall* nodep, AstClassRefDType* adtypep) {
// No need to width-resolve the class, as it was done when we did the child // No need to width-resolve the class, as it was done when we did the child
AstClass* const first_classp = adtypep->classp(); AstClass* const first_classp = adtypep->classp();
@ -3300,6 +3310,26 @@ private:
} }
UASSERT_OBJ(first_classp, nodep, "Unlinked"); UASSERT_OBJ(first_classp, nodep, "Unlinked");
for (AstClass* classp = first_classp; classp;) { for (AstClass* classp = first_classp; classp;) {
if (nodep->fileline()->timingOn()) {
if (classp->name() == "semaphore"
|| VString::startsWith(classp->name(), "mailbox")) {
// Find the package the class is in
AstNode* pkgItemp = classp;
while (pkgItemp->backp() && pkgItemp->backp()->nextp() == pkgItemp) {
pkgItemp = pkgItemp->backp();
}
AstPackage* const packagep = VN_CAST(pkgItemp->backp(), Package);
// Check if it's std
if (packagep && packagep->name() == "std") {
if (classp->name() == "semaphore" && nodep->name() == "get") {
methodCallWarnTiming(nodep, "semaphore");
} else if (nodep->name() == "put" || nodep->name() == "get"
|| nodep->name() == "peek") {
methodCallWarnTiming(nodep, "mailbox");
}
}
}
}
if (AstNodeFTask* const ftaskp if (AstNodeFTask* const ftaskp
= VN_CAST(classp->findMember(nodep->name()), NodeFTask)) { = VN_CAST(classp->findMember(nodep->name()), NodeFTask)) {
userIterate(ftaskp, nullptr); userIterate(ftaskp, nullptr);

View File

@ -1162,6 +1162,13 @@ package_declaration: // ==IEEE: package_declaration
packageFront<nodeModulep>: packageFront<nodeModulep>:
yPACKAGE lifetimeE idAny ';' yPACKAGE lifetimeE idAny ';'
{ $$ = new AstPackage{$<fl>3, *$3}; { $$ = new AstPackage{$<fl>3, *$3};
if ($$->name() == "std") {
if ($$->fileline()->filename() != V3Options::getStdPackagePath()) {
$$->v3error("Redeclaring the 'std' package is not allowed");
} else {
PARSEP->rootp()->stdPackagep(VN_AS($$, Package));
}
}
$$->inLibrary(true); // packages are always libraries; don't want to make them a "top" $$->inLibrary(true); // packages are always libraries; don't want to make them a "top"
$$->lifetime($2); $$->lifetime($2);
$$->modTrace(GRAMMARP->allTracingOn($$->fileline())); $$->modTrace(GRAMMARP->allTracingOn($$->fileline()));

View File

@ -1,6 +0,0 @@
%Error: t/t_mailbox.v:24:4: Can't find typedef: 'mailbox'
24 | mailbox #(int) m;
| ^~~~~~~
%Error: Internal Error: t/t_mailbox.v:24:14: ../V3LinkDot.cpp:#: Pin not under instance?
24 | mailbox #(int) m;
| ^~~

View File

@ -10,14 +10,19 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1); scenarios(simulator => 1);
compile( if (!$Self->have_coroutines) {
fails => $Self->{vlt_all}, skip("No coroutine support");
expect_filename => $Self->{golden_filename}, }
); else {
compile(
verilator_flags2 => ["--exe --main --timing -Wall"],
make_main => 0,
);
execute( execute(
check_finished => 1, check_finished => 1,
) if !$Self->{vlt_all}; );
}
ok(1); ok(1);
1; 1;

View File

@ -20,6 +20,7 @@
`define MAILBOX_T mailbox `define MAILBOX_T mailbox
`endif `endif
// verilator lint_off DECLFILENAME
module t(/*AUTOARG*/); module t(/*AUTOARG*/);
`MAILBOX_T #(int) m; `MAILBOX_T #(int) m;
int msg; int msg;

View File

@ -1,6 +1,5 @@
%Error: t/t_mailbox_bad.v:8:4: Can't find typedef: 'mailbox' %Error: t/t_mailbox_bad.v:12:13: Class method 'bad_method' not found in class 'mailbox__Tz1'
8 | mailbox #(int) m; : ... In instance t
| ^~~~~~~ 12 | if (m.bad_method() != 0) $stop;
%Error: Internal Error: t/t_mailbox_bad.v:8:14: ../V3LinkDot.cpp:#: Pin not under instance? | ^~~~~~~~~~
8 | mailbox #(int) m; %Error: Exiting due to
| ^~~

View File

@ -1,6 +0,0 @@
%Error: t/t_mailbox.v:24:4: Can't find typedef: 'mailbox'
24 | mailbox #(int) m;
| ^~~~~~~
%Error: Internal Error: t/t_mailbox.v:24:14: ../V3LinkDot.cpp:#: Pin not under instance?
24 | mailbox #(int) m;
| ^~~

View File

@ -10,17 +10,21 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1); scenarios(simulator => 1);
top_filename("t/t_mailbox.v"); if (!$Self->have_coroutines) {
skip("No coroutine support");
}
else {
top_filename("t/t_mailbox.v");
compile( compile(
v_flags2 => ["+define+T_MAILBOX+std::mailbox"], verilator_flags2 => ["--exe --main --timing -Wall -DMAILBOX_T=std::mailbox"],
fails => $Self->{vlt_all}, make_main => 0,
expect_filename => $Self->{golden_filename}, );
);
execute( execute(
check_finished => 1, check_finished => 1,
) if !$Self->{vlt_all}; );
}
ok(1); ok(1);
1; 1;

View File

@ -30,4 +30,20 @@
: ... In instance t : ... In instance t
27 | initial #2 $stop; 27 | initial #2 $stop;
| ^ | ^
%Error-NOTIMING: t/t_notiming.v:33:10: mailbox::put() requires --timing
: ... In instance t
33 | m.put(i);
| ^~~
%Error-NOTIMING: t/t_notiming.v:34:10: mailbox::get() requires --timing
: ... In instance t
34 | m.get(i);
| ^~~
%Error-NOTIMING: t/t_notiming.v:35:10: mailbox::peek() requires --timing
: ... In instance t
35 | m.peek(i);
| ^~~~
%Error-NOTIMING: t/t_notiming.v:36:10: semaphore::get() requires --timing
: ... In instance t
36 | s.get();
| ^~~
%Error: Exiting due to %Error: Exiting due to

View File

@ -25,6 +25,16 @@ module t;
initial #1 ->e; initial #1 ->e;
initial #2 $stop; // timeout initial #2 $stop; // timeout
mailbox#(int) m = new;
semaphore s = new;
initial begin
int i;
m.put(i);
m.get(i);
m.peek(i);
s.get();
end
endmodule endmodule
`ifdef VERILATOR_TIMING `ifdef VERILATOR_TIMING

View File

@ -1,7 +0,0 @@
%Error: t/t_semaphore.v:21:4: Can't find typedef: 'semaphore'
21 | semaphore s;
| ^~~~~~~~~
%Error: t/t_semaphore.v:22:4: Can't find typedef: 'semaphore'
22 | semaphore s2;
| ^~~~~~~~~
%Error: Exiting due to

View File

@ -10,14 +10,19 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1); scenarios(simulator => 1);
compile( if (!$Self->have_coroutines) {
fails => $Self->{vlt_all}, skip("No coroutine support");
expect_filename => $Self->{golden_filename}, }
); else {
compile(
verilator_flags2 => ["--exe --main --timing -Wall"],
make_main => 0,
);
execute( execute(
check_finished => 1, check_finished => 1,
) if !$Self->{vlt_all}; );
}
ok(1); ok(1);
1; 1;

View File

@ -16,11 +16,11 @@
`define SEMAPHORE_T semaphore `define SEMAPHORE_T semaphore
`endif `endif
// verilator lint_off DECLFILENAME
module t(/*AUTOARG*/); module t(/*AUTOARG*/);
// From UVM: // From UVM:
`SEMAPHORE_T s; `SEMAPHORE_T s;
`SEMAPHORE_T s2; `SEMAPHORE_T s2;
int msg;
initial begin initial begin
s = new(1); s = new(1);

View File

@ -1,4 +1,5 @@
%Error: t/t_semaphore_bad.v:8:4: Can't find typedef: 'semaphore' %Error: t/t_semaphore_bad.v:12:13: Class method 'bad_method' not found in class 'semaphore'
8 | semaphore s; : ... In instance t
| ^~~~~~~~~ 12 | if (s.bad_method() != 0) $stop;
| ^~~~~~~~~~
%Error: Exiting due to %Error: Exiting due to

View File

@ -1,7 +0,0 @@
%Error: t/t_semaphore.v:21:4: Can't find typedef: 'semaphore'
21 | semaphore s;
| ^~~~~~~~~
%Error: t/t_semaphore.v:22:4: Can't find typedef: 'semaphore'
22 | semaphore s2;
| ^~~~~~~~~
%Error: Exiting due to

View File

@ -10,17 +10,21 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
scenarios(simulator => 1); scenarios(simulator => 1);
top_filename("t/t_semaphore.v"); if (!$Self->have_coroutines) {
skip("No coroutine support");
}
else {
top_filename("t/t_semaphore.v");
compile( compile(
v_flags2 => ["+define+T_SEMAPHORE+std::semaphore"], verilator_flags2 => ["--exe --main --timing -Wall -DSEMAPHORE_T=std::semaphore"],
fails => $Self->{vlt_all}, make_main => 0,
expect_filename => $Self->{golden_filename}, );
);
execute( execute(
check_finished => 1, check_finished => 1,
) if !$Self->{vlt_all}; );
}
ok(1); ok(1);
1; 1;

View File

@ -0,0 +1,5 @@
%Error-PKGNODECL: t/t_std_identifier.v:16:20: Package/class 'std' not found, and needs to be predeclared (IEEE 1800-2017 26.3)
16 | int baz = foo::std::bar;
| ^~~
... For error description see https://verilator.org/warn/PKGNODECL?v=latest
%Error: Exiting due to

View File

@ -2,18 +2,21 @@
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition # DESCRIPTION: Verilator: Verilog Test driver/expect definition
# #
# Copyright 2003 by Wilson Snyder. This program is free software; you # Copyright 2022 by Antmicro Ltd. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU # 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 # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1); scenarios(linter => 1);
top_filename("t_semaphore.v");
lint( lint(
verilator_flags2 => ["--debug-exit-uvm"], fails => 1,
expect_filename => $Self->{golden_filename},
);
lint(
verilator_flags2 => ["-DTEST_DECLARE_STD"],
); );
ok(1); ok(1);

View File

@ -0,0 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
package foo;
`ifdef TEST_DECLARE_STD
class std;
static int bar;
endclass
`endif
endpackage
module t;
int baz = foo::std::bar;
endmodule

View File

@ -0,0 +1,4 @@
%Error: t/t_std_pkg_bad.v:7:9: Redeclaring the 'std' package is not allowed
7 | package std;
| ^~~
%Error: Exiting due to

View File

@ -2,18 +2,17 @@
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition # DESCRIPTION: Verilator: Verilog Test driver/expect definition
# #
# Copyright 2003 by Wilson Snyder. This program is free software; you # Copyright 2022 by Antmicro Ltd. This program is free software; you
# can redistribute it and/or modify it under the terms of either the GNU # 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 # Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0. # Version 2.0.
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
scenarios(vlt => 1); scenarios(linter => 1);
top_filename("t_mailbox.v");
lint( lint(
verilator_flags2 => ["--debug-exit-uvm"], fails => 1,
expect_filename => $Self->{golden_filename},
); );
ok(1); ok(1);

View File

@ -0,0 +1,11 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain, for
// any use, without warranty, 2022 by Antmicro Ltd.
// SPDX-License-Identifier: CC0-1.0
package std;
endpackage
module t;
endmodule

View File

@ -31,4 +31,20 @@
: ... In instance t : ... In instance t
27 | initial #2 $stop; 27 | initial #2 $stop;
| ^ | ^
%Error-NEEDTIMINGOPT: t/t_notiming.v:33:10: Use --timing or --no-timing to specify how mailbox::put() should be handled
: ... In instance t
33 | m.put(i);
| ^~~
%Error-NEEDTIMINGOPT: t/t_notiming.v:34:10: Use --timing or --no-timing to specify how mailbox::get() should be handled
: ... In instance t
34 | m.get(i);
| ^~~
%Error-NEEDTIMINGOPT: t/t_notiming.v:35:10: Use --timing or --no-timing to specify how mailbox::peek() should be handled
: ... In instance t
35 | m.peek(i);
| ^~~~
%Error-NEEDTIMINGOPT: t/t_notiming.v:36:10: Use --timing or --no-timing to specify how semaphore::get() should be handled
: ... In instance t
36 | s.get();
| ^~~
%Error: Exiting due to %Error: Exiting due to