forked from github/verilator
Support global clocking and $global_clock.
This commit is contained in:
parent
bea225e191
commit
f20997a2f0
1
Changes
1
Changes
@ -14,6 +14,7 @@ Verilator 5.007 devel
|
|||||||
**Minor:**
|
**Minor:**
|
||||||
|
|
||||||
* Support unpacked unions.
|
* Support unpacked unions.
|
||||||
|
* Support global clocking and $global_clock.
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.006 2022-01-22
|
Verilator 5.006 2022-01-22
|
||||||
|
@ -350,8 +350,7 @@ private:
|
|||||||
AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack();
|
AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack();
|
||||||
AstNodeExpr* inp = newSampledExpr(exprp);
|
AstNodeExpr* inp = newSampledExpr(exprp);
|
||||||
AstVar* invarp = nullptr;
|
AstVar* invarp = nullptr;
|
||||||
AstSenTree* const sentreep = nodep->sentreep();
|
AstSenTree* const sentreep = nodep->sentreep()->unlinkFrBack();
|
||||||
sentreep->unlinkFrBack();
|
|
||||||
AstAlways* const alwaysp
|
AstAlways* const alwaysp
|
||||||
= new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr};
|
= new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr};
|
||||||
m_modp->addStmtsp(alwaysp);
|
m_modp->addStmtsp(alwaysp);
|
||||||
|
@ -822,19 +822,23 @@ class AstClocking final : public AstNode {
|
|||||||
// @astgen op4 := eventp : Optional[AstVar]
|
// @astgen op4 := eventp : Optional[AstVar]
|
||||||
std::string m_name; // Clocking block name
|
std::string m_name; // Clocking block name
|
||||||
const bool m_isDefault = false; // True if default clocking
|
const bool m_isDefault = false; // True if default clocking
|
||||||
|
const bool m_isGlobal = false; // True if global clocking
|
||||||
|
|
||||||
public:
|
public:
|
||||||
AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp,
|
AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp,
|
||||||
AstClockingItem* itemsp, bool isDefault)
|
AstClockingItem* itemsp, bool isDefault, bool isGlobal)
|
||||||
: ASTGEN_SUPER_Clocking(fl)
|
: ASTGEN_SUPER_Clocking(fl)
|
||||||
, m_isDefault{isDefault} {
|
, m_isDefault{isDefault}
|
||||||
|
, m_isGlobal{isGlobal} {
|
||||||
m_name = name;
|
m_name = name;
|
||||||
this->sensesp(sensesp);
|
this->sensesp(sensesp);
|
||||||
addItemsp(itemsp);
|
addItemsp(itemsp);
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstClocking;
|
ASTGEN_MEMBERS_AstClocking;
|
||||||
|
void dump(std::ostream& str) const override;
|
||||||
std::string name() const override { return m_name; }
|
std::string name() const override { return m_name; }
|
||||||
bool isDefault() const { return m_isDefault; }
|
bool isDefault() const { return m_isDefault; }
|
||||||
|
bool isGlobal() const { return m_isGlobal; }
|
||||||
};
|
};
|
||||||
class AstClockingItem final : public AstNode {
|
class AstClockingItem final : public AstNode {
|
||||||
// Parents: CLOCKING
|
// Parents: CLOCKING
|
||||||
|
@ -1509,6 +1509,11 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
|||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
if (immediate()) str << " [IMMEDIATE]";
|
if (immediate()) str << " [IMMEDIATE]";
|
||||||
}
|
}
|
||||||
|
void AstClocking::dump(std::ostream& str) const {
|
||||||
|
this->AstNode::dump(str);
|
||||||
|
if (isDefault()) str << " [DEFAULT]";
|
||||||
|
if (isGlobal()) str << " [GLOBAL]";
|
||||||
|
}
|
||||||
void AstDisplay::dump(std::ostream& str) const {
|
void AstDisplay::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
// str << " " << displayType().ascii();
|
// str << " " << displayType().ascii();
|
||||||
|
@ -1137,11 +1137,23 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||||||
iterate(nodep->sensesp());
|
iterate(nodep->sensesp());
|
||||||
iterateAndNextNull(nodep->itemsp());
|
iterateAndNextNull(nodep->itemsp());
|
||||||
// If the block has no name, one cannot reference the clockvars
|
// If the block has no name, one cannot reference the clockvars
|
||||||
if (nodep->name().empty()) return;
|
VSymEnt* itSymp = nullptr;
|
||||||
VL_RESTORER(m_curSymp);
|
if (nodep->isGlobal() //
|
||||||
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
&& m_statep->forPrimary()) { // else flattening may see two globals
|
||||||
m_curSymp->fallbackp(nullptr);
|
m_statep->checkDuplicate(m_curSymp, nodep, "__024global_clock");
|
||||||
iterateAndNextNull(nodep->itemsp());
|
itSymp
|
||||||
|
= m_statep->insertBlock(m_curSymp, "__024global_clock", nodep, m_classOrPackagep);
|
||||||
|
itSymp->fallbackp(nullptr);
|
||||||
|
}
|
||||||
|
if (!nodep->name().empty()) {
|
||||||
|
itSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
||||||
|
itSymp->fallbackp(nullptr);
|
||||||
|
}
|
||||||
|
if (itSymp) {
|
||||||
|
VL_RESTORER(m_curSymp);
|
||||||
|
m_curSymp = itSymp;
|
||||||
|
iterateAndNextNull(nodep->itemsp());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void visit(AstClockingItem* nodep) override {
|
void visit(AstClockingItem* nodep) override {
|
||||||
if (nodep->varp()) {
|
if (nodep->varp()) {
|
||||||
|
@ -236,6 +236,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||||||
"$fwriteb" { FL; return yD_FWRITEB; }
|
"$fwriteb" { FL; return yD_FWRITEB; }
|
||||||
"$fwriteh" { FL; return yD_FWRITEH; }
|
"$fwriteh" { FL; return yD_FWRITEH; }
|
||||||
"$fwriteo" { FL; return yD_FWRITEO; }
|
"$fwriteo" { FL; return yD_FWRITEO; }
|
||||||
|
"$global_clock" { FL; return yD_GLOBAL_CLOCK; }
|
||||||
"$hold" { FL; return yaTIMINGSPEC; }
|
"$hold" { FL; return yaTIMINGSPEC; }
|
||||||
"$hypot" { FL; return yD_HYPOT; }
|
"$hypot" { FL; return yD_HYPOT; }
|
||||||
"$itor" { FL; return yD_ITOR; }
|
"$itor" { FL; return yD_ITOR; }
|
||||||
|
@ -844,6 +844,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||||||
%token<fl> yD_FWRITEB "$fwriteb"
|
%token<fl> yD_FWRITEB "$fwriteb"
|
||||||
%token<fl> yD_FWRITEH "$fwriteh"
|
%token<fl> yD_FWRITEH "$fwriteh"
|
||||||
%token<fl> yD_FWRITEO "$fwriteo"
|
%token<fl> yD_FWRITEO "$fwriteo"
|
||||||
|
%token<fl> yD_GLOBAL_CLOCK "$global_clock"
|
||||||
%token<fl> yD_HIGH "$high"
|
%token<fl> yD_HIGH "$high"
|
||||||
%token<fl> yD_HYPOT "$hypot"
|
%token<fl> yD_HYPOT "$hypot"
|
||||||
%token<fl> yD_INCREMENT "$increment"
|
%token<fl> yD_INCREMENT "$increment"
|
||||||
@ -4101,6 +4102,8 @@ system_f_call_or_t<nodeExprp>: // IEEE: part of system_tf_call (can be task
|
|||||||
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF{$1, *$5, $3, $6}; }
|
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF{$1, *$5, $3, $6}; }
|
||||||
| yD_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; }
|
| yD_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; }
|
||||||
| yD_FTELL '(' idClassSel ')' { $$ = new AstFTell{$1, $3}; }
|
| yD_FTELL '(' idClassSel ')' { $$ = new AstFTell{$1, $3}; }
|
||||||
|
| yD_GLOBAL_CLOCK parenE
|
||||||
|
{ $$ = new AstParseRef{$<fl>1, VParseRefExp::PX_TEXT, "__024global_clock", nullptr, nullptr}; }
|
||||||
| yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, nullptr}; }
|
| yD_HIGH '(' exprOrDataType ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, nullptr}; }
|
||||||
| yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, $5}; }
|
| yD_HIGH '(' exprOrDataType ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, $5}; }
|
||||||
| yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD{$1, $3, $5}; }
|
| yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD{$1, $3, $5}; }
|
||||||
@ -5441,17 +5444,15 @@ endLabelE<strp>:
|
|||||||
|
|
||||||
clocking_declaration<nodep>: // IEEE: clocking_declaration
|
clocking_declaration<nodep>: // IEEE: clocking_declaration
|
||||||
yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
||||||
{ $$ = new AstClocking{$<fl>2, *$2, $3, $5, false}; }
|
{ $$ = new AstClocking{$<fl>2, *$2, $3, $5, false, false}; }
|
||||||
| yDEFAULT yCLOCKING clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
| yDEFAULT yCLOCKING clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
||||||
{ $$ = new AstClocking{$<fl>2, "", $3, $5, true}; }
|
{ $$ = new AstClocking{$<fl>2, "", $3, $5, true, false}; }
|
||||||
| yDEFAULT yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
| yDEFAULT yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
||||||
{ $$ = new AstClocking{$<fl>3, *$3, $4, $6, true}; }
|
{ $$ = new AstClocking{$<fl>3, *$3, $4, $6, true, false}; }
|
||||||
| yGLOBAL__CLOCKING yCLOCKING clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
| yGLOBAL__CLOCKING yCLOCKING clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
||||||
{ $$ = nullptr;
|
{ $$ = new AstClocking{$<fl>2, "", $3, $5, false, true}; }
|
||||||
BBUNSUP($<fl>2, "Unsupported: global clocking"); }
|
|
||||||
| yGLOBAL__CLOCKING yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
| yGLOBAL__CLOCKING yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
||||||
{ $$ = nullptr;
|
{ $$ = new AstClocking{$<fl>3, *$3, $4, $6, false, true}; }
|
||||||
BBUNSUP($<fl>3, "Unsupported: global clocking"); }
|
|
||||||
;
|
;
|
||||||
|
|
||||||
clocking_event<senItemp>: // IEEE: clocking_event
|
clocking_event<senItemp>: // IEEE: clocking_event
|
||||||
|
22
test_regress/t/t_clocking_bad5.out
Normal file
22
test_regress/t/t_clocking_bad5.out
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
%Error: t/t_clocking_bad5.v:29:20: Duplicate declaration of CLOCKING 'ck': '$global_clock'
|
||||||
|
29 | global clocking ogck @(posedge clk); endclocking
|
||||||
|
| ^~~~
|
||||||
|
t/t_clocking_bad5.v:26:20: ... Location of original declaration
|
||||||
|
26 | global clocking ck @(posedge clk); endclocking
|
||||||
|
| ^~
|
||||||
|
%Error: t/t_clocking_bad5.v:32:20: Duplicate declaration of CLOCKING 'ogck': '$global_clock'
|
||||||
|
32 | global clocking ck @(posedge clk); endclocking
|
||||||
|
| ^~
|
||||||
|
t/t_clocking_bad5.v:29:20: ... Location of original declaration
|
||||||
|
29 | global clocking ogck @(posedge clk); endclocking
|
||||||
|
| ^~~~
|
||||||
|
%Error: t/t_clocking_bad5.v:32:20: Duplicate declaration of CLOCKING 'ck': 'ck'
|
||||||
|
32 | global clocking ck @(posedge clk); endclocking
|
||||||
|
| ^~
|
||||||
|
t/t_clocking_bad5.v:26:20: ... Location of original declaration
|
||||||
|
26 | global clocking ck @(posedge clk); endclocking
|
||||||
|
| ^~
|
||||||
|
%Error: t/t_clocking_bad5.v:16:14: Can't find definition of variable: '$global_clock'
|
||||||
|
16 | always @ ($global_clock) $display;
|
||||||
|
| ^~~~~~~~~~~~~
|
||||||
|
%Error: Exiting due to
|
20
test_regress/t/t_clocking_bad5.pl
Executable file
20
test_regress/t/t_clocking_bad5.pl
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2023 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(linter => 1);
|
||||||
|
|
||||||
|
lint(
|
||||||
|
verilator_flags2 => ["--timing"],
|
||||||
|
fails => 1,
|
||||||
|
expect_filename => $Self->{golden_filename},
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
34
test_regress/t/t_clocking_bad5.v
Normal file
34
test_regress/t/t_clocking_bad5.v
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2023 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t(/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
sub sub(.*);
|
||||||
|
|
||||||
|
// Bad - no global clock
|
||||||
|
always @ ($global_clock) $display;
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
|
||||||
|
module sub(/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk
|
||||||
|
);
|
||||||
|
input clk;
|
||||||
|
|
||||||
|
global clocking ck @(posedge clk); endclocking
|
||||||
|
|
||||||
|
// Bad - global duplicate
|
||||||
|
global clocking ogck @(posedge clk); endclocking
|
||||||
|
|
||||||
|
// Bad - name duplicate
|
||||||
|
global clocking ck @(posedge clk); endclocking
|
||||||
|
|
||||||
|
endmodule
|
@ -14,10 +14,4 @@
|
|||||||
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:18:15: Unsupported: clocking event edge override
|
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:18:15: Unsupported: clocking event edge override
|
||||||
18 | output edge #1 b;
|
18 | output edge #1 b;
|
||||||
| ^~~~
|
| ^~~~
|
||||||
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:13:20: Unsupported: global clocking
|
|
||||||
13 | global clocking cb @(posedge clk);
|
|
||||||
| ^~
|
|
||||||
%Error-UNSUPPORTED: t/t_clocking_unsup1.v:21:11: Unsupported: global clocking
|
|
||||||
21 | global clocking @(posedge clk);
|
|
||||||
| ^~~~~~~~
|
|
||||||
%Error: Exiting due to
|
%Error: Exiting due to
|
||||||
|
@ -18,6 +18,4 @@ module t(/*AUTOARG*/
|
|||||||
output edge #1 b;
|
output edge #1 b;
|
||||||
endclocking
|
endclocking
|
||||||
|
|
||||||
global clocking @(posedge clk);
|
|
||||||
endclocking
|
|
||||||
endmodule
|
endmodule
|
||||||
|
@ -23,6 +23,11 @@ module t (/*AUTOARG*/
|
|||||||
.clk (clk),
|
.clk (clk),
|
||||||
.in (in[31:0]));
|
.in (in[31:0]));
|
||||||
|
|
||||||
|
Test3 test3 (/*AUTOINST*/
|
||||||
|
// Inputs
|
||||||
|
.clk (clk),
|
||||||
|
.in (in[31:0]));
|
||||||
|
|
||||||
always @ (posedge clk) begin
|
always @ (posedge clk) begin
|
||||||
if (cyc!=0) begin
|
if (cyc!=0) begin
|
||||||
cyc <= cyc + 1;
|
cyc <= cyc + 1;
|
||||||
@ -69,6 +74,10 @@ module Test (/*AUTOARG*/
|
|||||||
assert property (@(posedge clk) $fell(dly1) || dly1%2==1);
|
assert property (@(posedge clk) $fell(dly1) || dly1%2==1);
|
||||||
assert property (@(posedge clk) !$stable(dly2));
|
assert property (@(posedge clk) !$stable(dly2));
|
||||||
assert property (@(posedge clk) $changed(dly2));
|
assert property (@(posedge clk) $changed(dly2));
|
||||||
|
|
||||||
|
global clocking @(posedge clk); endclocking
|
||||||
|
always @ ($global_clock) $display("%d", in);
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
|
||||||
@ -101,3 +110,18 @@ module Test2 (/*AUTOARG*/
|
|||||||
assert property ($stable(dly2[31:4]));
|
assert property ($stable(dly2[31:4]));
|
||||||
assert property (!$changed(dly2[31:4]));
|
assert property (!$changed(dly2[31:4]));
|
||||||
endmodule
|
endmodule
|
||||||
|
|
||||||
|
module Test3 (/*AUTOARG*/
|
||||||
|
// Inputs
|
||||||
|
clk, in
|
||||||
|
);
|
||||||
|
|
||||||
|
input clk;
|
||||||
|
input [31:0] in;
|
||||||
|
|
||||||
|
// Check the named form of global clocking
|
||||||
|
global clocking gck @(posedge clk); endclocking
|
||||||
|
always @ (gck) $display("%d", in);
|
||||||
|
always @ ($global_clock) $display("%d", in);
|
||||||
|
|
||||||
|
endmodule
|
||||||
|
Loading…
Reference in New Issue
Block a user