mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
Support event data type (with some restrictions).
This commit is contained in:
parent
9991b19610
commit
87e1c36e4a
2
Changes
2
Changes
@ -26,6 +26,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||
|
||||
**** Support $ferror, and $fflush without arguments, #1638.
|
||||
|
||||
**** Support event data type (with some restrictions).
|
||||
|
||||
**** Add error if use SystemC 2.2 and earlier (pre-2011) as is deprecated.
|
||||
|
||||
**** Greatly improve FST/VCD dump performance, #2244, #2246, #2250, #2257. [Geza Lore]
|
||||
|
@ -388,6 +388,16 @@ private:
|
||||
iterateChildren(nodep);
|
||||
}
|
||||
virtual void visit(AstSenItem* nodep) VL_OVERRIDE {
|
||||
if (nodep->varrefp()) {
|
||||
if (AstBasicDType* basicp = nodep->varrefp()->dtypep()->basicp()) {
|
||||
if (basicp->isEventValue()) {
|
||||
// Events need to be treated as active high so we only activate on event being
|
||||
// 1
|
||||
UINFO(8, "Demote event to HIGHEDGE " << nodep << endl);
|
||||
nodep->edgeType(VEdgeType::ET_HIGHEDGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nodep->edgeType() == VEdgeType::ET_ANYEDGE) {
|
||||
m_itemCombo = true;
|
||||
// Delete the sensitivity
|
||||
|
18
src/V3Ast.h
18
src/V3Ast.h
@ -372,6 +372,7 @@ public:
|
||||
BIT,
|
||||
BYTE,
|
||||
CHANDLE,
|
||||
EVENTVALUE, // See comments in t_event_copy as to why this is EVENTVALUE
|
||||
INT,
|
||||
INTEGER,
|
||||
LOGIC,
|
||||
@ -396,14 +397,16 @@ public:
|
||||
enum en m_e;
|
||||
const char* ascii() const {
|
||||
static const char* const names[] = {
|
||||
"%E-unk", "bit", "byte", "chandle", "int", "integer", "logic",
|
||||
"%E-unk", //
|
||||
"bit", "byte", "chandle", "event", "int", "integer", "logic",
|
||||
"longint", "real", "shortint", "shortreal", "time", "string", "VerilatedScope*",
|
||||
"char*", "IData", "QData", "LOGIC_IMPLICIT", " MAX"};
|
||||
return names[m_e];
|
||||
}
|
||||
const char* dpiType() const {
|
||||
static const char* const names[]
|
||||
= {"%E-unk", "svBit", "char", "void*", "int", "%E-integer",
|
||||
= {"%E-unk", //
|
||||
"svBit", "char", "void*", "char", "int", "%E-integer",
|
||||
"svLogic", "long long", "double", "short", "float", "%E-time",
|
||||
"const char*", "dpiScope", "const char*", "IData", "QData", "%E-logic-implicit",
|
||||
" MAX"};
|
||||
@ -428,6 +431,7 @@ public:
|
||||
case BIT: return 1; // scalar, can't bit extract unless ranged
|
||||
case BYTE: return 8;
|
||||
case CHANDLE: return 64;
|
||||
case EVENTVALUE: return 1;
|
||||
case INT: return 32;
|
||||
case INTEGER: return 32;
|
||||
case LOGIC: return 1; // scalar, can't bit extract unless ranged
|
||||
@ -449,15 +453,16 @@ public:
|
||||
|| m_e == DOUBLE || m_e == FLOAT;
|
||||
}
|
||||
bool isUnsigned() const {
|
||||
return m_e == CHANDLE || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|
||||
|| m_e == UINT32 || m_e == UINT64;
|
||||
return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR
|
||||
|| m_e == CHARPTR || m_e == UINT32 || m_e == UINT64;
|
||||
}
|
||||
bool isFourstate() const {
|
||||
return m_e == INTEGER || m_e == LOGIC || m_e == LOGIC_IMPLICIT || m_e == TIME;
|
||||
}
|
||||
bool isZeroInit() const { // Otherwise initializes to X
|
||||
return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == INT || m_e == LONGINT
|
||||
|| m_e == SHORTINT || m_e == STRING || m_e == DOUBLE || m_e == FLOAT);
|
||||
return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == EVENTVALUE || m_e == INT
|
||||
|| m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE
|
||||
|| m_e == FLOAT);
|
||||
}
|
||||
bool isIntNumeric() const { // Enum increment supported
|
||||
return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC
|
||||
@ -481,6 +486,7 @@ public:
|
||||
|| m_e == FLOAT);
|
||||
}
|
||||
bool isDouble() const { return m_e == DOUBLE; }
|
||||
bool isEventValue() const { return m_e == EVENTVALUE; }
|
||||
bool isString() const { return m_e == STRING; }
|
||||
};
|
||||
inline bool operator==(const AstBasicDTypeKwd& lhs, const AstBasicDTypeKwd& rhs) {
|
||||
|
@ -840,6 +840,7 @@ public:
|
||||
}
|
||||
bool isBitLogic() const { return keyword().isBitLogic(); }
|
||||
bool isDouble() const { return keyword().isDouble(); }
|
||||
bool isEventValue() const { return keyword().isEventValue(); }
|
||||
bool isOpaque() const { return keyword().isOpaque(); }
|
||||
bool isString() const { return keyword().isString(); }
|
||||
bool isSloppy() const { return keyword().isSloppy(); }
|
||||
|
@ -385,6 +385,8 @@ private:
|
||||
nodep->v3warn(BLKLOOPINIT, "Unsupported: Delayed assignment to array inside for "
|
||||
"loops (non-delayed is ok - see docs)");
|
||||
}
|
||||
AstBasicDType* basicp = lhsp->dtypep()->basicp();
|
||||
if (basicp && basicp->isEventValue()) nodep->v3error("Unsupported: event arrays");
|
||||
if (newlhsp) {
|
||||
nodep->lhsp(newlhsp);
|
||||
} else {
|
||||
@ -418,9 +420,18 @@ private:
|
||||
if (!dlyvscp) { // First use of this delayed variable
|
||||
string newvarname = (string("__Vdly__") + nodep->varp()->shortName());
|
||||
dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL);
|
||||
AstNodeAssign* prep = new AstAssignPre(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, false));
|
||||
AstNodeAssign* prep;
|
||||
AstBasicDType* basicp = oldvscp->dtypep()->basicp();
|
||||
if (basicp && basicp->isEventValue()) {
|
||||
// Events go to zero on next timestep unless reactivated
|
||||
prep = new AstAssignPre(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstConst(nodep->fileline(), AstConst::LogicFalse()));
|
||||
} else {
|
||||
prep = new AstAssignPre(nodep->fileline(),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, true),
|
||||
new AstVarRef(nodep->fileline(), oldvscp, false));
|
||||
}
|
||||
AstNodeAssign* postp = new AstAssignPost(
|
||||
nodep->fileline(), new AstVarRef(nodep->fileline(), oldvscp, true),
|
||||
new AstVarRef(nodep->fileline(), dlyvscp, false));
|
||||
|
@ -2025,6 +2025,8 @@ private:
|
||||
methodCallClass(nodep, adtypep);
|
||||
} else if (AstUnpackArrayDType* adtypep = VN_CAST(fromDtp, UnpackArrayDType)) {
|
||||
methodCallUnpack(nodep, adtypep);
|
||||
} else if (basicp && basicp->isEventValue()) {
|
||||
methodCallEvent(nodep, basicp);
|
||||
} else if (basicp && basicp->isString()) {
|
||||
methodCallString(nodep, basicp);
|
||||
} else {
|
||||
@ -2431,6 +2433,18 @@ private:
|
||||
nodep->v3error("Unknown built-in array method " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
void methodCallEvent(AstMethodCall* nodep, AstBasicDType* adtypep) {
|
||||
// Method call on event
|
||||
if (nodep->name() == "triggered") {
|
||||
// We represent events as numbers, so can just return number
|
||||
methodOkArguments(nodep, 0, 0);
|
||||
AstNode* newp = nodep->fromp()->unlinkFrBack();
|
||||
nodep->replaceWith(newp);
|
||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||
} else {
|
||||
nodep->v3error("Unknown built-in event method " << nodep->prettyNameQ());
|
||||
}
|
||||
}
|
||||
void methodCallString(AstMethodCall* nodep, AstBasicDType* adtypep) {
|
||||
// Method call on string
|
||||
if (nodep->name() == "len") {
|
||||
@ -3036,6 +3050,12 @@ private:
|
||||
iterateCheckAssign(nodep, "Assign RHS", nodep->rhsp(), FINAL, lhsDTypep);
|
||||
// if (debug()) nodep->dumpTree(cout, " AssignOut: ");
|
||||
}
|
||||
if (AstBasicDType* basicp = nodep->rhsp()->dtypep()->basicp()) {
|
||||
if (basicp->isEventValue()) {
|
||||
// see t_event_copy.v for commentary on the mess involved
|
||||
nodep->v3error("Unsupported: assignment of event data type");
|
||||
}
|
||||
}
|
||||
if (AstNewDynamic* dynp = VN_CAST(nodep->rhsp(), NewDynamic)) {
|
||||
UINFO(9, "= new[] -> .resize(): " << nodep);
|
||||
AstCMethodHard* newp;
|
||||
|
@ -1623,7 +1623,7 @@ data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc referenc
|
||||
SYMP,VFlagChildDType(),$1); }
|
||||
| ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
|
||||
| yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); }
|
||||
| yEVENT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::BIT); BBUNSUP($1, "Unsupported: event data types"); }
|
||||
| yEVENT { $$ = new AstBasicDType($1,AstBasicDTypeKwd::EVENTVALUE); }
|
||||
// // Rules overlap virtual_interface_declaration
|
||||
// // Parameters here are SV2009
|
||||
// // IEEE has ['.' modport] but that will conflict with port
|
||||
@ -2813,8 +2813,15 @@ statement_item<nodep>: // IEEE: statement_item
|
||||
| yDISABLE idAny/*hierarchical_identifier-task_or_block*/ ';' { $$ = new AstDisable($1,*$2); }
|
||||
| yDISABLE yFORK ';' { $$ = NULL; BBUNSUP($1, "Unsupported: disable fork statements"); }
|
||||
// // IEEE: event_trigger
|
||||
//UNSUP yP_MINUSGT hierarchical_identifier/*event*/ ';' { UNSUP }
|
||||
| yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';'
|
||||
{ // AssignDly because we don't have stratified queue, and need to
|
||||
// read events, clear next event, THEN apply this set
|
||||
$$ = new AstAssignDly($1, $2, new AstConst($1, AstConst::LogicTrue())); }
|
||||
//UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP }
|
||||
// // IEEE remove below
|
||||
| yP_MINUSGTGT delayE idDotted/*hierarchical_identifier-event*/ ';'
|
||||
{ $$ = new AstAssignDly($1, $3, new AstConst($1, AstConst::LogicTrue())); }
|
||||
//
|
||||
// // IEEE: loop_statement
|
||||
| yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1,AstConst::LogicTrue()),$2); }
|
||||
| yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat($1,$3,$5);}
|
||||
|
21
test_regress/t/t_event.pl
Executable file
21
test_regress/t/t_event.pl
Executable file
@ -0,0 +1,21 @@
|
||||
#!/usr/bin/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(simulator => 1);
|
||||
|
||||
compile(
|
||||
);
|
||||
|
||||
execute(
|
||||
check_finished => 1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
81
test_regress/t/t_event.v
Normal file
81
test_regress/t/t_event.v
Normal file
@ -0,0 +1,81 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2003 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`ifdef TEST_VERBOSE
|
||||
`define WRITE_VERBOSE(args) $write args
|
||||
`else
|
||||
`define WRITE_VERBOSE(args)
|
||||
`endif
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
event e1;
|
||||
event e2;
|
||||
`ifndef IVERILOG
|
||||
event ev [3:0];
|
||||
`endif
|
||||
|
||||
int cyc;
|
||||
|
||||
int last_event;
|
||||
always @(e1) begin
|
||||
`WRITE_VERBOSE(("[%0t] e1\n", $time));
|
||||
if (!e1.triggered) $stop;
|
||||
last_event[1] = 1;
|
||||
end
|
||||
|
||||
always @(e2) begin
|
||||
`WRITE_VERBOSE(("[%0t] e2\n", $time));
|
||||
last_event[2] = 1;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
`WRITE_VERBOSE(("[%0t] cyc=%0d last_event=%5b\n", $time, cyc, last_event));
|
||||
cyc <= cyc + 1;
|
||||
if (cyc == 1) begin
|
||||
// Check no initial trigger
|
||||
if (last_event != 0) $stop;
|
||||
end
|
||||
//
|
||||
else if (cyc == 10) begin
|
||||
last_event = 0;
|
||||
-> e1;
|
||||
end
|
||||
else if (cyc == 12) begin
|
||||
if (last_event != 32'b10) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
else if (cyc == 13) begin
|
||||
// Check not still triggering
|
||||
if (last_event != 0) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
//
|
||||
else if (cyc == 10) begin
|
||||
last_event = 0;
|
||||
->> e2;
|
||||
end
|
||||
else if (cyc == 12) begin
|
||||
if (last_event != 32'b100) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
else if (cyc == 13) begin
|
||||
// Check not still triggering
|
||||
if (last_event != 0) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
//
|
||||
else if (cyc == 99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
9
test_regress/t/t_event_copy.out
Normal file
9
test_regress/t/t_event_copy.out
Normal file
@ -0,0 +1,9 @@
|
||||
%Error: t/t_event_copy.v:100:13: Unsupported: assignment of event data type
|
||||
: ... In instance t
|
||||
100 | e4 = e3;
|
||||
| ^
|
||||
%Error: t/t_event_copy.v:101:13: Unsupported: assignment of event data type
|
||||
: ... In instance t
|
||||
101 | e3 = e2;
|
||||
| ^
|
||||
%Error: Exiting due to
|
23
test_regress/t/t_event_copy.pl
Executable file
23
test_regress/t/t_event_copy.pl
Executable file
@ -0,0 +1,23 @@
|
||||
#!/usr/bin/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(simulator => 1);
|
||||
|
||||
compile(
|
||||
fails => $Self->{vlt_all},
|
||||
expect_filename => $Self->{golden_filename},
|
||||
);
|
||||
|
||||
#execute(
|
||||
# check_finished => 1,
|
||||
# );
|
||||
|
||||
ok(1);
|
||||
1;
|
142
test_regress/t/t_event_copy.v
Normal file
142
test_regress/t/t_event_copy.v
Normal file
@ -0,0 +1,142 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||
// any use, without warranty, 2003 by Wilson Snyder.
|
||||
// SPDX-License-Identifier: CC0-1.0
|
||||
|
||||
`ifdef TEST_VERBOSE
|
||||
`define WRITE_VERBOSE(args) $write args
|
||||
`else
|
||||
`define WRITE_VERBOSE(args)
|
||||
`endif
|
||||
|
||||
module t(/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
event e1;
|
||||
event e2;
|
||||
event e3;
|
||||
event e4;
|
||||
`ifndef IVERILOG
|
||||
event ev [3:0];
|
||||
`endif
|
||||
|
||||
int cyc;
|
||||
|
||||
int last_event;
|
||||
always @(e1) begin
|
||||
`WRITE_VERBOSE(("[%0t] e1\n", $time));
|
||||
`ifndef IVERILOG
|
||||
if (!e1.triggered) $stop;
|
||||
`endif
|
||||
last_event[1] = 1;
|
||||
end
|
||||
|
||||
always @(e2) begin
|
||||
`WRITE_VERBOSE(("[%0t] e2\n", $time));
|
||||
last_event[2] = 1;
|
||||
end
|
||||
|
||||
always @(e3) begin
|
||||
`WRITE_VERBOSE(("[%0t] e3\n", $time));
|
||||
last_event[3] = 1;
|
||||
end
|
||||
|
||||
always @(e4) begin
|
||||
`WRITE_VERBOSE(("[%0t] e4\n", $time));
|
||||
last_event[4] = 1;
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
`WRITE_VERBOSE(("[%0t] cyc=%0d last_event=%5b\n", $time, cyc, last_event));
|
||||
cyc <= cyc + 1;
|
||||
if (cyc == 1) begin
|
||||
// Check no initial trigger
|
||||
if (last_event != 0) $stop;
|
||||
end
|
||||
//
|
||||
else if (cyc == 10) begin
|
||||
last_event = 0;
|
||||
-> e1;
|
||||
end
|
||||
else if (cyc == 12) begin
|
||||
if (last_event != 32'b10) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
else if (cyc == 13) begin
|
||||
// Check not still triggering
|
||||
if (last_event != 0) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
//
|
||||
else if (cyc == 20) begin
|
||||
last_event = 0;
|
||||
`ifdef IVERILOG
|
||||
-> e2;
|
||||
`else
|
||||
// Events are both references and events themselves. I.e. 'event e'
|
||||
// declaration means 'event e = new'. Then e is a reference to that
|
||||
// created event.
|
||||
//
|
||||
// Always having indirection is bad for performance, so Verilator
|
||||
// should have 'event e' as an "EVENTVALUE" stored as a char, or
|
||||
// ideally a one bit field reference (not vector as that can't be
|
||||
// V3Ordered).
|
||||
//
|
||||
// Then events once copied become EVENTREFs, much like a ClassRef which
|
||||
// points to an EVENTVALUE. Thus a Verilog "event" starts as an
|
||||
// EVENTVALUE, and if an assignment is made it becomes an EVENTVALUE
|
||||
// and an EVENTREF initing to that EVENTVALUE.
|
||||
//
|
||||
// All static scheduling for events would go out the window once an
|
||||
// event can be pointed to by an EVENTREF, as basically any EVENTREF
|
||||
// activation could be activating any event. A graph algorithm could
|
||||
// determine what events/eventrefs are associated and only
|
||||
// pessamistically schedule those events (users of EVENTVALUES) that
|
||||
// are ever pointed to by an EVENTREF.
|
||||
e4 = e3; // Old handle to e4
|
||||
e3 = e2; // Same event, also triggers e2
|
||||
// IEEE 2017 15.5.5.1 says that this causes a merge, and the below
|
||||
// should also activate the "old e3". However we could not find any
|
||||
// simulator that actually does this. Instead the "old e3" becomes
|
||||
// unreachable (via old handle), but is reachable by "e4" as assigned
|
||||
// earlier.
|
||||
->> e3; // Delayed
|
||||
`endif
|
||||
end
|
||||
else if (cyc == 22) begin
|
||||
if (last_event != 32'b100) $stop;
|
||||
last_event = 0;
|
||||
-> e2; // IEEE says triggers e3, but does not
|
||||
end
|
||||
else if (cyc == 24) begin
|
||||
if (last_event != 32'b100) $stop;
|
||||
last_event = 0;
|
||||
-> e4; // Triggers old e3
|
||||
end
|
||||
else if (cyc == 26) begin
|
||||
if (last_event != 32'b1000) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
//
|
||||
else if (cyc == 30) begin
|
||||
last_event = 0;
|
||||
`ifndef IVERILOG
|
||||
e3 = null;
|
||||
-> e3; // Triggers nothing
|
||||
`endif
|
||||
end
|
||||
else if (cyc == 32) begin
|
||||
if (last_event != 0) $stop;
|
||||
last_event = 0;
|
||||
end
|
||||
else if (cyc == 99) begin
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
Loading…
Reference in New Issue
Block a user