Support event data type (with some restrictions).

This commit is contained in:
Wilson Snyder 2020-04-25 15:37:46 -04:00
parent 9991b19610
commit 87e1c36e4a
12 changed files with 344 additions and 11 deletions

View File

@ -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]

View File

@ -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

View File

@ -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) {

View File

@ -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(); }

View File

@ -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));

View File

@ -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;

View File

@ -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
View 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
View 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

View 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
View 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;

View 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