Add isolate_assignments meta comment
git-svn-id: file://localhost/svn/verilator/trunk/verilator@871 77ca24e4-aefa-0310-84f0-b9a241c72d87
This commit is contained in:
parent
8738a51449
commit
895a3264a3
4
Changes
4
Changes
|
|
@ -3,6 +3,10 @@ Revision history for Verilator
|
|||
The contributors that suggested a given feature are shown in []. [by ...]
|
||||
indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
* Verilator 3.63*
|
||||
|
||||
*** Add /*verilator isolate_asignments*/ attribute. [Mike Shinkarovsky]
|
||||
|
||||
* Verilator 3.631 1/2/2007
|
||||
|
||||
** Support standard NAME[#] for cells created by arraying or generate for.
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ desired, but other assertions are, use --assert --nopsl.)
|
|||
=item --bin I<filename>
|
||||
|
||||
Rarely needed. Override the default filename for Verilator itself. When a
|
||||
dependancy (.d) file is created, this filename will become a source
|
||||
dependency (.d) file is created, this filename will become a source
|
||||
dependency, such that a change in this binary will have make rebuild the
|
||||
output files.
|
||||
|
||||
|
|
@ -253,7 +253,7 @@ Enables all forms of coverage, alias for --coverage-line, --coverage-user
|
|||
Specifies basic block line coverage analysis code should be inserted.
|
||||
|
||||
Coverage analysis adds statements at each code flow change point, which are
|
||||
the branches of IF and CASE statements, a superset of normal Verilog Line
|
||||
the branches of IF and CASE statements, a super-set of normal Verilog Line
|
||||
Coverage. At each such branch a unique counter is incremented. At the end
|
||||
of a test, the counters along with the filename and line number
|
||||
corresponding to each counter are written into logs/coverage.pl.
|
||||
|
|
@ -857,7 +857,7 @@ order of magnitude.
|
|||
|
||||
=head1 CROSS COMPILATION
|
||||
|
||||
Verilator supports cross-compling Verilated code. This is generally used
|
||||
Verilator supports cross-compiling Verilated code. This is generally used
|
||||
to run Verilator on a Linux system and produce C++ code that is then compiled
|
||||
on Windows.
|
||||
|
||||
|
|
@ -1096,6 +1096,41 @@ be pure; they cannot reference any variables outside the task itself.
|
|||
Used after a input declaration to indicate the signal should be declared in
|
||||
SystemC as a sc_clock instead of a bool.
|
||||
|
||||
=item /*verilator isolate_asignments*/
|
||||
|
||||
Used after a signal declaration to indicate the assignments to this signal
|
||||
in any blocks should be isolated into new blocks. When there is a large
|
||||
combinatorial block that is resulting in a UNOPTFLAT warning, attaching
|
||||
this to the signal causing a false loop may clear up the problem.
|
||||
|
||||
IE, with the following
|
||||
|
||||
reg splitme /* verilator isolate_asignments*/;
|
||||
always @* begin
|
||||
if (....) begin
|
||||
splitme = ....;
|
||||
other assignments
|
||||
end
|
||||
end
|
||||
|
||||
Verilator will internally split the block that assigns to "splitme" into
|
||||
two blocks:
|
||||
|
||||
It would then internally break it into (sort of):
|
||||
|
||||
// All assignments excluding those to splitme
|
||||
always @* begin
|
||||
if (....) begin
|
||||
other assignments
|
||||
end
|
||||
end
|
||||
// All assignments to splitme
|
||||
always @* begin
|
||||
if (....) begin
|
||||
splitme = ....;
|
||||
end
|
||||
end
|
||||
|
||||
=item /*verilator tracing_off*/
|
||||
|
||||
Disable waveform tracing for all future signals that are declared in this
|
||||
|
|
@ -1515,6 +1550,10 @@ The UNOPTFLAT warning may also be due to clock enables, identified from the
|
|||
reported path going through a clock gating cell. To fix these, use the
|
||||
clock_enable meta comment described above.
|
||||
|
||||
The UNOPTFLAT warning may also occur where outputs from a block of logic
|
||||
are independent, but occur in the same always block. To fix this, use the
|
||||
isolate_asignments meta comment described above.
|
||||
|
||||
=item UNSIGNED
|
||||
|
||||
Warns that you are comparing a unsigned value in a way that implies it is
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ RAW_OBJS = \
|
|||
V3Scope.o \
|
||||
V3Signed.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
V3Stats.o \
|
||||
V3StatsReport.o \
|
||||
V3Subst.o \
|
||||
|
|
|
|||
|
|
@ -350,6 +350,7 @@ void AstVar::dump(ostream& str) {
|
|||
if (isUsedClock()) str<<" [C]";
|
||||
if (isSigPublic()) str<<" [P]";
|
||||
if (attrClockEn()) str<<" [aCLKEN]";
|
||||
if (attrIsolateAssign()) str<<" [aISO]";
|
||||
if (attrFileDescr()) str<<" [aFD]";
|
||||
if (isFuncReturn()) str<<" [FUNCRTN]";
|
||||
else if (isFuncLocal()) str<<" [FUNC]";
|
||||
|
|
|
|||
|
|
@ -241,6 +241,7 @@ private:
|
|||
bool m_funcLocal:1; // Local variable for a function
|
||||
bool m_funcReturn:1; // Return variable for a function
|
||||
bool m_attrClockEn:1;// User clock enable attribute
|
||||
bool m_attrIsolateAssign:1;// User isolate_asignments attribute
|
||||
bool m_fileDescr:1; // File descriptor
|
||||
bool m_isConst:1; // Table contains constant data
|
||||
bool m_isStatic:1; // Static variable
|
||||
|
|
@ -252,7 +253,8 @@ private:
|
|||
m_sc=false; m_scClocked=false; m_scSensitive=false;
|
||||
m_usedClock=false; m_usedParam=false;
|
||||
m_sigPublic=false; m_funcLocal=false; m_funcReturn=false;
|
||||
m_attrClockEn=false; m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
||||
m_attrClockEn=false; m_attrIsolateAssign=false;
|
||||
m_fileDescr=false; m_isConst=false; m_isStatic=false;
|
||||
m_trace=false;
|
||||
}
|
||||
public:
|
||||
|
|
@ -301,6 +303,7 @@ public:
|
|||
void attrClockEn(bool flag) { m_attrClockEn = flag; }
|
||||
void attrFileDescr(bool flag) { m_fileDescr = flag; }
|
||||
void attrScClocked(bool flag) { m_scClocked = flag; }
|
||||
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
|
||||
void usedClock(bool flag) { m_usedClock = flag; }
|
||||
void usedParam(bool flag) { m_usedParam = flag; }
|
||||
void sigPublic(bool flag) { m_sigPublic = flag; }
|
||||
|
|
@ -348,6 +351,7 @@ public:
|
|||
bool attrClockEn() const { return m_attrClockEn; }
|
||||
bool attrFileDescr() const { return m_fileDescr; }
|
||||
bool attrScClocked() const { return m_scClocked; }
|
||||
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
|
||||
int widthAlignBytes() const; // Structure alignment 1,2,4 or 8 bytes (arrays affect this)
|
||||
int widthTotalBytes() const; // Width in bytes rounding up 1,2,4,8,12,...
|
||||
uint32_t msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
|
||||
|
|
@ -359,6 +363,7 @@ public:
|
|||
// Note the method below too
|
||||
if (fromp->attrClockEn()) attrClockEn(true);
|
||||
if (fromp->attrFileDescr()) attrFileDescr(true);
|
||||
if (fromp->attrIsolateAssign()) attrIsolateAssign(true);
|
||||
}
|
||||
bool gateMultiInputOptimizable() const {
|
||||
// Ok to gate optimize; must return false if propagateAttrFrom would do anything
|
||||
|
|
|
|||
|
|
@ -0,0 +1,204 @@
|
|||
// $Id$
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into separate statements to reduce temps
|
||||
//
|
||||
// Code available from: http://www.veripool.com/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2007 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
// V3SplitAs's Transformations:
|
||||
//
|
||||
// Search each ALWAYS for a VARREF lvalue with a /*isolate_asignments*/ attribute
|
||||
// If found, color statements with both, assignment to that varref, or other assignments.
|
||||
// Replicate the Always, and remove mis-colored duplicate code.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include "V3Global.h"
|
||||
#include "V3SplitAs.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
class SplitAsBaseVisitor : public AstNVisitor {
|
||||
public:
|
||||
// METHODS
|
||||
//int debug() { return 9; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Find all split variables in a block
|
||||
|
||||
class SplitAsFindVisitor : public SplitAsBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstVarScope* m_splitVscp; // Variable we want to split
|
||||
|
||||
// METHODS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->lvalue() && !m_splitVscp
|
||||
&& nodep->varp()->attrIsolateAssign()) {
|
||||
m_splitVscp = nodep->varScopep();
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
SplitAsFindVisitor(AstAlways* nodep) {
|
||||
m_splitVscp = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~SplitAsFindVisitor() {}
|
||||
// METHODS
|
||||
AstVarScope* splitVscp() const { return m_splitVscp; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Remove nodes not containing proper references
|
||||
|
||||
class SplitAsCleanVisitor : public SplitAsBaseVisitor {
|
||||
private:
|
||||
// STATE
|
||||
AstVarScope* m_splitVscp; // Variable we want to split
|
||||
bool m_modeMatch; // Remove matching Vscp, else non-matching
|
||||
bool m_keepStmt; // Current Statement must be preserved
|
||||
bool m_matches; // Statement below has matching lvalue reference
|
||||
|
||||
// METHODS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->lvalue()) {
|
||||
if (nodep->varScopep()==m_splitVscp) {
|
||||
UINFO(6," CL VAR "<<nodep<<endl);
|
||||
m_matches = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNodeStmt* nodep, AstNUser*) {
|
||||
UINFO(6," CL STMT "<<nodep<<endl);
|
||||
bool oldKeep = m_keepStmt;
|
||||
{
|
||||
m_matches = false;
|
||||
m_keepStmt = false;
|
||||
|
||||
nodep->iterateChildren(*this);
|
||||
|
||||
if (m_keepStmt
|
||||
|| (m_modeMatch ? m_matches : !m_matches)) {
|
||||
UINFO(6," Keep STMT "<<nodep<<endl);
|
||||
m_keepStmt = true;
|
||||
} else {
|
||||
UINFO(6," Delete STMT "<<nodep<<endl);
|
||||
nodep->unlinkFrBack(); pushDeletep(nodep);
|
||||
}
|
||||
}
|
||||
// If something below matches, the upper statement remains too.
|
||||
m_keepStmt = oldKeep || m_keepStmt;
|
||||
UINFO(9," upKeep="<<m_keepStmt<<" STMT "<<nodep<<endl);
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
SplitAsCleanVisitor(AstAlways* nodep, AstVarScope* vscp, bool modeMatch) {
|
||||
m_splitVscp = vscp;
|
||||
m_modeMatch = modeMatch;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~SplitAsCleanVisitor() {}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// SplitAs class functions
|
||||
|
||||
class SplitAsVisitor : public SplitAsBaseVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// AstAlways::user() -> bool. True if already processed
|
||||
|
||||
// STATE
|
||||
V3Double0 m_statSplits; // Statistic tracking
|
||||
AstVarScope* m_splitVscp; // Variable we want to split
|
||||
|
||||
// METHODS
|
||||
void splitAlways(AstAlways* nodep) {
|
||||
UINFO(3,"Split "<<nodep<<endl);
|
||||
UINFO(3," For "<<m_splitVscp<<endl);
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-in : ");
|
||||
// Duplicate it and link in
|
||||
AstAlways* newp = nodep->cloneTree(false)->castAlways();
|
||||
newp->user(true); // So we don't clone it again
|
||||
nodep->addNextHere(newp);
|
||||
{ // Delete stuff we don't want in old
|
||||
SplitAsCleanVisitor visitor (nodep, m_splitVscp, false);
|
||||
if (debug()>=9) nodep->dumpTree(cout,"-out0: ");
|
||||
}
|
||||
{ // Delete stuff we don't want in new
|
||||
SplitAsCleanVisitor visitor (newp, m_splitVscp, true);
|
||||
if (debug()>=9) newp->dumpTree(cout,"-out1: ");
|
||||
}
|
||||
}
|
||||
|
||||
virtual void visit(AstAlways* nodep, AstNUser*) {
|
||||
// Are there any lvalue references below this?
|
||||
// There could be more then one. So, we process the first one found first.
|
||||
if (!nodep->user()) {
|
||||
SplitAsFindVisitor visitor (nodep);
|
||||
m_splitVscp = visitor.splitVscp();
|
||||
if (m_splitVscp) {
|
||||
splitAlways(nodep);
|
||||
m_statSplits++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Speedup; no always under math
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {}
|
||||
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
SplitAsVisitor(AstNetlist* nodep) {
|
||||
m_splitVscp = NULL;
|
||||
AstNode::userClearTree(); // userp() used on entire tree
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~SplitAsVisitor() {
|
||||
V3Stats::addStat("Optimizations, isolate_assignments blocks", m_statSplits);
|
||||
}
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// SplitAs class functions
|
||||
|
||||
void V3SplitAs::splitAsAll(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
SplitAsVisitor visitor (nodep);
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
// $Id$ //-*- C++ -*-
|
||||
//*************************************************************************
|
||||
// DESCRIPTION: Verilator: Break always into separate statements to reduce temps
|
||||
//
|
||||
// Code available from: http://www.veripool.com/verilator
|
||||
//
|
||||
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
|
||||
//
|
||||
//*************************************************************************
|
||||
//
|
||||
// Copyright 2003-2007 by Wilson Snyder. This program is free software; you can
|
||||
// redistribute it and/or modify it under the terms of either the GNU
|
||||
// General Public License or the Perl Artistic License.
|
||||
//
|
||||
// Verilator is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
//*************************************************************************
|
||||
|
||||
#ifndef _V3SPLITAS_H_
|
||||
#define _V3SPLITAS_H_ 1
|
||||
#include "config_build.h"
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
#include "V3Ast.h"
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3SplitAs {
|
||||
public:
|
||||
static void splitAsAll(AstNetlist* nodep);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
|
@ -71,6 +71,7 @@
|
|||
#include "V3Scope.h"
|
||||
#include "V3Signed.h"
|
||||
#include "V3Split.h"
|
||||
#include "V3SplitAs.h"
|
||||
#include "V3Stats.h"
|
||||
#include "V3Subst.h"
|
||||
#include "V3Table.h"
|
||||
|
|
@ -284,8 +285,10 @@ void process () {
|
|||
// Split single ALWAYS blocks into multiple blocks for better ordering chances
|
||||
if (v3Global.opt.oSplit()) {
|
||||
V3Split::splitAlwaysAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("split.tree"));
|
||||
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("split.tree"));
|
||||
}
|
||||
V3SplitAs::splitAsAll(v3Global.rootp());
|
||||
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("splitas.tree"));
|
||||
|
||||
// Create tracing sample points, before we start eliminating signals
|
||||
if (v3Global.opt.trace()) {
|
||||
|
|
|
|||
|
|
@ -450,6 +450,7 @@ escid \\[^ \t\f\r\n]+
|
|||
<VLG,PSL>"/*verilator public*/" {yylval.fileline = CRELINE(); return yVL_PUBLIC;}
|
||||
<VLG,PSL>"/*verilator public_module*/" {yylval.fileline = CRELINE(); return yVL_PUBLIC_MODULE;}
|
||||
<VLG,PSL>"/*verilator sc_clock*/" {yylval.fileline = CRELINE(); return yVL_CLOCK;}
|
||||
<VLG,PSL>"/*verilator isolate_assignments*/" {yylval.fileline = CRELINE(); return yVL_ISOLATE_ASSIGNMENTS;}
|
||||
<VLG,PSL>"/*verilator systemc_clock*/" {yylval.fileline = CRELINE(); return yVL_CLOCK;}
|
||||
<VLG,PSL>"/*verilator tracing_off*/" {yylval.fileline = CRELINE(); return yVL_TRACING_OFF;}
|
||||
<VLG,PSL>"/*verilator tracing_on*/" {yylval.fileline = CRELINE(); return yVL_TRACING_ON;}
|
||||
|
|
|
|||
|
|
@ -169,6 +169,7 @@ class AstSenTree;
|
|||
%token<fileline> yVL_PARALLEL_CASE "/*verilator parallel_case*/"
|
||||
%token<fileline> yVL_PUBLIC "/*verilator public*/"
|
||||
%token<fileline> yVL_PUBLIC_MODULE "/*verilator public_module*/"
|
||||
%token<fileline> yVL_ISOLATE_ASSIGNMENTS "/*verilator isolate_assignments*/"
|
||||
%token<fileline> yVL_TRACING_OFF "/*verilator tracing_off*/"
|
||||
%token<fileline> yVL_TRACING_ON "/*verilator tracing_on*/"
|
||||
|
||||
|
|
@ -519,6 +520,7 @@ sigAttrList: sigAttr {}
|
|||
sigAttr: yVL_CLOCK { V3Parse::s_varAttrp->attrScClocked(true); }
|
||||
| yVL_CLOCK_ENABLE { V3Parse::s_varAttrp->attrClockEn(true); }
|
||||
| yVL_PUBLIC { V3Parse::s_varAttrp->sigPublic(true); }
|
||||
| yVL_ISOLATE_ASSIGNMENTS { V3Parse::s_varAttrp->attrIsolateAssign(true); }
|
||||
;
|
||||
|
||||
sigList: onesig { $$ = $1; }
|
||||
|
|
|
|||
|
|
@ -69,7 +69,12 @@ module file (/*AUTOARG*/
|
|||
);
|
||||
|
||||
input [31:0] crc;
|
||||
`ifdef ISOLATE
|
||||
output reg [31:0] b /* verilator isolate_assignments*/;
|
||||
`else
|
||||
output reg [31:0] b;
|
||||
`endif
|
||||
|
||||
output reg [31:0] c;
|
||||
output reg [31:0] d;
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# $Id$
|
||||
# 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
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
top_filename("t/t_unopt_combo.v");
|
||||
|
||||
compile (
|
||||
v_flags2 => ['-DISOLATE --stats'],
|
||||
);
|
||||
|
||||
if ($Last_Self->{v3}) {
|
||||
file_grep ($Last_Self->{stats}, qr/Optimizations, isolate_assignments blocks\s+1/i);
|
||||
}
|
||||
|
||||
execute (
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
Loading…
Reference in New Issue