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:
Wilson Snyder 2007-01-18 00:51:26 +00:00
parent 8738a51449
commit 895a3264a3
12 changed files with 330 additions and 5 deletions

View File

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

View File

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

View File

@ -156,6 +156,7 @@ RAW_OBJS = \
V3Scope.o \
V3Signed.o \
V3Split.o \
V3SplitAs.o \
V3Stats.o \
V3StatsReport.o \
V3Subst.o \

View File

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

View File

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

204
src/V3SplitAs.cpp Normal file
View File

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

36
src/V3SplitAs.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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