mirror of
https://github.com/verilator/verilator.git
synced 2025-01-01 04:07:34 +00:00
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:**
|
||||
|
||||
* Support unpacked unions.
|
||||
* Support global clocking and $global_clock.
|
||||
|
||||
|
||||
Verilator 5.006 2022-01-22
|
||||
|
@ -350,8 +350,7 @@ private:
|
||||
AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack();
|
||||
AstNodeExpr* inp = newSampledExpr(exprp);
|
||||
AstVar* invarp = nullptr;
|
||||
AstSenTree* const sentreep = nodep->sentreep();
|
||||
sentreep->unlinkFrBack();
|
||||
AstSenTree* const sentreep = nodep->sentreep()->unlinkFrBack();
|
||||
AstAlways* const alwaysp
|
||||
= new AstAlways{nodep->fileline(), VAlwaysKwd::ALWAYS, sentreep, nullptr};
|
||||
m_modp->addStmtsp(alwaysp);
|
||||
|
@ -822,19 +822,23 @@ class AstClocking final : public AstNode {
|
||||
// @astgen op4 := eventp : Optional[AstVar]
|
||||
std::string m_name; // Clocking block name
|
||||
const bool m_isDefault = false; // True if default clocking
|
||||
const bool m_isGlobal = false; // True if global clocking
|
||||
|
||||
public:
|
||||
AstClocking(FileLine* fl, const std::string& name, AstSenItem* sensesp,
|
||||
AstClockingItem* itemsp, bool isDefault)
|
||||
AstClockingItem* itemsp, bool isDefault, bool isGlobal)
|
||||
: ASTGEN_SUPER_Clocking(fl)
|
||||
, m_isDefault{isDefault} {
|
||||
, m_isDefault{isDefault}
|
||||
, m_isGlobal{isGlobal} {
|
||||
m_name = name;
|
||||
this->sensesp(sensesp);
|
||||
addItemsp(itemsp);
|
||||
}
|
||||
ASTGEN_MEMBERS_AstClocking;
|
||||
void dump(std::ostream& str) const override;
|
||||
std::string name() const override { return m_name; }
|
||||
bool isDefault() const { return m_isDefault; }
|
||||
bool isGlobal() const { return m_isGlobal; }
|
||||
};
|
||||
class AstClockingItem final : public AstNode {
|
||||
// Parents: CLOCKING
|
||||
|
@ -1509,6 +1509,11 @@ void AstNodeCoverOrAssert::dump(std::ostream& str) const {
|
||||
this->AstNodeStmt::dump(str);
|
||||
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 {
|
||||
this->AstNodeStmt::dump(str);
|
||||
// str << " " << displayType().ascii();
|
||||
|
@ -1137,11 +1137,23 @@ class LinkDotFindVisitor final : public VNVisitor {
|
||||
iterate(nodep->sensesp());
|
||||
iterateAndNextNull(nodep->itemsp());
|
||||
// If the block has no name, one cannot reference the clockvars
|
||||
if (nodep->name().empty()) return;
|
||||
VL_RESTORER(m_curSymp);
|
||||
m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep);
|
||||
m_curSymp->fallbackp(nullptr);
|
||||
iterateAndNextNull(nodep->itemsp());
|
||||
VSymEnt* itSymp = nullptr;
|
||||
if (nodep->isGlobal() //
|
||||
&& m_statep->forPrimary()) { // else flattening may see two globals
|
||||
m_statep->checkDuplicate(m_curSymp, nodep, "__024global_clock");
|
||||
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 {
|
||||
if (nodep->varp()) {
|
||||
|
@ -236,6 +236,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
||||
"$fwriteb" { FL; return yD_FWRITEB; }
|
||||
"$fwriteh" { FL; return yD_FWRITEH; }
|
||||
"$fwriteo" { FL; return yD_FWRITEO; }
|
||||
"$global_clock" { FL; return yD_GLOBAL_CLOCK; }
|
||||
"$hold" { FL; return yaTIMINGSPEC; }
|
||||
"$hypot" { FL; return yD_HYPOT; }
|
||||
"$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_FWRITEH "$fwriteh"
|
||||
%token<fl> yD_FWRITEO "$fwriteo"
|
||||
%token<fl> yD_GLOBAL_CLOCK "$global_clock"
|
||||
%token<fl> yD_HIGH "$high"
|
||||
%token<fl> yD_HYPOT "$hypot"
|
||||
%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_FSEEK '(' idClassSel ',' expr ',' expr ')' { $$ = new AstFSeek{$1, $3, $5, $7}; }
|
||||
| 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 ',' expr ')' { $$ = new AstAttrOf{$1, VAttrType::DIM_HIGH, $3, $5}; }
|
||||
| yD_HYPOT '(' expr ',' expr ')' { $$ = new AstHypotD{$1, $3, $5}; }
|
||||
@ -5441,17 +5444,15 @@ endLabelE<strp>:
|
||||
|
||||
clocking_declaration<nodep>: // IEEE: clocking_declaration
|
||||
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
|
||||
{ $$ = new AstClocking{$<fl>2, "", $3, $5, true}; }
|
||||
{ $$ = new AstClocking{$<fl>2, "", $3, $5, true, false}; }
|
||||
| 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
|
||||
{ $$ = nullptr;
|
||||
BBUNSUP($<fl>2, "Unsupported: global clocking"); }
|
||||
{ $$ = new AstClocking{$<fl>2, "", $3, $5, false, true}; }
|
||||
| yGLOBAL__CLOCKING yCLOCKING idAny clocking_event ';' clocking_itemListE yENDCLOCKING endLabelE
|
||||
{ $$ = nullptr;
|
||||
BBUNSUP($<fl>3, "Unsupported: global clocking"); }
|
||||
{ $$ = new AstClocking{$<fl>3, *$3, $4, $6, false, true}; }
|
||||
;
|
||||
|
||||
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
|
||||
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
|
||||
|
@ -18,6 +18,4 @@ module t(/*AUTOARG*/
|
||||
output edge #1 b;
|
||||
endclocking
|
||||
|
||||
global clocking @(posedge clk);
|
||||
endclocking
|
||||
endmodule
|
||||
|
@ -23,6 +23,11 @@ module t (/*AUTOARG*/
|
||||
.clk (clk),
|
||||
.in (in[31:0]));
|
||||
|
||||
Test3 test3 (/*AUTOINST*/
|
||||
// Inputs
|
||||
.clk (clk),
|
||||
.in (in[31:0]));
|
||||
|
||||
always @ (posedge clk) begin
|
||||
if (cyc!=0) begin
|
||||
cyc <= cyc + 1;
|
||||
@ -69,6 +74,10 @@ module Test (/*AUTOARG*/
|
||||
assert property (@(posedge clk) $fell(dly1) || dly1%2==1);
|
||||
assert property (@(posedge clk) !$stable(dly2));
|
||||
assert property (@(posedge clk) $changed(dly2));
|
||||
|
||||
global clocking @(posedge clk); endclocking
|
||||
always @ ($global_clock) $display("%d", in);
|
||||
|
||||
endmodule
|
||||
|
||||
|
||||
@ -101,3 +110,18 @@ module Test2 (/*AUTOARG*/
|
||||
assert property ($stable(dly2[31:4]));
|
||||
assert property (!$changed(dly2[31:4]));
|
||||
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