mirror of
https://github.com/verilator/verilator.git
synced 2026-10-03 16:44:11 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30c3540086 | ||
|
|
663a084ca4 | ||
|
|
b4d9ccd9af | ||
|
|
98fff6a4ce | ||
|
|
4977a5e1d9 | ||
|
|
e4297486ef | ||
|
|
ad591767c9 |
@@ -3,6 +3,20 @@ 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.658 2008/02/25
|
||||
|
||||
**** Fix unistd compile error in 3.657. [Patricio Kaplan, Jonathan Kimmitt]
|
||||
|
||||
* Verilator 3.657 2008/02/20
|
||||
|
||||
**** Fix assignments of {a,b,c} = {c,b,a}. [Jonathan Kimmitt]
|
||||
|
||||
**** Fix Perl warning with --lint-only. [by Ding Xiaoliang]
|
||||
|
||||
**** Avoid creating obj_dir with --lint-only. [Ding Xiaoliang]
|
||||
|
||||
**** Fix parsing of always @(*). [Patricio Kaplan]
|
||||
|
||||
* Verilator 3.656 2008/01/18
|
||||
|
||||
**** Wide VL_CONST_W_#X functions are now made automatically. [Bernard Deadman]
|
||||
|
||||
@@ -52,6 +52,10 @@ Usability:
|
||||
Better reporting of unopt problems, including what lines of code
|
||||
Report more errors (all of them?) before exiting [Eugene Weber]
|
||||
|
||||
Internal Code:
|
||||
Eliminate the AstNUser* passed to all visitors; its only needed in V3Width,
|
||||
and removing it will speed up and simplify all the other code.
|
||||
|
||||
Performance:
|
||||
Constant propagation
|
||||
Extra cleaning AND: 1 & ((VARREF >> 1) | ((&VARREF >> 1) & VARREF))
|
||||
|
||||
+2
-1
@@ -91,6 +91,7 @@ if (! GetOptions (
|
||||
"sp!" => sub {$Opt_Sp = 'sp';},
|
||||
"sc!" => sub {$Opt_Sp = 'sc';},
|
||||
"cc!" => sub {$Opt_Sp = 0;},
|
||||
"lint-only!" => sub {$Opt_Sp = 0;},
|
||||
#"ignc!" => ..., # Undocumented debugging, disable $c but don't complain
|
||||
# Additional parameters
|
||||
"<>" => sub {}, # Ignored
|
||||
@@ -434,7 +435,7 @@ to gcc -MP option.
|
||||
=item --Mdir I<directory>
|
||||
|
||||
Specifies the name of the Make object directory. All generated files will
|
||||
be placed in this directory.
|
||||
be placed in this directory. If not specified, "obj_dir" is used.
|
||||
|
||||
=item --mod-prefix I<topname>
|
||||
|
||||
|
||||
+115
-11
@@ -39,11 +39,63 @@
|
||||
#include "V3Width.h"
|
||||
#include "V3Signed.h"
|
||||
|
||||
//######################################################################
|
||||
// Utilities
|
||||
|
||||
class ConstVarMarkVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::userp -> bool, Var marked, 0=not set yet
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->varp()) nodep->varp()->user(1);
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ConstVarMarkVisitor(AstNode* nodep) {
|
||||
AstNode::userClearTree();
|
||||
nodep->iterateAndNext(*this, NULL);
|
||||
}
|
||||
virtual ~ConstVarMarkVisitor() {}
|
||||
};
|
||||
|
||||
class ConstVarFindVisitor : public AstNVisitor {
|
||||
// NODE STATE
|
||||
// AstVar::userp -> bool, input from ConstVarMarkVisitor
|
||||
// MEMBERS
|
||||
bool m_found;
|
||||
private:
|
||||
// VISITORS
|
||||
virtual void visit(AstVarRef* nodep, AstNUser*) {
|
||||
if (nodep->varp() && nodep->varp()->user()) m_found = true;
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
ConstVarFindVisitor(AstNode* nodep) {
|
||||
m_found = false;
|
||||
nodep->iterateAndNext(*this, NULL);
|
||||
}
|
||||
virtual ~ConstVarFindVisitor() {}
|
||||
// METHODS
|
||||
bool found() const { return m_found; }
|
||||
};
|
||||
|
||||
//######################################################################
|
||||
// Const state, as a visitor of each AstNode
|
||||
|
||||
class ConstVisitor : public AstNVisitor {
|
||||
private:
|
||||
// NODE STATE
|
||||
// ** only when m_warn is set. If state is needed other times,
|
||||
// ** must track down everywhere V3Const is called and make sure no overlaps.
|
||||
// AstVar::userp -> Used by ConstVarMarkVisitor/ConstVarFindVisitor
|
||||
|
||||
// STATE
|
||||
bool m_params; // If true, propogate parameterized and true numbers only
|
||||
bool m_required; // If true, must become a constant
|
||||
@@ -494,10 +546,26 @@ private:
|
||||
}
|
||||
}
|
||||
else if (!m_cpp && nodep->lhsp()->castConcat()) {
|
||||
UINFO(4," ASSI "<<nodep<<endl);
|
||||
bool need_temp = false;
|
||||
if (m_warn && !nodep->castAssignDly()) { // Is same var on LHS and RHS?
|
||||
ConstVarMarkVisitor mark(nodep->lhsp());
|
||||
ConstVarFindVisitor find(nodep->rhsp());
|
||||
if (find.found()) need_temp = true;
|
||||
}
|
||||
if (need_temp) {
|
||||
// The first time we constify, there may be the same variable on the LHS
|
||||
// and RHS. In that case, we must use temporaries, or {a,b}={b,a} will break.
|
||||
UINFO(4," ASSITEMP "<<nodep<<endl);
|
||||
// ASSIGN(CONCAT(lc1,lc2),rhs) -> ASSIGN(temp1,SEL(rhs,{size})),
|
||||
// ASSIGN(temp2,SEL(newrhs,{size}))
|
||||
// ASSIGN(lc1,temp1),
|
||||
// ASSIGN(lc2,temp2)
|
||||
} else {
|
||||
UINFO(4," ASSI "<<nodep<<endl);
|
||||
// ASSIGN(CONCAT(lc1,lc2),rhs) -> ASSIGN(lc1,SEL(rhs,{size})),
|
||||
// ASSIGN(lc2,SEL(newrhs,{size}))
|
||||
}
|
||||
if (debug()>=9) nodep->dumpTree(cout," Ass_old: ");
|
||||
// ASSIGN(CONCAT(lc1,lc2),rhs) -> ASSIGN(lc1,SEL(rhs,{size})),
|
||||
// ASSIGN(lc2,SEL(newrhs,{size}))
|
||||
// Unlink the stuff
|
||||
AstNode* lc1p = nodep->lhsp()->castConcat()->lhsp()->unlinkFrBack();
|
||||
AstNode* lc2p = nodep->lhsp()->castConcat()->rhsp()->unlinkFrBack();
|
||||
@@ -517,14 +585,50 @@ private:
|
||||
sel2p->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
// Make new assigns of same flavor as old one
|
||||
//*** Not cloneTree; just one node.
|
||||
AstNodeAssign* asn1p=nodep->cloneType(lc1p, sel1p)->castNodeAssign();
|
||||
AstNodeAssign* asn2p=nodep->cloneType(lc2p, sel2p)->castNodeAssign();
|
||||
asn1p->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn2p->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
nodep->addNextHere(asn1p);
|
||||
nodep->addNextHere(asn2p);
|
||||
if (debug()>=9) asn1p->dumpTree(cout," _new: ");
|
||||
if (debug()>=9) asn2p->dumpTree(cout," _new: ");
|
||||
AstNode* newp = NULL;
|
||||
if (!need_temp) {
|
||||
AstNodeAssign* asn1ap=nodep->cloneType(lc1p, sel1p)->castNodeAssign();
|
||||
AstNodeAssign* asn2ap=nodep->cloneType(lc2p, sel2p)->castNodeAssign();
|
||||
asn1ap->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn2ap->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
newp = newp->addNext(asn1ap);
|
||||
newp = newp->addNext(asn2ap);
|
||||
} else {
|
||||
if (!m_modp) nodep->v3fatalSrc("Not under module");
|
||||
// We could create just one temp variable, but we'll get better optimization
|
||||
// if we make one per term.
|
||||
string name1 = ((string)"__Vconcswap__"+cvtToStr(m_modp->varNumGetInc()));
|
||||
string name2 = ((string)"__Vconcswap__"+cvtToStr(m_modp->varNumGetInc()));
|
||||
AstVar* temp1p = new AstVar(sel1p->fileline(), AstVarType::BLOCKTEMP, name1,
|
||||
new AstRange(sel1p->fileline(), msb1-lsb1, 0));
|
||||
AstVar* temp2p = new AstVar(sel2p->fileline(), AstVarType::BLOCKTEMP, name2,
|
||||
new AstRange(sel2p->fileline(), msb2-lsb2, 0));
|
||||
m_modp->addStmtp(temp1p);
|
||||
m_modp->addStmtp(temp2p);
|
||||
AstNodeAssign* asn1ap=nodep->cloneType
|
||||
(new AstVarRef(sel1p->fileline(), temp1p, true),
|
||||
sel1p)->castNodeAssign();
|
||||
AstNodeAssign* asn2ap=nodep->cloneType
|
||||
(new AstVarRef(sel2p->fileline(), temp2p, true),
|
||||
sel2p)->castNodeAssign();
|
||||
AstNodeAssign* asn1bp=nodep->cloneType
|
||||
(lc1p, new AstVarRef(sel1p->fileline(), temp1p, false))
|
||||
->castNodeAssign();
|
||||
AstNodeAssign* asn2bp=nodep->cloneType
|
||||
(lc2p, new AstVarRef(sel2p->fileline(), temp2p, false))
|
||||
->castNodeAssign();
|
||||
asn1ap->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn1bp->width(msb1-lsb1+1,msb1-lsb1+1);
|
||||
asn2ap->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
asn2bp->width(msb2-lsb2+1,msb2-lsb2+1);
|
||||
// This order matters
|
||||
newp = newp->addNext(asn1ap);
|
||||
newp = newp->addNext(asn2ap);
|
||||
newp = newp->addNext(asn1bp);
|
||||
newp = newp->addNext(asn2bp);
|
||||
}
|
||||
if (debug()>=9) newp->dumpTreeAndNext(cout," _new: ");
|
||||
nodep->addNextHere(newp);
|
||||
// Cleanup
|
||||
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
|
||||
conp->deleteTree(); conp=NULL;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "verilatedos.h"
|
||||
#include <stdarg.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <iomanip>
|
||||
#include <memory>
|
||||
@@ -232,6 +233,14 @@ bool V3File::checkTimes(const string& filename, const string& cmdline) {
|
||||
return dependImp.checkTimes(filename, cmdline);
|
||||
}
|
||||
|
||||
void V3File::createMakeDir() {
|
||||
static bool created = false;
|
||||
if (!created) {
|
||||
created = true;
|
||||
mkdir(v3Global.opt.makeDir().c_str(), 0777);
|
||||
}
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3OutFile: A class for printing to a file, with automatic indentation of C++ code.
|
||||
|
||||
|
||||
@@ -46,6 +46,7 @@ public:
|
||||
return new_ofstream_nodepend (filename, append);
|
||||
}
|
||||
static ofstream* new_ofstream_nodepend(const string& filename, bool append=false) {
|
||||
if (filename != "/dev/null") createMakeDir();
|
||||
if (append) {
|
||||
return new ofstream(filename.c_str(), ios::app);
|
||||
} else {
|
||||
@@ -53,15 +54,20 @@ public:
|
||||
}
|
||||
}
|
||||
static FILE* new_fopen_w(const string& filename) {
|
||||
if (filename != "/dev/null") createMakeDir();
|
||||
addTgtDepend(filename);
|
||||
return fopen(filename.c_str(),"w");
|
||||
}
|
||||
|
||||
// Dependencies
|
||||
static void addSrcDepend(const string& filename);
|
||||
static void addTgtDepend(const string& filename);
|
||||
static void writeDepend(const string& filename);
|
||||
static void writeTimes(const string& filename, const string& cmdline);
|
||||
static bool checkTimes(const string& filename, const string& cmdline);
|
||||
|
||||
// Directory utilities
|
||||
static void createMakeDir();
|
||||
};
|
||||
|
||||
//============================================================================
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <dirent.h>
|
||||
#include <unistd.h>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <map>
|
||||
@@ -226,6 +227,55 @@ string V3Options::filePath (FileLine* fl, const string& modname, const string& e
|
||||
return "";
|
||||
}
|
||||
|
||||
void V3Options::unlinkRegexp(const string& dir, const string& regexp) {
|
||||
if (DIR* dirp = opendir(dir.c_str())) {
|
||||
while (struct dirent* direntp = readdir(dirp)) {
|
||||
if (wildmatch(direntp->d_name, regexp.c_str())) {
|
||||
string fullname = dir + "/" + string(direntp->d_name);
|
||||
unlink (fullname.c_str());
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
}
|
||||
}
|
||||
|
||||
// Double procedures, inlined, unrolls loop much better
|
||||
inline bool V3Options::wildmatchi(const char* s, const char* p) {
|
||||
for ( ; *p; s++, p++) {
|
||||
if (*p!='*') {
|
||||
if (((*s)!=(*p)) && *p != '?')
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// Trailing star matches everything.
|
||||
if (!*++p) return true;
|
||||
while (wildmatch(s, p) == false)
|
||||
if (*++s == '\0')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return(*s == '\0' || *s == '[');
|
||||
}
|
||||
|
||||
bool V3Options::wildmatch(const char* s, const char* p) {
|
||||
for ( ; *p; s++, p++) {
|
||||
if (*p!='*') {
|
||||
if (((*s)!=(*p)) && *p != '?')
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
// Trailing star matches everything.
|
||||
if (!*++p) return true;
|
||||
while (wildmatchi(s, p) == false)
|
||||
if (*++s == '\0')
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return(*s == '\0' || *s == '[');
|
||||
}
|
||||
|
||||
//######################################################################
|
||||
// V3 Options accessors
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ class V3Options {
|
||||
void optimize(int level);
|
||||
void coverage(bool flag) { m_coverageLine = m_coverageUser = flag; }
|
||||
bool onoff(const char* sw, const char* arg, bool& flag);
|
||||
static bool wildmatchi(const char* s, const char* p);
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
@@ -203,12 +204,16 @@ class V3Options {
|
||||
void parseOptsList (FileLine* fl, int argc, char** argv);
|
||||
void parseOptsFile (FileLine* fl, const string& filename);
|
||||
|
||||
// METHODS (generic string utilities)
|
||||
static bool wildmatch(const char* s, const char* p);
|
||||
|
||||
// METHODS (generic file utilities)
|
||||
static string filenameFromDirBase (const string& dir, const string& basename);
|
||||
static string filenameNonDir (const string& filename); ///< Return non-directory part of filename
|
||||
static string filenameNonExt (const string& filename); ///< Return non-extensioned (no .) part of filename
|
||||
static string filenameNonDirExt (const string& filename) { return filenameNonExt(filenameNonDir(filename)); } ///< Return basename of filename
|
||||
static string filenameDir (const string& filename); ///< Return directory part of filename
|
||||
static void unlinkRegexp(const string& dir, const string& regexp);
|
||||
static string getenvStr(const char* envvar, const char* defaultValue) {
|
||||
if (const char* envvalue = getenv(envvar)) {
|
||||
return envvalue;
|
||||
|
||||
+5
-27
@@ -33,6 +33,7 @@
|
||||
#include "V3PreShell.h"
|
||||
#include "V3PreProc.h"
|
||||
#include "V3File.h"
|
||||
#include "V3Read.h"
|
||||
|
||||
//######################################################################
|
||||
|
||||
@@ -64,38 +65,15 @@ protected:
|
||||
}
|
||||
}
|
||||
|
||||
void preproc (FileLine* fl, const string& modname, const string& vppFilename) {
|
||||
void preproc (FileLine* fl, const string& modname, V3Read* readerp) {
|
||||
// Preprocess the given module, putting output in vppFilename
|
||||
unlink(vppFilename.c_str());
|
||||
UINFONL(1," Preprocessing "<<modname<<endl);
|
||||
|
||||
// Open
|
||||
ofstream* ofp = NULL;
|
||||
ostream* osp;
|
||||
if (v3Global.opt.preprocOnly()) {
|
||||
osp = &cout;
|
||||
} else if (!v3Global.opt.keepTempFiles()) { // Must match unlink rule in V3Read.cpp
|
||||
osp = ofp = V3File::new_ofstream_nodepend(vppFilename);
|
||||
} else {
|
||||
osp = ofp = V3File::new_ofstream(vppFilename);
|
||||
}
|
||||
if (osp->fail()) {
|
||||
fl->v3error("Cannot write preprocessor output: "+vppFilename);
|
||||
return;
|
||||
}
|
||||
|
||||
// Preprocess
|
||||
preprocOpen(fl, modname, "Cannot find file containing module: ");
|
||||
while (!s_preprocp->isEof()) {
|
||||
string line = s_preprocp->getline();
|
||||
*osp << line;
|
||||
}
|
||||
|
||||
// Close
|
||||
if (ofp) {
|
||||
ofp->close();
|
||||
delete ofp;
|
||||
osp = ofp = NULL;
|
||||
readerp->ppPushText(line);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -129,8 +107,8 @@ V3PreProc* V3PreShellImp::s_preprocp = NULL;
|
||||
void V3PreShell::boot(char** env) {
|
||||
V3PreShellImp::s_preImp.boot(env);
|
||||
}
|
||||
void V3PreShell::preproc(FileLine* fl, const string& modname, const string& vppFilename) {
|
||||
V3PreShellImp::s_preImp.preproc(fl, modname, vppFilename);
|
||||
void V3PreShell::preproc(FileLine* fl, const string& modname, V3Read* readerp) {
|
||||
V3PreShellImp::s_preImp.preproc(fl, modname, readerp);
|
||||
}
|
||||
void V3PreShell::preprocInclude(FileLine* fl, const string& modname) {
|
||||
V3PreShellImp::s_preImp.preprocInclude(fl, modname);
|
||||
|
||||
+3
-1
@@ -26,13 +26,15 @@
|
||||
#include "verilatedos.h"
|
||||
#include "V3Error.h"
|
||||
|
||||
class V3Read;
|
||||
|
||||
//============================================================================
|
||||
|
||||
class V3PreShell {
|
||||
// Static class for calling preprocessor
|
||||
public:
|
||||
static void boot(char** env);
|
||||
static void preproc(FileLine* fileline, const string& module, const string& vppFilename);
|
||||
static void preproc(FileLine* fileline, const string& module, V3Read* readerp);
|
||||
static void preprocInclude(FileLine* fileline, const string& module);
|
||||
static string dependFiles() { return ""; } // Perl only
|
||||
static void define(const string& name, const string& value);
|
||||
|
||||
+55
-22
@@ -57,7 +57,7 @@ extern int yydebug;
|
||||
class V3Lexer : public V3LexerBase {
|
||||
public:
|
||||
// CONSTRUCTORS
|
||||
V3Lexer(std::istream* arg_yyin) : V3LexerBase(arg_yyin) {}
|
||||
V3Lexer() : V3LexerBase(NULL) {}
|
||||
~V3Lexer() {}
|
||||
// METHODS
|
||||
void stateExitPsl() {
|
||||
@@ -91,6 +91,29 @@ V3Read::~V3Read() {
|
||||
parserClear();
|
||||
}
|
||||
|
||||
int V3Read::ppInputToLex(char* buf, int max_size) {
|
||||
int got = 0;
|
||||
while (got < max_size // Haven't got enough
|
||||
&& !m_ppBuffers.empty()) { // And something buffered
|
||||
string front = m_ppBuffers.front(); m_ppBuffers.pop_front();
|
||||
int len = front.length();
|
||||
if (len > (max_size-got)) { // Front string too big
|
||||
string remainder = front.substr(max_size-got);
|
||||
front = front.substr(0, max_size-got);
|
||||
m_ppBuffers.push_front(remainder); // Put back remainder for next time
|
||||
len = (max_size-got);
|
||||
}
|
||||
strncpy(buf+got, front.c_str(), len);
|
||||
got += len;
|
||||
}
|
||||
if (debug()>=9) {
|
||||
string out = string(buf,got);
|
||||
cout<<" inputToLex got="<<got<<" '"<<out<<"'"<<endl;
|
||||
}
|
||||
// Note returns 0 at EOF
|
||||
return got;
|
||||
}
|
||||
|
||||
void V3Read::readFile(FileLine* fileline, const string& modfilename, bool inLibrary) {
|
||||
string modname = V3Options::filenameNonExt(modfilename);
|
||||
|
||||
@@ -98,42 +121,52 @@ void V3Read::readFile(FileLine* fileline, const string& modfilename, bool inLibr
|
||||
m_fileline = new FileLine(fileline);
|
||||
m_inLibrary = inLibrary;
|
||||
|
||||
// Read it
|
||||
string vppfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_"+modname+".vpp";
|
||||
V3PreShell::preproc(fileline, modfilename, vppfilename);
|
||||
// Preprocess into m_ppBuffer
|
||||
V3PreShell::preproc(fileline, modfilename, this);
|
||||
|
||||
if (!v3Global.opt.preprocOnly()) {
|
||||
lexFile (vppfilename, modfilename);
|
||||
if (v3Global.opt.preprocOnly() || v3Global.opt.keepTempFiles()) {
|
||||
// Create output file with all the preprocessor output we buffered up
|
||||
string vppfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_"+modname+".vpp";
|
||||
ofstream* ofp = NULL;
|
||||
ostream* osp;
|
||||
if (v3Global.opt.preprocOnly()) {
|
||||
osp = &cout;
|
||||
} else {
|
||||
osp = ofp = V3File::new_ofstream(vppfilename);
|
||||
}
|
||||
if (osp->fail()) {
|
||||
fileline->v3error("Cannot write preprocessor output: "+vppfilename);
|
||||
return;
|
||||
} else {
|
||||
for (deque<string>::iterator it = m_ppBuffers.begin(); it!=m_ppBuffers.end(); ++it) {
|
||||
*osp << *it;
|
||||
}
|
||||
if (ofp) {
|
||||
ofp->close();
|
||||
delete ofp; ofp = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!v3Global.opt.keepTempFiles()) { // Must match new_ofstream_nodepend rule in V3PreShell.cpp
|
||||
unlink (vppfilename.c_str());
|
||||
// Parse it
|
||||
if (!v3Global.opt.preprocOnly()) {
|
||||
lexFile (modfilename);
|
||||
}
|
||||
}
|
||||
|
||||
void V3Read::lexFile(const string& vppfilename, const string& modname) {
|
||||
// Open the preprocess output
|
||||
// Don't track a input dependency, as we created the file ourselves
|
||||
ifstream* fsp = V3File::new_ifstream_nodepend(vppfilename);
|
||||
if (fsp->fail()) {
|
||||
m_fileline->v3fatal("Module "<<modname<<" isn't found, or preprocessor errors in "<<vppfilename);
|
||||
}
|
||||
|
||||
void V3Read::lexFile(const string& modname) {
|
||||
// Prepare for lexing
|
||||
UINFO(3,"Lexing "<<vppfilename<<endl);
|
||||
UINFO(3,"Lexing "<<modname<<endl);
|
||||
V3Read::s_readp = this;
|
||||
V3Read::fileline()->warnResetDefault(); // Reenable warnings on each file
|
||||
if (m_lexerp) delete m_lexerp; // Restart from clean slate.
|
||||
m_lexerp = new V3Lexer(fsp);
|
||||
m_lexerp = new V3Lexer();
|
||||
// if (debug()) { m_lexerp->set_debug(~0); }
|
||||
// if (debug()) yydebug = 1;
|
||||
UINFO(4,"Lexing Done "<<vppfilename<<endl);
|
||||
UINFO(4,"Lexing Done "<<modname<<endl);
|
||||
|
||||
// Lex it
|
||||
if (yyparse()) v3fatal("Cannot continue\n");
|
||||
|
||||
// Cleanup
|
||||
fsp->close(); delete fsp; fsp = NULL;
|
||||
}
|
||||
|
||||
//======================================================================
|
||||
|
||||
+7
-1
@@ -45,6 +45,7 @@ class V3Read {
|
||||
deque<string*> m_stringps; // Created strings for later cleanup
|
||||
deque<V3Number*> m_numberps; // Created numbers for later cleanup
|
||||
deque<FileLine> m_lintState; // Current lint state for save/restore
|
||||
deque<string> m_ppBuffers; // Preprocessor->lex buffer of characters to process
|
||||
//int debug() { return 9; }
|
||||
|
||||
protected:
|
||||
@@ -52,6 +53,7 @@ protected:
|
||||
friend class V3Lexer;
|
||||
friend class V3LexerBase;
|
||||
friend class FileLine;
|
||||
friend class V3PreShellImp;
|
||||
int yylexThis();
|
||||
static bool optPsl();
|
||||
static void ppline (const char* text);
|
||||
@@ -64,6 +66,9 @@ protected:
|
||||
static bool popBeginKeywords() { if (s_readp->m_inBeginKwd) { s_readp->m_inBeginKwd--; return true; } else return false; }
|
||||
static int lastVerilogState() { return s_readp->m_lastVerilogState; }
|
||||
|
||||
void ppPushText(const string& text) { m_ppBuffers.push_back(text); }
|
||||
int ppInputToLex(char* buf, int max_size);
|
||||
|
||||
public: // But for internal use only
|
||||
static string* newString(const string& text) {
|
||||
// Allocate a string, remembering it so we can reclaim storage at lex end
|
||||
@@ -100,6 +105,7 @@ public: // But for internal use only
|
||||
static void statePushVlg(); // Parser -> lexer communication
|
||||
static void statePop(); // Parser -> lexer communication
|
||||
static int stateVerilogRecent(); // Parser -> lexer communication
|
||||
static int flexPpInputToLex(char* buf, int max_size) { return s_readp->ppInputToLex(buf,max_size); }
|
||||
|
||||
public:
|
||||
// CREATORS
|
||||
@@ -118,7 +124,7 @@ public:
|
||||
void readFile(FileLine* fileline, const string& modname, bool inLibrary);
|
||||
|
||||
private:
|
||||
void lexFile(const string& vppfilename, const string& modname);
|
||||
void lexFile(const string& modname);
|
||||
};
|
||||
|
||||
#endif // Guard
|
||||
|
||||
+4
-7
@@ -464,6 +464,7 @@ void process () {
|
||||
V3EmitC::emitcSyms();
|
||||
V3EmitC::emitcTrace();
|
||||
}
|
||||
// Unfortunately we have some lint checks in emitc.
|
||||
V3EmitC::emitc();
|
||||
|
||||
// Statistics
|
||||
@@ -521,13 +522,9 @@ int main(int argc, char** argv, char** env) {
|
||||
//--FRONTEND------------------
|
||||
|
||||
// Cleanup
|
||||
mkdir(v3Global.opt.makeDir().c_str(), 0777);
|
||||
string cleanFilename = "/bin/rm -rf "+v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_*.tree";
|
||||
system(cleanFilename.c_str());
|
||||
cleanFilename = "/bin/rm -rf "+v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_*.dot";
|
||||
system(cleanFilename.c_str());
|
||||
cleanFilename = "/bin/rm -rf "+v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_*.txt";
|
||||
system(cleanFilename.c_str());
|
||||
V3Options::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.tree");
|
||||
V3Options::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.dot");
|
||||
V3Options::unlinkRegexp(v3Global.opt.makeDir(), v3Global.opt.prefix()+"_*.txt");
|
||||
|
||||
// Read first filename
|
||||
v3Global.readFiles();
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
//**********************************************************************
|
||||
//**** Version and host name
|
||||
|
||||
#define DTVERSION "Verilator 3.656 2008/01/18"
|
||||
#define DTVERSION "Verilator 3.658 2008/01/18"
|
||||
|
||||
//**********************************************************************
|
||||
//**** Functions
|
||||
|
||||
+4
-1
@@ -33,6 +33,9 @@ extern void yyerrorf(const char* format, ...);
|
||||
|
||||
#define STATE_VERILOG_RECENT S05 // State name for most recent Verilog Version
|
||||
|
||||
#define YY_INPUT(buf,result,max_size) \
|
||||
result = V3Read::flexPpInputToLex(buf,max_size);
|
||||
|
||||
//======================================================================
|
||||
|
||||
#define NEXTLINE() {V3Read::incLineno();}
|
||||
@@ -698,7 +701,7 @@ escid \\[^ \t\f\r\n]+
|
||||
/************************************************************************/
|
||||
/* Attributes */
|
||||
<V95,V01,V05,S05>{
|
||||
"(*" { yymore(); yy_push_state(ATTRMODE); }
|
||||
"(*"/{ws}*[^)] { yymore(); yy_push_state(ATTRMODE); } // Doesn't match (*)
|
||||
}
|
||||
|
||||
/************************************************************************/
|
||||
|
||||
+7
-7
@@ -526,15 +526,15 @@ regsigList: regsig { $$ = $1; }
|
||||
| regsigList ',' regsig { $$ = $1;$1->addNext($3); }
|
||||
;
|
||||
|
||||
portV2kDecl: varRESET varInput signingE v2kNetDeclE regrangeE portV2kSig { $$ = $6; }
|
||||
| varRESET varInout signingE v2kNetDeclE regrangeE portV2kSig { $$ = $6; }
|
||||
| varRESET varOutput signingE v2kVarDeclE regrangeE portV2kSig { $$ = $6; }
|
||||
portV2kDecl: varRESET varInput v2kNetDeclE signingE regrangeE portV2kSig { $$ = $6; }
|
||||
| varRESET varInout v2kNetDeclE signingE regrangeE portV2kSig { $$ = $6; }
|
||||
| varRESET varOutput v2kVarDeclE signingE regrangeE portV2kSig { $$ = $6; }
|
||||
;
|
||||
|
||||
// IEEE: port_declaration - plus ';'
|
||||
portDecl: varRESET varInput signingE v2kVarDeclE regrangeE sigList ';' { $$ = $6; }
|
||||
| varRESET varInout signingE v2kVarDeclE regrangeE sigList ';' { $$ = $6; }
|
||||
| varRESET varOutput signingE v2kVarDeclE regrangeE sigList ';' { $$ = $6; }
|
||||
portDecl: varRESET varInput v2kVarDeclE signingE regrangeE sigList ';' { $$ = $6; }
|
||||
| varRESET varInout v2kVarDeclE signingE regrangeE sigList ';' { $$ = $6; }
|
||||
| varRESET varOutput v2kVarDeclE signingE regrangeE sigList ';' { $$ = $6; }
|
||||
;
|
||||
|
||||
varDecl: varRESET varReg signingE regrangeE regsigList ';' { $$ = $5; }
|
||||
@@ -838,7 +838,7 @@ eventControlE: /* empty */ { $$ = NULL; }
|
||||
// IEEE: event_control
|
||||
eventControl: '@' '(' senList ')' { $$ = new AstSenTree($1,$3); }
|
||||
| '@' senitemVar { $$ = new AstSenTree($1,$2); } /* For events only */
|
||||
| '@' '(' '*' ')' { $$ = NULL; $2->v3error("Use @*. always @ (*) to be depreciated in Verilog 2005.\n"); }
|
||||
| '@' '(' '*' ')' { $$ = NULL; } /* Verilog 2001 */
|
||||
| '@' '*' { $$ = NULL; } /* Verilog 2001 */
|
||||
;
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
// please note it here, otherwise:**
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2007 by Wilson Snyder.
|
||||
// without warranty, 2008 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// $Id:$
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
@@ -14,7 +14,7 @@ module t (/*AUTOARG*/
|
||||
|
||||
reg [31:0] a, b, c;
|
||||
|
||||
always @ (/*AS*/a or b) begin
|
||||
always @ (*) begin // Test Verilog 2001 (*)
|
||||
// verilator lint_off COMBDLY
|
||||
c <= a | b;
|
||||
// verilator lint_on COMBDLY
|
||||
|
||||
@@ -15,21 +15,24 @@ module t (/*AUTOARG*/
|
||||
reg [63:0] crc;
|
||||
reg [63:0] sum;
|
||||
|
||||
reg [31:0] out1;
|
||||
sub sub (.in1(crc[15:0]), .in2(crc[31:16]), .out1(out1));
|
||||
wire [31:0] out1;
|
||||
wire [31:0] out2;
|
||||
sub sub (.in1(crc[15:0]), .in2(crc[31:16]), .out1(out1), .out2);
|
||||
|
||||
always @ (posedge clk) begin
|
||||
//$write("[%0t] cyc==%0d crc=%x sum=%x out=%x\n",$time, cyc, crc, sum, out1);
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] cyc==%0d crc=%x sum=%x out=%x %x\n",$time, cyc, crc, sum, out1, out2);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
sum <= {sum[62:0], sum[63]^sum[2]^sum[0]} ^ {32'h0,out1};
|
||||
sum <= {sum[62:0], sum[63]^sum[2]^sum[0]} ^ {out2,out1};
|
||||
if (cyc==1) begin
|
||||
// Setup
|
||||
crc <= 64'h00000000_00000097;
|
||||
sum <= 64'h0;
|
||||
end
|
||||
else if (cyc==90) begin
|
||||
if (sum !== 64'hc1f743ad62c2c04d) $stop;
|
||||
if (sum !== 64'he396068aba3898a2) $stop;
|
||||
end
|
||||
else if (cyc==91) begin
|
||||
end
|
||||
@@ -49,18 +52,20 @@ endmodule
|
||||
|
||||
module sub (/*AUTOARG*/
|
||||
// Outputs
|
||||
out1,
|
||||
out1, out2,
|
||||
// Inputs
|
||||
in1, in2
|
||||
);
|
||||
|
||||
input [15:0] in1;
|
||||
input [15:0] in2;
|
||||
output reg [31:0] out1;
|
||||
output reg signed [31:0] out1;
|
||||
output reg unsigned [31:0] out2;
|
||||
|
||||
always @* begin
|
||||
// verilator lint_off WIDTH
|
||||
out1 = $signed(in1) * $signed(in2);
|
||||
out2 = $unsigned(in1) * $unsigned(in2);
|
||||
// verilator lint_on WIDTH
|
||||
end
|
||||
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/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.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,165 @@
|
||||
// $Id$
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2008 by Wilson Snyder.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
integer cyc=0;
|
||||
reg [63:0] crc;
|
||||
reg [63:0] sum;
|
||||
|
||||
// Take CRC data and apply to testblock inputs
|
||||
wire [31:0] Operand1 = crc[31:0];
|
||||
wire [15:0] Operand2 = crc[47:32];
|
||||
wire Unsigned = crc[48];
|
||||
reg rst;
|
||||
|
||||
parameter wl = 16;
|
||||
|
||||
/*AUTOWIRE*/
|
||||
// Beginning of automatic wires (for undeclared instantiated-module outputs)
|
||||
wire [wl-1:0] Quotient; // From test of Test.v
|
||||
wire [wl-1:0] Remainder; // From test of Test.v
|
||||
// End of automatics
|
||||
|
||||
Test test (/*AUTOINST*/
|
||||
// Outputs
|
||||
.Quotient (Quotient[wl-1:0]),
|
||||
.Remainder (Remainder[wl-1:0]),
|
||||
// Inputs
|
||||
.Operand1 (Operand1[wl*2-1:0]),
|
||||
.Operand2 (Operand2[wl-1:0]),
|
||||
.clk (clk),
|
||||
.rst (rst),
|
||||
.Unsigned (Unsigned));
|
||||
|
||||
// Aggregate outputs into a single result vector
|
||||
wire [63:0] result = {32'h0, Quotient, Remainder};
|
||||
|
||||
// What checksum will we end up with
|
||||
`define EXPECTED_SUM 64'h98d41f89a8be5693
|
||||
|
||||
// Test loop
|
||||
always @ (posedge clk) begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$write("[%0t] cyc==%0d crc=%x result=%x it=%x\n",$time, cyc, crc, result, test.Iteration);
|
||||
`endif
|
||||
cyc <= cyc + 1;
|
||||
if (cyc < 20 || test.Iteration==4'd15) begin
|
||||
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
|
||||
end
|
||||
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
|
||||
if (cyc==0) begin
|
||||
// Setup
|
||||
crc <= 64'h5aef0c8d_d70a4497;
|
||||
rst <= 1'b1;
|
||||
end
|
||||
else if (cyc<20) begin
|
||||
sum <= 64'h0;
|
||||
rst <= 1'b0;
|
||||
end
|
||||
else if (cyc<90) begin
|
||||
end
|
||||
else if (cyc==99) begin
|
||||
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
|
||||
if (crc !== 64'h8dd70a44972ad809) $stop;
|
||||
if (sum !== `EXPECTED_SUM) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module Test(clk, rst, Operand1, Operand2, Unsigned, Quotient, Remainder);
|
||||
|
||||
parameter wl = 16;
|
||||
|
||||
input [wl*2-1:0] Operand1;
|
||||
input [wl-1:0] Operand2;
|
||||
input clk, rst, Unsigned;
|
||||
output [wl-1:0] Quotient, Remainder;
|
||||
|
||||
reg Cy, Overflow, Sign1, Sign2, Zero, Negative;
|
||||
reg [wl-1:0] ah,al,Quotient, Remainder;
|
||||
reg [3:0] Iteration;
|
||||
reg [wl-1:0] sub_quot,op;
|
||||
reg ah_ext;
|
||||
|
||||
reg [1:0] a,b,c,d,e;
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (!rst) begin
|
||||
{a,b,c,d,e} = Operand1[9:0];
|
||||
{a,b,c,d,e} = {e,d,c,b,a};
|
||||
if (a != Operand1[1:0]) $stop;
|
||||
if (b != Operand1[3:2]) $stop;
|
||||
if (c != Operand1[5:4]) $stop;
|
||||
if (d != Operand1[7:6]) $stop;
|
||||
if (e != Operand1[9:8]) $stop;
|
||||
end
|
||||
end
|
||||
|
||||
always @(posedge clk) begin
|
||||
if (rst) begin
|
||||
Iteration <= 0;
|
||||
Quotient <= 0;
|
||||
Remainder <= 0;
|
||||
end
|
||||
else begin
|
||||
if (Iteration == 0) begin
|
||||
{ah,al} = Operand1;
|
||||
op = Operand2;
|
||||
Cy = 0;
|
||||
Overflow = 0;
|
||||
Sign1 = (~Unsigned)&ah[wl-1];
|
||||
Sign2 = (~Unsigned)&(ah[wl-1]^op[wl-1]);
|
||||
if (Sign1) {ah,al} = -{ah,al};
|
||||
end
|
||||
`define BUG1
|
||||
`ifdef BUG1
|
||||
{ah_ext,ah,al} = {ah,al,Cy};
|
||||
`else
|
||||
ah_ext = ah[15];
|
||||
ah[15:1] = ah[14:0];
|
||||
ah[0] = al[15];
|
||||
al[15:1] = al[14:0];
|
||||
al[0] = Cy;
|
||||
`endif
|
||||
`ifdef TEST_VERBOSE
|
||||
$display("%x %x %x %x %x %x %x %x %x",
|
||||
Iteration, ah, al, Quotient, Remainder, Overflow, ah_ext, sub_quot, Cy);
|
||||
`endif
|
||||
{Cy,sub_quot} = (~Unsigned)&op[wl-1]? {ah_ext,ah}+op : {ah_ext,ah} - {1'b1,op};
|
||||
if (Cy)
|
||||
begin
|
||||
{ah_ext,ah} = {1'b0,sub_quot};
|
||||
end
|
||||
if (Iteration != 15 )
|
||||
begin
|
||||
if (ah_ext) Overflow = 1;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if (al[14] && ~Unsigned) Overflow = 1;
|
||||
Quotient <= Sign2 ? -{al[14:0],Cy} : {al[14:0],Cy};
|
||||
Remainder <= Sign1 ? -ah : ah;
|
||||
if (Overflow)
|
||||
begin
|
||||
Quotient <= Sign2 ? 16'h8001 : {Unsigned,{15{1'b1}}};
|
||||
Remainder <= Unsigned ? 16'hffff : 16'h8000;
|
||||
Zero = 1;
|
||||
Negative = 1;
|
||||
end
|
||||
end
|
||||
Iteration <= Iteration + 1; // Count number of times this instruction is repeated
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("./driver.pl", @ARGV, $0); die; }
|
||||
# General Public License or the Perl Artistic License.
|
||||
|
||||
compile (
|
||||
v_flags2 => ["--lint-only"],
|
||||
v_flags2 => ["--lint-only --Mdir obj_lint_only"],
|
||||
fails=>1,
|
||||
expect=>
|
||||
'%Error: t/t_var_in_assign_bad.v:\d+: Assigning to input variable: value
|
||||
@@ -16,5 +16,6 @@ compile (
|
||||
%Error: Exiting due to.*',
|
||||
) if $Last_Self->{v3};
|
||||
|
||||
(!-d "obj_lint_only") or $Last_Self->error("%Error: lint-only shouldn't make output directory");
|
||||
ok(1);
|
||||
1;
|
||||
|
||||
Reference in New Issue
Block a user