Merge branch 'master' of ssh://git-verilator-wsnyder/git/verilator

This commit is contained in:
Wilson Snyder 2011-07-26 18:30:25 -04:00
commit 4bfea7f54d
47 changed files with 1926 additions and 880 deletions

View File

@ -5,12 +5,16 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.814****
** Support 'real' numbers and related functions.
*** Support 'const' variables in limited cases; similar to enums. [Alex Solomatnikov]
*** Support disable for loop escapes.
*** Support $fopen and I/O with integer instead of `verilator_file_descriptor.
**** Fix $display missing leading zeros in %0d, bug367. [Alex Solomatnikov]
**** Use 'vluint64_t' for SystemC instead of (same sized) 'uint64' for MSVC++.
* Verilator 3.813 2011/06/28

View File

@ -930,8 +930,8 @@ Enables the specified warning message.
Enable all lint related warning messages (note by default they are already
enabled), but do not affect style messages. This is equivalent to
"-Wwarn-CASEINCOMPLETE -Wwarn-CASEOVERLAP -Wwarn-CASEX -Wwarn-CASEWITHX
-Wwarn-CMPCONST -Wwarn-IMPLICIT -Wwarn-LITENDIAN -Wwarn-UNSIGNED
-Wwarn-WIDTH".
-Wwarn-CMPCONST -Wwarn-IMPLICIT -Wwarn-LITENDIAN -Wwarn-REALCVT
-Wwarn-UNSIGNED -Wwarn-WIDTH".
=item -Wwarn-style
@ -2096,7 +2096,7 @@ that Verilator will print a list of known scopes to help your debugging.
=head2 Floating Point
Floating Point numbers are not synthesizable, and so not supported.
Floating Point (real) numbers are supported.
=head2 Latches
@ -2336,10 +2336,6 @@ Read memory commands should work properly. Note Verilator and the Verilog
specification does not include support for readmem to multi-dimensional
arrays.
=item $realtime
Treated as $time.
=item $test$plusargs, $value$plusargs
Supported, but the instantiating C++/SystemC testbench must call
@ -2619,6 +2615,11 @@ not really needed. The best solution is to insure that each module is in a
unique file by the same name. Otherwise, make sure all library files are
read in as libraries with -v, instead of automatically with -y.
=item REALCVT
Warns that a real number is being implicitly rounded to an integer, with
possible loss of precision.
=item REDEFMACRO
Warns that you have redefined the same macro with a different value, for

View File

@ -284,12 +284,15 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
// Note also assumes variables < 64 are not wide, this assumption is
// sometimes not true in low-level routines written here in verilated.cpp
static VL_THREAD char tmp[VL_VALUE_STRING_MAX_WIDTH];
static VL_THREAD char tmpf[VL_VALUE_STRING_MAX_WIDTH];
const char* pctp = NULL; // Most recent %##.##g format
bool inPct = false;
bool widthSet = false;
int width = 0;
const char* pos = formatp;
for (; *pos; ++pos) {
if (!inPct && pos[0]=='%') {
pctp = pos;
inPct = true;
widthSet = false;
width = 0;
@ -311,6 +314,9 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
widthSet = true;
width = width*10 + (fmt - '0');
break;
case '.':
inPct = true; // Get more digits
break;
case '%':
output += '%';
break;
@ -324,6 +330,16 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
output += cstrp;
break;
}
case 'e':
case 'f':
case 'g': {
double d = va_arg(ap, double);
strncpy(tmpf, pctp, pos-pctp+1);
tmpf[pos-pctp+1] = '\0';
sprintf(tmp, tmpf, d);
output += tmp;
break;
}
default: {
// Deal with all read-and-print somethings
const int lbits = va_arg(ap, int);
@ -357,14 +373,26 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
case 'd': { // Signed decimal
int digits=sprintf(tmp,"%" VL_PRI64 "d",(vlsint64_t)(VL_EXTENDS_QQ(lbits,lbits,ld)));
int needmore = width-digits;
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
if (needmore>0) {
if (pctp && pctp[0] && pctp[1]=='0') { //%0
output.append(needmore,'0'); // Pre-pad zero
} else {
output.append(needmore,' '); // Pre-pad spaces
}
}
output += tmp;
break;
}
case 'u': { // Unsigned decimal
int digits=sprintf(tmp,"%" VL_PRI64 "u",ld);
int needmore = width-digits;
if (needmore>0) output.append(needmore,' '); // Pre-pad spaces
if (needmore>0) {
if (pctp && pctp[0] && pctp[1]=='0') { //%0
output.append(needmore,'0'); // Pre-pad zero
} else {
output.append(needmore,' '); // Pre-pad spaces
}
}
output += tmp;
break;
}

View File

@ -35,6 +35,7 @@
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
// <iostream> avoided to reduce compile time
// <string> avoided and instead in verilated_heavy.h to reduce compile time
using namespace std;
@ -374,6 +375,16 @@ extern FILE* VL_CVT_I_FP(IData lhs);
static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; }
/// Return QData from void*
static inline QData VL_CVT_VP_Q(void* fp) { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
/// Return double from QData (bits, not numerically)
static inline double VL_CVT_D_Q(QData lhs) { union { double d; QData q; } u; u.q=lhs; return u.d; }
/// Return QData from double (bits, not numerically)
static inline QData VL_CVT_Q_D(double lhs) { union { double d; QData q; } u; u.d=lhs; return u.q; }
/// Return double from QData (numeric)
static inline double VL_ITOR_D_I(IData lhs) { return ((double)((vlsint32_t)(lhs))); }
/// Return QData from double (numeric)
static inline IData VL_RTOI_I_D(double lhs) { return ((vlsint32_t)(trunc(lhs))); }
/// Return QData from double (numeric)
static inline IData VL_RTOIROUND_I_D(double lhs) { return ((vlsint32_t)(round(lhs))); }
// Sign extend such that if MSB set, we get ffff_ffff, else 0s
// (Requires clean input)
@ -403,9 +414,11 @@ void _VL_DEBUG_PRINT_W(int lbits, WDataInP iwp);
#if defined(SYSTEMC_VERSION) && (SYSTEMC_VERSION>20011000)
# define VL_TIME_I() ((IData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
# define VL_TIME_Q() ((QData)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
# define VL_TIME_D() ((double)(sc_time_stamp().to_default_time_units()*VL_TIME_MULTIPLIER))
#else
# define VL_TIME_I() ((IData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
# define VL_TIME_Q() ((QData)(sc_time_stamp()*VL_TIME_MULTIPLIER))
# define VL_TIME_D() ((double)(sc_time_stamp()*VL_TIME_MULTIPLIER))
extern double sc_time_stamp();
#endif

View File

@ -209,7 +209,6 @@ RAW_OBJS = \
V3PreShell.o \
V3Premit.o \
V3Scope.o \
V3Signed.o \
V3Slice.o \
V3Split.o \
V3SplitAs.o \

View File

@ -74,7 +74,9 @@ void AstNode::init() {
m_clonep = NULL;
m_cloneCnt = 0;
// Attributes
m_signed = false;
m_numeric = (int)AstNumeric::UNSIGNED;
m_didWidth = false;
m_doingWidth = false;
m_width = 0;
m_widthMin = 0;
m_user1p = NULL;
@ -873,7 +875,7 @@ bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext) {
if (this==NULL || node2p==NULL) return false;
if (this->type() != node2p->type()
|| this->width() != node2p->width()
|| this->isSigned() != node2p->isSigned()
|| this->numeric() != node2p->numeric()
|| !this->same(node2p)) {
return false;
}

View File

@ -56,6 +56,36 @@ public:
//######################################################################
class AstNumeric {
public:
enum en {
UNSIGNED,
SIGNED,
DOUBLE
// Limited to 2 bits, unless change V3Ast's packing function
};
enum en m_e;
const char* ascii() const {
static const char* names[] = {
"UNSIGNED","SIGNED","DOUBLE"
};
return names[m_e];
};
inline AstNumeric () {}
inline AstNumeric (en _e) : m_e(_e) {}
explicit inline AstNumeric (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
inline bool isDouble() const { return m_e==DOUBLE; }
inline bool isSigned() const { return m_e==SIGNED; }
inline bool isUnsigned() const { return m_e==UNSIGNED; }
};
inline bool operator== (AstNumeric lhs, AstNumeric rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstNumeric lhs, AstNumeric::en rhs) { return (lhs.m_e == rhs); }
inline bool operator== (AstNumeric::en lhs, AstNumeric rhs) { return (lhs == rhs.m_e); }
inline ostream& operator<<(ostream& os, AstNumeric rhs) { return os<<rhs.ascii(); }
//######################################################################
class AstPragmaType {
public:
enum en {
@ -209,7 +239,7 @@ class AstBasicDTypeKwd {
public:
enum en {
BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT,
REAL, SHORTINT, SHORTREAL, TIME,
DOUBLE, SHORTINT, FLOAT, TIME,
// Closer to a class type, but limited usage
STRING,
// Internal types for mid-steps
@ -251,8 +281,8 @@ public:
case INTEGER: return 32;
case LOGIC: return 1;
case LONGINT: return 64;
case REAL: return 64;
case SHORTREAL: return 32;
case DOUBLE: return 64;
case FLOAT: return 32;
case SHORTINT: return 16;
case TIME: return 64;
case STRING: return 64; // Just the pointer, for today
@ -267,7 +297,7 @@ public:
}
bool isZeroInit() const { // Otherwise initializes to X
return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT
|| m_e==STRING || m_e==REAL || m_e==SHORTREAL);
|| m_e==STRING || m_e==DOUBLE || m_e==FLOAT);
}
bool isSloppy() const { // Don't be as anal about width warnings
return !(m_e==LOGIC || m_e==BIT);
@ -279,10 +309,10 @@ public:
return (m_e==LOGIC || m_e==TIME);
}
bool isOpaque() const { // IE not a simple number we can bit optimize
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==REAL || m_e==SHORTREAL);
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==DOUBLE || m_e==FLOAT);
}
bool isReal() const {
return (m_e==REAL);
bool isDouble() const {
return (m_e==DOUBLE);
}
};
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
@ -689,7 +719,9 @@ class AstNode {
static int s_cloneCntGbl; // Count of which userp is set
// Attributes
bool m_signed:1; // Node is signed
uint32_t m_numeric:2; // Node is real/signed - important that bitfields remain unsigned
bool m_didWidth:1; // Did V3Width computation
bool m_doingWidth:1; // Inside V3Width
// // Space for more bools here
int m_width; // Bit width of operation
@ -785,6 +817,8 @@ public:
static int instrCountLd() { return 2; } ///< Instruction cycles to load memory
static int instrCountMul() { return 3; } ///< Instruction cycles to multiply integers
static int instrCountPli() { return 20; } ///< Instruction cycles to call pli routines
static int instrCountDouble() { return 8; } ///< Instruction cycles to convert or do floats
static int instrCountDoubleDiv() { return 40; } ///< Instruction cycles to divide floats
static int instrCountCall() { return instrCountBranch()+10; } ///< Instruction cycles to call subroutine
static int instrCountTime() { return instrCountCall()+5; } ///< Instruction cycles to determine simulation time
@ -812,10 +846,18 @@ public:
bool widthSized() const { return !m_widthMin || m_widthMin==m_width; }
void width(int width, int sized) { m_width=width; m_widthMin=sized; }
void widthFrom(AstNode* fromp) { if (fromp) { m_width=fromp->m_width; m_widthMin=fromp->m_widthMin; }}
void widthSignedFrom(AstNode* fromp) { widthFrom(fromp); signedFrom(fromp); }
void signedFrom(AstNode* fromp) { if (fromp) { m_signed=fromp->m_signed; }}
void isSigned(bool flag) { m_signed=flag; }
bool isSigned() const { return m_signed; }
void widthSignedFrom(AstNode* fromp) { widthFrom(fromp); numericFrom(fromp); }
void numericFrom(AstNode* fromp) { numeric(fromp->numeric()); }
void numeric(AstNumeric flag) { m_numeric = (int)flag; if (flag.isDouble()) width(64,64); }
AstNumeric numeric() const { return AstNumeric(m_numeric); }
bool isDouble() const { return numeric().isDouble(); }
bool isSigned() const { return numeric().isSigned(); }
void isSigned(bool flag) { numeric(flag ? AstNumeric::SIGNED : AstNumeric::UNSIGNED); }
bool isUnsigned() const { return numeric().isUnsigned(); }
void didWidth(bool flag) { m_didWidth=flag; }
bool didWidth() const { return m_didWidth; }
void doingWidth(bool flag) { m_doingWidth=flag; }
bool doingWidth() const { return m_doingWidth; }
bool isQuad() const { return (width()>VL_WORDSIZE && width()<=VL_QUADSIZE); }
bool isWide() const { return (width()>VL_QUADSIZE); }
@ -986,6 +1028,8 @@ struct AstNodeUniop : public AstNodeMath {
virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; // Set out to evaluation of a AstConst'ed lhs
virtual bool cleanLhs() = 0;
virtual bool sizeMattersLhs() = 0; // True if output result depends on lhs size
virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors?
virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors?
virtual int instrCount() const { return widthInstrs(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode*) const { return true; }
@ -1008,6 +1052,7 @@ struct AstNodeBiop : public AstNodeMath {
virtual bool sizeMattersLhs() = 0; // True if output result depends on lhs size
virtual bool sizeMattersRhs() = 0; // True if output result depends on rhs size
virtual bool signedFlavor() const { return false; } // Signed flavor of nodes with both flavors?
virtual bool doubleFlavor() const { return false; } // D flavor of nodes with both flavors?
virtual int instrCount() const { return widthInstrs(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode*) const { return true; }
@ -1280,7 +1325,6 @@ private:
string m_name; // Name of task
string m_cname; // Name of task if DPI import
bool m_taskPublic:1; // Public task
bool m_didSigning:1; // V3Signed completed; can skip iteration
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
bool m_prototype:1; // Just a prototype
bool m_dpiExport:1; // DPI exported
@ -1291,7 +1335,7 @@ private:
public:
AstNodeFTask(FileLine* fileline, const string& name, AstNode* stmtsp)
: AstNode(fileline)
, m_name(name), m_taskPublic(false), m_didSigning(false)
, m_name(name), m_taskPublic(false)
, m_attrIsolateAssign(false), m_prototype(false)
, m_dpiExport(false), m_dpiImport(false), m_dpiContext(false)
, m_dpiTask(false), m_pure(false) {
@ -1318,8 +1362,6 @@ public:
void scopeNamep(AstNode* nodep) { setNOp4p(nodep); }
void taskPublic(bool flag) { m_taskPublic=flag; }
bool taskPublic() const { return m_taskPublic; }
void didSigning(bool flag) { m_didSigning=flag; }
bool didSigning() const { return m_didSigning; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
bool attrIsolateAssign() const { return m_attrIsolateAssign; }
void prototype(bool flag) { m_prototype = flag; }

View File

@ -113,9 +113,9 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
arg += "const char*";
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
arg += "const VerilatedScope*";
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::REAL) {
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::DOUBLE) {
arg += "double";
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SHORTREAL) {
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::FLOAT) {
arg += "float";
} else if (strtype) {
if (isInOnly()) arg += "const ";
@ -503,6 +503,7 @@ void AstNode::dump(ostream& os) {
<<((editCount()>=editCountLast())?"#>":">")
<<" {"<<dec<<fileline()->lineno()<<"}"
<<" "<<(isSigned()?"s":"")
<<(isDouble()?"d":"")
<<"w"<<(widthSized()?"":"u")<<width();
if (!widthSized()) os<<"/"<<widthMin();
if (name()!="") os<<" "<<AstNode::quoteName(name());

View File

@ -46,19 +46,25 @@ struct AstConst : public AstNodeMath {
private:
V3Number m_num; // Constant value
public:
class Unsized32 {}; // for creator type-overload selection
AstConst(FileLine* fl, const V3Number& num)
:AstNodeMath(fl)
,m_num(num) {
width(m_num.width(), m_num.sized()?0:m_num.minWidth());
isSigned(m_num.isSigned());
numeric(m_num.isDouble() ? AstNumeric::DOUBLE
: m_num.isSigned() ? AstNumeric::SIGNED
: AstNumeric::UNSIGNED);
}
AstConst(FileLine* fl, uint32_t num)
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { width(m_num.width(), m_num.sized()?0:m_num.minWidth()); }
class Unsized32 {}; // for creator type-overload selection
AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { m_num.width(32,false); width(32,m_num.minWidth()); }
class RealDouble {}; // for creator type-overload selection
AstConst(FileLine* fl, RealDouble, double num)
:AstNodeMath(fl)
,m_num(V3Number(fl,64)) { m_num.setDouble(num); numeric(AstNumeric::DOUBLE); }
class LogicFalse {};
AstConst(FileLine* fl, LogicFalse) // Shorthand const 0, know the dtype should be a logic of size 1
:AstNodeMath(fl)
@ -258,7 +264,8 @@ private:
m_keyword = AstBasicDTypeKwd::LOGIC;
}
if (signst == signedst_NOP && keyword().isSigned()) signst = signedst_SIGNED;
setSignedState(signst);
if (keyword().isDouble()) numeric(AstNumeric::DOUBLE);
else setSignedState(signst);
if (!rangep) { // Set based on keyword properties
// V3Width will pull from this width
if (keyword().width() > 1 && !isOpaque()) rangep = new AstRange(fileline(), keyword().width()-1, 0);
@ -278,7 +285,8 @@ public:
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
void rangep(AstRange* nodep) { setNOp1p(nodep); }
void setSignedState(AstSignedState signst) {
if (signst!=signedst_NOP) isSigned(signst==signedst_SIGNED);
if (signst==signedst_UNSIGNED) numeric(AstNumeric::UNSIGNED);
else if (signst==signedst_SIGNED) numeric(AstNumeric::SIGNED);
}
// METHODS
virtual AstBasicDType* basicp() const { return (AstBasicDType*)this; } // (Slow) recurse down to find basic data type
@ -581,8 +589,6 @@ private:
bool m_attrClockEn:1;// User clock enable attribute
bool m_attrIsolateAssign:1;// User isolate_assignments attribute
bool m_attrSFormat:1;// User sformat attribute
bool m_didSigning:1; // V3Signed completed; can skip iteration
bool m_didWidth:1; // V3Width completed; can skip iteration
bool m_fileDescr:1; // File descriptor
bool m_isConst:1; // Table contains constant data
bool m_isStatic:1; // Static variable
@ -596,7 +602,6 @@ private:
m_sigPublic=false; m_sigModPublic=false; m_sigUserRdPublic=false; m_sigUserRWPublic=false;
m_funcLocal=false; m_funcReturn=false;
m_attrClockEn=false; m_attrIsolateAssign=false; m_attrSFormat=false;
m_didSigning=false; m_didWidth=false;
m_fileDescr=false; m_isConst=false; m_isStatic=false;
m_trace=false;
}
@ -607,6 +612,7 @@ public:
init();
combineType(type); setOp1p(dtypep);
if (dtypep && dtypep->basicp()) {
numericFrom(dtypep);
width(dtypep->basicp()->width(), 0);
} else width(1, 0);
}
@ -626,6 +632,7 @@ public:
if (examplep->dtypep()) {
setOp1p(examplep->dtypep()->cloneTree(true));
}
numericFrom(examplep);
width(examplep->width(), examplep->widthMin());
}
ASTNODE_NODE_FUNCS(Var, VAR)
@ -659,10 +666,6 @@ public:
void attrScClocked(bool flag) { m_scClocked = flag; }
void attrIsolateAssign(bool flag) { m_attrIsolateAssign = flag; }
void attrSFormat(bool flag) { m_attrSFormat = flag; }
void didSigning(bool flag) { m_didSigning=flag; }
bool didSigning() const { return m_didSigning; }
void didWidth(bool flag) { m_didWidth=flag; }
bool didWidth() const { return m_didWidth; }
void usedClock(bool flag) { m_usedClock = flag; }
void usedParam(bool flag) { m_usedParam = flag; }
void usedLoopIdx(bool flag) { m_usedLoopIdx = flag; }
@ -1454,6 +1457,15 @@ struct AstCondBound : public AstNodeCond {
ASTNODE_NODE_FUNCS(CondBound, CONDBOUND)
};
struct AstCondD : public AstNodeCond {
// Conditional ?: statement, double rhs/lhs/out
// Parents: MATH
// Children: MATH
AstCondD(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
: AstNodeCond(fl, condp, expr1p, expr2p) { numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(CondD, CONDD)
};
struct AstCoverDecl : public AstNodeStmt {
// Coverage analysis point declaration
// Parents: {statement list}
@ -1624,7 +1636,7 @@ public:
void ignoreOverlap(bool flag) { m_ignoreOverlap = flag; }
};
class AstSFormatF : public AstNode {
struct AstSFormatF : public AstNode {
// Convert format to string, generally under a AstDisplay or AstSFormat
// Also used as "real" function for /*verilator sformat*/ functions
string m_text;
@ -2447,6 +2459,20 @@ struct AstTime : public AstNodeTermop {
virtual bool same(AstNode* samep) const { return true; }
};
struct AstTimeD : public AstNodeTermop {
AstTimeD(FileLine* fl) : AstNodeTermop(fl) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(TimeD, TIMED)
virtual string emitVerilog() { return "%f$realtime"; }
virtual string emitC() { return "VL_TIME_D()"; }
virtual bool cleanOut() { return true; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual int instrCount() const { return instrCountTime(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
};
struct AstUCFunc : public AstNodeMath {
// User's $c function
// Perhaps this should be a AstNodeListop; but there's only one list math right now
@ -2482,9 +2508,22 @@ struct AstNegate : public AstNodeUniop {
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;}
virtual bool sizeMattersLhs() {return true;}
};
struct AstNegateD : public AstNodeUniop {
AstNegateD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(NegateD, NEGATED)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegateD(lhs); }
virtual string emitVerilog() { return "%f(- %l)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "-"; }
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return false;}
virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstRedAnd : public AstNodeUniop {
AstRedAnd(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(1,1); }
width(1,1); numeric(AstNumeric::UNSIGNED); }
ASTNODE_NODE_FUNCS(RedAnd, REDAND)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedAnd(lhs); }
virtual string emitVerilog() { return "%f(& %l)"; }
@ -2494,7 +2533,7 @@ struct AstRedAnd : public AstNodeUniop {
};
struct AstRedOr : public AstNodeUniop {
AstRedOr(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(1,1); }
width(1,1); numeric(AstNumeric::UNSIGNED); }
ASTNODE_NODE_FUNCS(RedOr, REDOR)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedOr(lhs); }
virtual string emitVerilog() { return "%f(| %l)"; }
@ -2504,7 +2543,7 @@ struct AstRedOr : public AstNodeUniop {
};
struct AstRedXor : public AstNodeUniop {
AstRedXor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(1,1); }
width(1,1); numeric(AstNumeric::UNSIGNED); }
ASTNODE_NODE_FUNCS(RedXor, REDXOR)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXor(lhs); }
virtual string emitVerilog() { return "%f(^ %l)"; }
@ -2518,7 +2557,7 @@ struct AstRedXor : public AstNodeUniop {
struct AstRedXnor : public AstNodeUniop {
// AstRedXnors are replaced with AstRedXors in V3Const.
AstRedXnor(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(1,1); }
width(1,1); numeric(AstNumeric::UNSIGNED); }
ASTNODE_NODE_FUNCS(RedXnor, REDXNOR)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRedXnor(lhs); }
virtual string emitVerilog() { return "%f(~^ %l)"; }
@ -2576,7 +2615,7 @@ struct AstExtendS : public AstNodeUniop {
struct AstSigned : public AstNodeUniop {
// $signed(lhs)
AstSigned(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
isSigned(true);
numeric(AstNumeric::SIGNED);
}
ASTNODE_NODE_FUNCS(Signed, SIGNED)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); }
@ -2589,7 +2628,7 @@ struct AstSigned : public AstNodeUniop {
struct AstUnsigned : public AstNodeUniop {
// $unsigned(lhs)
AstUnsigned(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
isSigned(false);
numeric(AstNumeric::UNSIGNED);
}
ASTNODE_NODE_FUNCS(Unsigned, UNSIGNED)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opAssign(lhs); out.isSigned(false); }
@ -2599,6 +2638,63 @@ struct AstUnsigned : public AstNodeUniop {
virtual bool sizeMattersLhs() {return true;} // Eliminated before matters
virtual int instrCount() const { return 0; }
};
struct AstRToIS : public AstNodeUniop {
// $rtoi(lhs)
AstRToIS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(32,32); }
ASTNODE_NODE_FUNCS(RToIS, RTOIS)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRToIS(lhs); }
virtual string emitVerilog() { return "%f$rtoi(%l)"; }
virtual string emitC() { return "VL_RTOI_I_D(%li)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
virtual int instrCount() const { return instrCountDouble(); }
};
struct AstRToIRoundS : public AstNodeUniop {
AstRToIRoundS(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(32,32); }
ASTNODE_NODE_FUNCS(RToIRoundS, RTOIROUNDS)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRToIRoundS(lhs); }
virtual string emitVerilog() { return "%f$rtoi_rounded(%l)"; }
virtual string emitC() { return "VL_RTOIROUND_I_D(%li)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
virtual int instrCount() const { return instrCountDouble(); }
};
struct AstIToRD : public AstNodeUniop {
AstIToRD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(IToRD, ITORD)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opIToRD(lhs); }
virtual string emitVerilog() { return "%f$itor(%l)"; }
virtual string emitC() { return "VL_ITOR_D_I(%li)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
virtual int instrCount() const { return instrCountDouble(); }
};
struct AstRealToBits : public AstNodeUniop {
AstRealToBits(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
width(64,64); }
ASTNODE_NODE_FUNCS(RealToBits, REALTOBITS)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opRealToBits(lhs); }
virtual string emitVerilog() { return "%f$realtobits(%l)"; }
virtual string emitC() { return "VL_CVT_Q_D(%li)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
virtual int instrCount() const { return instrCountDouble(); }
};
struct AstBitsToRealD : public AstNodeUniop {
AstBitsToRealD(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(BitsToRealD, BITSTOREALD)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opBitsToRealD(lhs); }
virtual string emitVerilog() { return "%f$bitstoreal(%l)"; }
virtual string emitC() { return "VL_CVT_D_Q(%li)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} // Eliminated before matters
virtual bool sizeMattersLhs() {return false;} // Eliminated before matters
virtual int instrCount() const { return instrCountDouble(); }
};
struct AstCLog2 : public AstNodeUniop {
AstCLog2(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {}
ASTNODE_NODE_FUNCS(CLog2, CLOG2)
@ -2851,6 +2947,20 @@ struct AstEq : public AstNodeBiCom {
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
};
struct AstEqD : public AstNodeBiCom {
AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
width(1,1); }
ASTNODE_NODE_FUNCS(EqD, EQD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f== %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "=="; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstNeq : public AstNodeBiCom {
AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
width(1,1); }
@ -2863,6 +2973,20 @@ struct AstNeq : public AstNodeBiCom {
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
};
struct AstNeqD : public AstNodeBiCom {
AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
width(1,1); }
ASTNODE_NODE_FUNCS(NeqD, NEQD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f!= %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "!="; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstLt : public AstNodeBiop {
AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
@ -2875,6 +2999,20 @@ struct AstLt : public AstNodeBiop {
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
};
struct AstLtD : public AstNodeBiop {
AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
ASTNODE_NODE_FUNCS(LtD, LTD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f< %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "<"; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstLtS : public AstNodeBiop {
AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
@ -2900,6 +3038,20 @@ struct AstGt : public AstNodeBiop {
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
};
struct AstGtD : public AstNodeBiop {
AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
ASTNODE_NODE_FUNCS(GtD, GTD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f> %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return ">"; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstGtS : public AstNodeBiop {
AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
@ -2925,6 +3077,20 @@ struct AstGte : public AstNodeBiop {
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
};
struct AstGteD : public AstNodeBiop {
AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
ASTNODE_NODE_FUNCS(GteD, GTED)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f>= %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return ">="; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstGteS : public AstNodeBiop {
AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
@ -2950,6 +3116,20 @@ struct AstLte : public AstNodeBiop {
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
};
struct AstLteD : public AstNodeBiop {
AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
ASTNODE_NODE_FUNCS(LteD, LTED)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f<= %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "<="; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstLteS : public AstNodeBiop {
AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
width(1,1); }
@ -3018,6 +3198,20 @@ struct AstAdd : public AstNodeBiComAsv {
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
};
struct AstAddD : public AstNodeBiComAsv {
AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(AddD, ADDD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAddD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f+ %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "+"; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstSub : public AstNodeBiop {
AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
if (lhsp) widthSignedFrom(lhsp); }
@ -3030,6 +3224,20 @@ struct AstSub : public AstNodeBiop {
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
};
struct AstSubD : public AstNodeBiop {
AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(SubD, SUBD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opSubD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f- %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "-"; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstMul : public AstNodeBiComAsv {
AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
if (lhsp) widthSignedFrom(lhsp); }
@ -3043,6 +3251,20 @@ struct AstMul : public AstNodeBiComAsv {
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
virtual int instrCount() const { return widthInstrs()*instrCountMul(); }
};
struct AstMulD : public AstNodeBiComAsv {
AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(MulD, MULD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opMulD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f* %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "*"; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
virtual int instrCount() const { return instrCountDouble(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstMulS : public AstNodeBiComAsv {
AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiComAsv(fl, lhsp, rhsp) {
if (lhsp) widthSignedFrom(lhsp); }
@ -3069,6 +3291,20 @@ struct AstDiv : public AstNodeBiop {
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
virtual int instrCount() const { return widthInstrs()*instrCountDiv(); }
};
struct AstDivD : public AstNodeBiop {
AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(DivD, DIVD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f/ %r)"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual string emitSimpleOperator() { return "/"; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDoubleDiv(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstDivS : public AstNodeBiop {
AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
if (lhsp) widthSignedFrom(lhsp); }
@ -3119,6 +3355,19 @@ struct AstPow : public AstNodeBiop {
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*instrCountMul(); }
};
struct AstPowD : public AstNodeBiop {
AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
numeric(AstNumeric::DOUBLE); }
ASTNODE_NODE_FUNCS(PowD, POWD)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowD(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f** %r)"; }
virtual string emitC() { return "pow(%li,%ri)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDoubleDiv(); }
virtual bool doubleFlavor() const { return true; }
};
struct AstPowS : public AstNodeBiop {
AstPowS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
if (lhsp) widthSignedFrom(lhsp); }

View File

@ -148,17 +148,19 @@ private:
bool isCaseTreeFast(AstCase* nodep) {
int width = 0;
bool opaque = false;
m_caseItems = 0;
m_caseNoOverlapsAllCovered = true;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
for (AstNode* icondp = itemp->condsp(); icondp!=NULL; icondp=icondp->nextp()) {
if (icondp->width() > width) width = icondp->width();
if (icondp->isDouble()) opaque = true;
if (!icondp->castConst()) width = CASE_BARF; // Can't parse; not a constant
m_caseItems++;
}
}
m_caseWidth = width;
if (width==0 || width > CASE_OVERLAP_WIDTH) {
if (width==0 || width > CASE_OVERLAP_WIDTH || opaque) {
m_caseNoOverlapsAllCovered = false;
return false; // Too wide for analysis
}
@ -348,7 +350,9 @@ private:
and1p = cexprp->cloneTree(false);
and2p = icondp;
}
AstEq* condp = new AstEq(itemp->fileline(), and1p, and2p);
AstNodeBiop* condp = (and1p->isDouble()
? (new AstEqD(itemp->fileline(), and1p, and2p))->castNodeBiop()
: (new AstEq(itemp->fileline(), and1p, and2p))->castNodeBiop());
if (!ifexprp) {
ifexprp = condp;
} else {

View File

@ -37,7 +37,6 @@
#include "V3Const.h"
#include "V3Ast.h"
#include "V3Width.h"
#include "V3Signed.h"
#include "V3Simulate.h"
//######################################################################
@ -1783,17 +1782,23 @@ private:
TREEOP ("AstXnor {operandsSame($lhsp,,$rhsp)}", "replaceAllOnes(nodep)");
TREEOP ("AstXor {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstEq {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
TREEOP ("AstEqD {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)"); // We let X==X -> 1, although in a true 4-state sim it's X.
TREEOP ("AstEqCase {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstEqWild {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstGt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstGtD {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstGtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstGte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstGteD {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstGteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstLt {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLtD {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLtS {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLte {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstLteD {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstLteS {operandsSame($lhsp,,$rhsp)}", "replaceNum(nodep,1)");
TREEOP ("AstNeq {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstNeqD {operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstNeqCase{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstNeqWild{operandsSame($lhsp,,$rhsp)}", "replaceZero(nodep)");
TREEOP ("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}", "replaceWLhs(nodep)");

View File

@ -545,6 +545,8 @@ public:
ofp()->printf(",0x%08" VL_PRI64 "x", (vluint64_t)(nodep->num().dataWord(word)));
}
ofp()->printf(",0x%08" VL_PRI64 "x)", (vluint64_t)(nodep->num().dataWord(0)));
} else if (nodep->isDouble()) {
ofp()->printf("%g", nodep->num().toDouble());
} else if (nodep->isQuad()) {
vluint64_t num = nodep->toUQuad();
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", num);
@ -1210,6 +1212,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
switch (tolower(pos[0])) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
// Digits, like %5d, etc.
vfmt += pos[0];
inPct = true; // Get more digits
@ -1228,6 +1231,9 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
case 'h':
case 'x': displayArg(nodep,&elistp,isScan, vfmt,'x'); break;
case 's': displayArg(nodep,&elistp,isScan, vfmt,'s'); break;
case 'e': displayArg(nodep,&elistp,isScan, vfmt,'e'); break;
case 'f': displayArg(nodep,&elistp,isScan, vfmt,'f'); break;
case 'g': displayArg(nodep,&elistp,isScan, vfmt,'g'); break;
case 'm': {
if (!scopenamep) nodep->v3fatalSrc("Display with %m but no AstScopeName");
string suffix = scopenamep->scopePrettyName();
@ -2009,7 +2015,9 @@ class EmitCTrace : EmitCStmts {
return varp->isSc() && varp->isScBv();
}
void emitTraceInitOne(AstTraceDecl* nodep) {
if (nodep->isWide()) {
if (nodep->isDouble()) {
puts("vcdp->declDouble");
} else if (nodep->isWide()) {
puts("vcdp->declArray");
} else if (nodep->isQuad()) {
puts("vcdp->declQuad ");
@ -2038,7 +2046,9 @@ class EmitCTrace : EmitCStmts {
string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL
|| m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB)
? "full":"chg");
if (nodep->isWide() || emitTraceIsScBv(nodep)) {
if (nodep->isDouble()) {
puts("vcdp->"+full+"Double");
} else if (nodep->isWide() || emitTraceIsScBv(nodep)) {
puts("vcdp->"+full+"Array");
} else if (nodep->isQuad()) {
puts("vcdp->"+full+"Quad ");

View File

@ -73,6 +73,7 @@ public:
LITENDIAN, // Little bit endian vector
MODDUP, // Duplicate module
MULTIDRIVEN, // Driven from multiple blocks
REALCVT, // Real conversion
REDEFMACRO, // Redefining existing define macro
STMTDLY, // Delayed statement
SYMRSVDWORD, // Symbol is Reserved Word
@ -111,7 +112,7 @@ public:
"IFDEPTH", "IMPERFECTSCH", "IMPLICIT", "IMPURE", "INCABSPATH",
"LITENDIAN", "MODDUP",
"MULTIDRIVEN",
"REDEFMACRO",
"REALCVT", "REDEFMACRO",
"STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
@ -135,6 +136,7 @@ public:
|| m_e==CMPCONST
|| m_e==IMPLICIT
|| m_e==LITENDIAN
|| m_e==REALCVT
|| m_e==UNSIGNED
|| m_e==WIDTH); }
// Warnings that are style only

View File

@ -428,7 +428,7 @@ private:
if (dtypep) dtypep->unlinkFrBack();
else dtypep = new AstBasicDType(nodep->fileline(), AstBasicDTypeKwd::LOGIC);
AstVar* newvarp = new AstVar(nodep->fileline(), AstVarType::OUTPUT, nodep->name(), dtypep);
newvarp->isSigned(nodep->isSigned());
if (nodep->isSigned()) newvarp->numeric(AstNumeric::SIGNED);
newvarp->funcReturn(true);
newvarp->trace(false); // Not user visible
newvarp->attrIsolateAssign(nodep->attrIsolateAssign());

View File

@ -135,8 +135,8 @@ private:
// Spec says value is integral, if negative is ignored
AstVar* varp = new AstVar(nodep->fileline(), AstVarType::BLOCKTEMP, name,
AstLogicPacked(), 32);
varp->isSigned(true);
varp->dtypep()->isSigned(true);
varp->numeric(AstNumeric::SIGNED);
varp->dtypep()->numeric(AstNumeric::SIGNED);
varp->usedLoopIdx(true);
m_modp->addStmtp(varp);
AstNode* initsp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
@ -144,7 +144,7 @@ private:
AstNode* decp = new AstAssign(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, true),
new AstSub(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
new AstConst(nodep->fileline(), 1)));
AstNode* zerosp = new AstConst(nodep->fileline(), 0); zerosp->isSigned(true);
AstNode* zerosp = new AstConst(nodep->fileline(), 0); zerosp->numeric(AstNumeric::SIGNED);
AstNode* condp = new AstGtS(nodep->fileline(), new AstVarRef(nodep->fileline(), varp, false),
zerosp);
AstNode* bodysp = nodep->bodysp(); if (bodysp) bodysp->unlinkFrBackWithNext();

View File

@ -257,6 +257,7 @@ private:
switch (tolower(ch)) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case '.':
inPct = true;
break;
case '%': break; // %% - just output a %

View File

@ -27,6 +27,8 @@
#include <algorithm>
#include "V3Number.h"
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
//######################################################################
// Read class functions
// CREATION
@ -44,6 +46,7 @@ void V3Number::width(int width, bool sized) {
void V3Number::init (FileLine* fileline, int swidth) {
m_fileline = fileline;
m_signed = false;
m_double = false;
m_autoExtend = false;
m_fromString = false;
width(swidth);
@ -298,6 +301,24 @@ V3Number& V3Number::setLong(uint32_t value) {
m_value[0] = value;
return *this;
}
V3Number& V3Number::setLongS(vlsint32_t value) {
for (int i=0; i<words(); i++) m_value[i]=m_valueX[i] = 0;
union { uint32_t u; vlsint32_t s; } u;
u.s = value;
m_value[0] = u.u;
return *this;
}
V3Number& V3Number::setDouble(double value) {
if (VL_UNLIKELY(width()!=64)) {
m_fileline->v3fatalSrc("Real operation on wrong sized number");
}
m_double = true;
union { double d; uint32_t u[2]; } u;
u.d = value;
for (int i=2; i<words(); i++) m_value[i]=m_valueX[i] = 0;
m_value[0] = u.u[0]; m_value[1] = u.u[1];
return *this;
}
V3Number& V3Number::setSingleBits(char value) {
for (int i=1/*upper*/; i<words(); i++) m_value[i]=m_valueX[i] = 0;
m_value[0] = (value=='1'||value=='x'||value==1||value==3);
@ -306,12 +327,12 @@ V3Number& V3Number::setSingleBits(char value) {
}
V3Number& V3Number::setAllBits0() {
for (int i=0; i<words(); i++) { m_value[i] = m_valueX[i]=0; }
return *this;
for (int i=0; i<words(); i++) { m_value[i] = m_valueX[i]=0; }
return *this;
}
V3Number& V3Number::setAllBits1() {
for (int i=0; i<words(); i++) { m_value[i]= ~0; m_valueX[i] = 0; }
return *this;
for (int i=0; i<words(); i++) { m_value[i]= ~0; m_valueX[i] = 0; }
return *this;
}
V3Number& V3Number::setAllBitsX() {
for (int i=0; i<words(); i++) { m_value[i]=m_valueX[i] = ~0; }
@ -333,6 +354,10 @@ V3Number& V3Number::setMask(int nbits) {
string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
ostringstream out;
if (isDouble()) {
out<<toDouble();
return out.str();
}
if (prefixed) {
if (sized()) {
out<<width()<<"'";
@ -375,6 +400,9 @@ bool V3Number::displayedFmtLegal(char format) {
case 'b': return true;
case 'c': return true;
case 'd': return true; // Unsigned decimal
case 'e': return true;
case 'f': return true;
case 'g': return true;
case 'h': return true;
case 'o': return true;
case 's': return true;
@ -390,7 +418,7 @@ string V3Number::displayed(const string& vformat) const {
UASSERT(pos != vformat.end() && pos[0]=='%', "display with non format argument "<<*this);
pos++;
string fmtsize;
for (; pos != vformat.end() && isdigit(pos[0]); pos++) {
for (; pos != vformat.end() && (isdigit(pos[0]) || pos[0]=='.'); pos++) {
fmtsize += pos[0];
}
string str;
@ -472,9 +500,20 @@ string V3Number::displayed(const string& vformat) const {
str = cvtToStr(toUQuad());
}
int intfmtsize = atoi(fmtsize.c_str());
while ((int)(str.length()) < intfmtsize) str = " "+str;
bool zeropad = fmtsize.length()>0 && fmtsize[0]=='0';
while ((int)(str.length()) < intfmtsize) {
if (zeropad) str = "0"+str;
else str = " "+str;
}
return str;
}
case 'e':
case 'f':
case 'g': {
char tmp[MAX_SPRINTF_DOUBLE_SIZE];
sprintf(tmp, vformat.c_str(), toDouble());
return tmp;
}
default:
m_fileline->v3fatalSrc("Unknown $display format code for number: %"<<pos[0]);
return "ERR";
@ -490,6 +529,18 @@ uint32_t V3Number::toUInt() const {
return m_value[0];
}
double V3Number::toDouble() const {
if (VL_UNLIKELY(!isDouble())) {
m_fileline->v3fatalSrc("Real conversion on non real number");
}
if (VL_UNLIKELY(width()!=64)) {
m_fileline->v3fatalSrc("Real operation on wrong sized number");
}
union { double d; uint32_t u[2]; } u;
u.u[0] = m_value[0]; u.u[1] = m_value[1];
return u.d;
}
vlsint32_t V3Number::toSInt() const {
if (isSigned()) {
uint32_t v = toUInt();
@ -1049,7 +1100,7 @@ V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) {
// L(lhs) bit return
// The spec says a unsigned >>> still acts as a normal >>.
// We presume it is signed; as that's V3Signed's job to convert to opShiftR
// We presume it is signed; as that's V3Width's job to convert to opShiftR
if (rhs.isFourState()) return setAllBitsX();
setZero();
uint32_t rhsval = rhs.toUInt();
@ -1434,3 +1485,74 @@ V3Number& V3Number::opCond (const V3Number& lhs, const V3Number& if1s, const V3
}
return *this;
}
//======================================================================
// Ops - Floating point
V3Number& V3Number::opIToRD (const V3Number& lhs) {
return setDouble(lhs.toSInt());
}
V3Number& V3Number::opRToIS (const V3Number& lhs) {
double v = trunc(lhs.toDouble());
vlsint32_t i = v; // C converts from double to vlsint32
return setLongS(i);
}
V3Number& V3Number::opRToIRoundS (const V3Number& lhs) {
double v = round(lhs.toDouble());
vlsint32_t i = v; // C converts from double to vlsint32
return setLongS(i);
}
V3Number& V3Number::opRealToBits (const V3Number& lhs) {
// Conveniently our internal format is identical so we can copy bits...
if (lhs.width()!=64 || this->width()!=64) {
m_fileline->v3fatalSrc("Real operation on wrong sized number");
}
return opAssign(lhs);
}
V3Number& V3Number::opBitsToRealD (const V3Number& lhs) {
// Conveniently our internal format is identical so we can copy bits...
if (lhs.width()!=64 || this->width()!=64) {
m_fileline->v3fatalSrc("Real operation on wrong sized number");
}
return opAssign(lhs);
}
V3Number& V3Number::opNegateD (const V3Number& lhs) {
return setDouble(- lhs.toDouble());
}
V3Number& V3Number::opAddD (const V3Number& lhs, const V3Number& rhs) {
return setDouble(lhs.toDouble() + rhs.toDouble());
}
V3Number& V3Number::opSubD (const V3Number& lhs, const V3Number& rhs) {
return setDouble(lhs.toDouble() - rhs.toDouble());
}
V3Number& V3Number::opMulD (const V3Number& lhs, const V3Number& rhs) {
return setDouble(lhs.toDouble() * rhs.toDouble());
}
V3Number& V3Number::opDivD (const V3Number& lhs, const V3Number& rhs) {
// On exceptions, we just generate 'inf' through floating point
// IEEE says it's implementation defined what happens
return setDouble(lhs.toDouble() / rhs.toDouble());
}
V3Number& V3Number::opPowD (const V3Number& lhs, const V3Number& rhs) {
// On exceptions, we just generate 'inf' through floating point
// IEEE says it's implementation defined what happens
return setDouble(pow(lhs.toDouble(), rhs.toDouble()));
}
V3Number& V3Number::opEqD (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toDouble() == rhs.toDouble());
}
V3Number& V3Number::opNeqD (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toDouble() != rhs.toDouble());
}
V3Number& V3Number::opGtD (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toDouble() > rhs.toDouble());
}
V3Number& V3Number::opGteD (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toDouble() >= rhs.toDouble());
}
V3Number& V3Number::opLtD (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toDouble() < rhs.toDouble());
}
V3Number& V3Number::opLteD (const V3Number& lhs, const V3Number& rhs) {
return setSingleBits(lhs.toDouble() <= rhs.toDouble());
}

View File

@ -35,6 +35,7 @@ class V3Number {
int m_width; // Width as specified/calculated.
bool m_sized:1; // True if the user specified the width, else we track it.
bool m_signed:1; // True if signed value
bool m_double:1; // True if double real value
bool m_fromString:1; // True if from string
bool m_autoExtend:1; // True if SystemVerilog extend-to-any-width
FileLine* m_fileline;
@ -50,6 +51,8 @@ public:
V3Number& setZero();
V3Number& setQuad(vluint64_t value);
V3Number& setLong(uint32_t value);
V3Number& setLongS(vlsint32_t value);
V3Number& setDouble(double value);
void setBit (int bit, char value) { // Note must be pre-zeroed!
if (bit>=m_width) return;
if (value=='0'||value==0) m_value [bit/32] &= ~(1UL<<(bit&31));
@ -132,6 +135,7 @@ public:
bool autoExtend() const { return m_autoExtend; }
bool isFromString() const { return m_fromString; }
bool isSigned() const { return m_signed; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
bool isDouble() const { return m_double; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
bool isNegative() const { return bitIs1(width()-1); }
bool isFourState() const { for (int i=0;i<words();i++) {if (m_valueX[i]) return true;} return false; }
bool hasZ() const { for(int i=0;i<words();i++) {if((~m_value[i]) & m_valueX[i]) return true;} return false;}
@ -151,6 +155,7 @@ public:
vluint64_t toUQuad() const;
vlsint64_t toSQuad() const;
string toString() const;
double toDouble() const;
uint32_t toHash() const;
uint32_t dataWord(int word) const;
uint32_t countOnes() const;
@ -236,6 +241,25 @@ public:
V3Number& opLte (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteS (const V3Number& lhs, const V3Number& rhs); // Signed
// "D" - double (aka real) math
V3Number& opIToRD (const V3Number& lhs);
V3Number& opRToIS (const V3Number& lhs);
V3Number& opRToIRoundS (const V3Number& lhs);
V3Number& opRealToBits (const V3Number& lhs);
V3Number& opBitsToRealD(const V3Number& lhs);
V3Number& opNegateD (const V3Number& lhs);
V3Number& opAddD (const V3Number& lhs, const V3Number& rhs);
V3Number& opSubD (const V3Number& lhs, const V3Number& rhs);
V3Number& opMulD (const V3Number& lhs, const V3Number& rhs);
V3Number& opDivD (const V3Number& lhs, const V3Number& rhs);
V3Number& opPowD (const V3Number& lhs, const V3Number& rhs);
// Comparisons
V3Number& opEqD (const V3Number& lhs, const V3Number& rhs);
V3Number& opNeqD (const V3Number& lhs, const V3Number& rhs);
V3Number& opGtD (const V3Number& lhs, const V3Number& rhs);
V3Number& opGteD (const V3Number& lhs, const V3Number& rhs);
V3Number& opLtD (const V3Number& lhs, const V3Number& rhs);
V3Number& opLteD (const V3Number& lhs, const V3Number& rhs);
};
inline ostream& operator<<(ostream& os, V3Number rhs) { return os<<rhs.ascii(); }

View File

@ -43,7 +43,6 @@
#include "V3Case.h"
#include "V3Const.h"
#include "V3Width.h"
#include "V3Signed.h"
#include "V3Unroll.h"
//######################################################################

View File

@ -254,6 +254,7 @@ public:
void verilatorCmtLintSave();
void verilatorCmtLintRestore();
void verilatorCmtBad(const char* text);
double parseDouble(const char* text, size_t length);
void pushBeginKeywords(int state) { m_inBeginKwd++; m_lastVerilogState=state; }
bool popBeginKeywords() { if (m_inBeginKwd) { m_inBeginKwd--; return true; } else return false; }
int lastVerilogState() { return m_lastVerilogState; }

View File

@ -1,451 +0,0 @@
//*************************************************************************
// DESCRIPTION: Verilator: Signed/unsigned resolution
//
// Code available from: http://www.veripool.org/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2005-2011 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.
//
// 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.
//
//*************************************************************************
// Signedness depends on:
// Decimal numbers are signed
// Based numbers are unsigned unless 's' prefix
// Comparison results are unsigned
// Bit&Part selects are unsigned, even if whole
// Concatenates are unsigned
// Ignore signedness of self-determined:
// shift rhs, ** rhs, x?: lhs, concat and replicate members
// Else, if any operand unsigned, output unsigned
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include <cstdio>
#include <cstdarg>
#include <unistd.h>
#include <map>
#include <iomanip>
#include "V3Global.h"
#include "V3Signed.h"
#include "V3Ast.h"
//######################################################################
// Signed class functions
class SignedVisitor : public AstNVisitor {
private:
// NODE STATE/TYPES
// STATE
bool m_paramsOnly; // Computing parameter value; limit operation
// METHODS - special type detection
bool backRequiresUnsigned(AstNode* nodep) {
// The spec doesn't state this, but if you have an array select where the selection
// index is NOT wide enough, you do not sign extend, but always zero extend.
return (nodep->castArraySel()
|| nodep->castSel());
}
// VISITORS
//========
// Signed: Output explicit by user, Lhs either
virtual void visit(AstUnsigned* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstSigned* nodep, AstNUser*) { signed_Os_Ix(nodep); }
//========
// Signed: Output unsigned, Operands either
virtual void visit(AstSel* nodep, AstNUser*) { signed_Ou_Ix(nodep); } //See backRequiresUnsigned
virtual void visit(AstAttrOf* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstCountOnes* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstCLog2* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstPslBool* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstTime* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
//
virtual void visit(AstRedAnd* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstRedOr* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstRedXnor* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
virtual void visit(AstRedXor* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstIsUnknown* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstOneHot* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstOneHot0* nodep,AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFEof* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFGetC* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFGetS* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstFScanF* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstSScanF* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstTestPlusArgs* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstValuePlusArgs* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
//
virtual void visit(AstConcat* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstReplicate* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstRange* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
// ... One presumes these are unsigned out, though the spec doesn't say
virtual void visit(AstLogNot* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstLogAnd* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstLogOr* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstLogIf* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstLogIff* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstBufIf1* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
// ... These shouldn't matter, just make unsigned
virtual void visit(AstScopeName* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstText* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstUCFunc* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
// ... These comparisons don't care about inbound types
// ... (Though they should match. We don't check.)
virtual void visit(AstEq* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstEqCase* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstEqWild* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstNeq* nodep, AstNUser*) { signed_Ou_Ix(nodep); }
virtual void visit(AstNeqCase* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
virtual void visit(AstNeqWild* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
// ... Opaque returns, so arbitrary
virtual void visit(AstCvtPackString* nodep, AstNUser*){ signed_Ou_Ix(nodep); }
//========
// Signed: Output signed
virtual void visit(AstRand* nodep, AstNUser*) { signed_Os_Ix(nodep); }
//=======
// Signed: Output signed iff LHS signed; unary operator
virtual void visit(AstNot* nodep, AstNUser*) { signed_Olhs(nodep); }
virtual void visit(AstNegate* nodep, AstNUser*) { signed_Olhs(nodep); }
virtual void visit(AstShiftL* nodep, AstNUser*) { signed_Olhs(nodep); }
virtual void visit(AstShiftR* nodep, AstNUser*) { signed_Olhs(nodep); }
// Signed: Output signed iff LHS signed; binary operator
// Note by contrast, bit extract selects are unsigned
virtual void visit(AstArraySel* nodep, AstNUser*) { signed_Olhs(nodep); } //See backRequiresUnsigned
//=======
// Signed: Output signed iff LHS & RHS signed; binary operator
virtual void visit(AstAnd* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
virtual void visit(AstOr* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
virtual void visit(AstXnor* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
virtual void visit(AstXor* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
virtual void visit(AstSub* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
virtual void visit(AstAdd* nodep, AstNUser*) { signed_OlhsAndRhs(nodep); }
//=======
// Signed: Output signed iff RHS & THS signed
virtual void visit(AstNodeCond* nodep, AstNUser*) { signed_OrhsAndThs(nodep); }
//=======
// These have proper signedness set when they were created.
virtual void visit(AstReturn* nodep, AstNUser*) { nodep->iterateChildren(*this); }
virtual void visit(AstNodeDType* nodep, AstNUser*) { nodep->iterateChildren(*this); }
// Inherit from others
virtual void visit(AstVar* nodep, AstNUser*) {
// Avoid recursion; can't use user() as they're all full, and anyhow this is often called
if (nodep->didSigning()) return;
nodep->didSigning(true);
nodep->iterateChildren(*this);
nodep->signedFrom(nodep->dtypep());
}
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
nodep->varp()->iterate(*this);
nodep->signedFrom(nodep->varp());
}
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
nodep->itemp()->iterate(*this);
nodep->signedFrom(nodep->itemp());
}
virtual void visit(AstCast* nodep, AstNUser*) {
nodep->lhsp()->iterate(*this);
nodep->dtypep()->iterate(*this);
nodep->signedFrom(nodep->dtypep());
}
virtual void visit(AstConst* nodep, AstNUser*) {
// The node got setup with the signed state of the node.
// However a later operation may have changed the node->signed w/o changing
// the number's sign. So we don't: nodep->isSigned(nodep->num().isSigned());
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
// Avoid recursion; can't use user() as they're all full, and anyhow this is often called
if (nodep->didSigning()) return;
nodep->didSigning(true);
nodep->iterateChildren(*this);
if (nodep->fvarp()) {
nodep->signedFrom(nodep->fvarp()); // Which will get it from fvarp()->dtypep()
}
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->taskp()) nodep->taskp()->iterate(*this);
nodep->signedFrom(nodep->taskp());
}
virtual void visit(AstRefDType* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->defp()) nodep->defp()->iterate(*this);
nodep->signedFrom(nodep->skipRefp());
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {
if (!nodep->castGenIf()) { // for m_paramsOnly
nodep->ifsp()->iterateAndNext(*this);
nodep->elsesp()->iterateAndNext(*this);
}
nodep->condp()->iterateAndNext(*this);
}
virtual void visit(AstPin* nodep, AstNUser*) {
// Same as above taskref argument.
nodep->iterateChildren(*this);
}
// VISITORS - Special
virtual void visit(AstSFormatF* nodep, AstNUser*) {
nodep->iterateChildren(*this);
//
UINFO(9," Display in "<<nodep->text()<<endl);
string dispout = "";
bool inPct = false;
AstNode* argp = nodep->exprsp();
for (const char* inp = nodep->text().c_str(); *inp; inp++) {
char ch = *inp; // Breaks with iterators...
if (!inPct && ch=='%') {
inPct = true;
} else if (inPct && isdigit(ch)) {
} else if (tolower(inPct)) {
inPct = false;
switch (tolower(ch)) {
case '%': break; // %% - just output a %
case 'm': break; // %m - auto insert "name"
case 'd': { // Convert decimal to either 'd' or 'u'
if (argp && argp->isSigned()) { // Convert it
ch = '~';
}
if (argp) argp=argp->nextp();
break;
}
default: // Most operators, just move to next argument
if (argp) argp=argp->nextp();
break;
} // switch
}
dispout += ch;
}
nodep->text(dispout);
UINFO(9," Display out "<<nodep->text()<<endl);
}
// VISITORS - These need to be changed to different op types
// Uniop
virtual void visit(AstExtend* nodep, AstNUser*) {
signed_Olhs(nodep);
if (nodep->isSigned() && !backRequiresUnsigned(nodep->backp())) {
replaceWithSignedVersion(nodep, new AstExtendS (nodep->fileline(), nodep->lhsp()->unlinkFrBack())); nodep=NULL;
}
}
virtual void visit(AstExtendS* nodep, AstNUser*) {
signed_Olhs(nodep);
if (!(nodep->isSigned() && !backRequiresUnsigned(nodep->backp()))) {
replaceWithSignedVersion(nodep, new AstExtend (nodep->fileline(), nodep->lhsp()->unlinkFrBack())); nodep=NULL;
}
}
// Biop
virtual void visit(AstPow* nodep, AstNUser*) {
// Pow is special, output sign only depends on LHS sign
signed_Olhs(nodep);
if (nodep->isSigned()) {
replaceWithSignedVersion(nodep, new AstPowS (nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack())); nodep=NULL;
}
}
virtual void visit(AstPowS* nodep, AstNUser*) {
// Pow is special, output sign only depends on LHS sign
signed_Olhs(nodep);
if (!nodep->isSigned()) {
replaceWithSignedVersion(nodep, new AstPow (nodep->fileline(), nodep->lhsp()->unlinkFrBack(), nodep->rhsp()->unlinkFrBack())); nodep=NULL;
}
}
// These have different node types, as they operate differently
// Must add to case statement below,
virtual void visit(AstGt* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
virtual void visit(AstGtS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
virtual void visit(AstGte* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
virtual void visit(AstGteS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
virtual void visit(AstLt* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
virtual void visit(AstLtS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
virtual void visit(AstLte* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
virtual void visit(AstLteS* nodep, AstNUser*) { checkReplace_Ou_FlavLhsAndRhs(nodep); }
// Need replacements; output matches input sign
virtual void visit(AstDiv* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
virtual void visit(AstDivS* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
virtual void visit(AstModDiv* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
virtual void visit(AstModDivS* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
virtual void visit(AstMul* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
virtual void visit(AstMulS* nodep, AstNUser*) { checkReplace_OlhsAndRhs(nodep); }
// ShiftRS converts to ShiftR, but not vice-versa
virtual void visit(AstShiftRS* nodep, AstNUser*) { checkReplace_Olhs(nodep); }
// VISITORS - defaults
virtual void visit(AstNodeMath* nodep, AstNUser*) {
nodep->v3fatalSrc("Visit function missing? Signedness unknown for this node: "<<nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
//=======
// Lower level functions
void checkReplace_Ou_FlavLhsAndRhs(AstNodeBiop* nodep) {
// For compares, the output of the comparison is unsigned.
// However, we need the appropriate type of compare selected by RHS & LHS
signed_Ou_Ix(nodep);
checkReplace(nodep, nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
}
void checkReplace_Olhs(AstNodeBiop* nodep) {
signed_Olhs(nodep);
checkReplace(nodep, nodep->isSigned());
}
void checkReplace_OlhsAndRhs(AstNodeBiop* nodep) {
signed_OlhsAndRhs(nodep);
checkReplace(nodep, nodep->isSigned());
}
void checkReplace(AstNodeBiop* nodep, bool signedFlavorNeeded) {
if (signedFlavorNeeded != nodep->signedFlavor()) {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* newp = NULL;
// Given a signed/unsigned node type, create the opposite type
switch (nodep->type()) {
case AstType::atGT: newp = new AstGtS (nodep->fileline(), lhsp, rhsp); break;
case AstType::atGTS: newp = new AstGt (nodep->fileline(), lhsp, rhsp); break;
case AstType::atGTE: newp = new AstGteS (nodep->fileline(), lhsp, rhsp); break;
case AstType::atGTES: newp = new AstGte (nodep->fileline(), lhsp, rhsp); break;
case AstType::atLT: newp = new AstLtS (nodep->fileline(), lhsp, rhsp); break;
case AstType::atLTS: newp = new AstLt (nodep->fileline(), lhsp, rhsp); break;
case AstType::atLTE: newp = new AstLteS (nodep->fileline(), lhsp, rhsp); break;
case AstType::atLTES: newp = new AstLte (nodep->fileline(), lhsp, rhsp); break;
case AstType::atDIV: newp = new AstDivS (nodep->fileline(), lhsp, rhsp); break;
case AstType::atDIVS: newp = new AstDiv (nodep->fileline(), lhsp, rhsp); break;
case AstType::atMODDIV: newp = new AstModDivS (nodep->fileline(), lhsp, rhsp); break;
case AstType::atMODDIVS: newp = new AstModDiv (nodep->fileline(), lhsp, rhsp); break;
case AstType::atMUL: newp = new AstMulS (nodep->fileline(), lhsp, rhsp); break;
case AstType::atMULS: newp = new AstMul (nodep->fileline(), lhsp, rhsp); break;
case AstType::atSHIFTRS: newp = new AstShiftR (nodep->fileline(), lhsp, rhsp); break;
default:
nodep->v3fatalSrc("Node needs sign change, but bad case: "<<nodep<<endl);
break;
}
replaceWithSignedVersion(nodep,newp);
}
}
// COMMON SCHEMES
// Signed: Output signed, Lhs/Rhs/etc either
void signed_Os_Ix(AstNode* nodep) {
nodep->iterateChildren(*this);
nodep->isSigned(true);
}
// Signed: Output unsigned, Lhs/Rhs/etx either
void signed_Ou_Ix(AstNode* nodep) {
nodep->iterateChildren(*this);
nodep->isSigned(false);
}
// Signed: Output signed iff LHS signed; unary operator
void signed_Olhs(AstNodeUniop* nodep) {
nodep->iterateChildren(*this);
nodep->isSigned(nodep->lhsp()->isSigned());
}
// Signed: Output signed iff LHS signed; binary operator
void signed_Olhs(AstNodeBiop* nodep) {
nodep->iterateChildren(*this);
nodep->isSigned(nodep->lhsp()->isSigned());
}
// Signed: Output signed iff LHS signed; select operator
void signed_Olhs(AstSel* nodep) {
nodep->iterateChildren(*this);
nodep->isSigned(nodep->fromp()->isSigned());
}
// Signed: Output signed iff LHS & RHS signed; binary operator
void signed_OlhsAndRhs(AstNodeBiop* nodep) {
nodep->iterateChildren(*this);
nodep->isSigned(nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
}
// Signed: Output signed iff RHS & THS signed
void signed_OrhsAndThs(AstNodeTriop* nodep) {
nodep->iterateChildren(*this);
nodep->isSigned(nodep->rhsp()->isSigned() && nodep->thsp()->isSigned());
}
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
nodep->replaceWith(newp);
newp->widthSignedFrom(nodep);
pushDeletep(nodep); nodep=NULL;
}
public:
// CONSTRUCTORS
SignedVisitor(bool paramsOnly) {
m_paramsOnly = paramsOnly;
}
virtual ~SignedVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
// Signed class functions
/// Remove all $signed, $unsigned, we're done with them.
class SignedRemoveVisitor : public AstNVisitor {
private:
// VISITORS
virtual void visit(AstSigned* nodep, AstNUser*) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
}
virtual void visit(AstUnsigned* nodep, AstNUser*) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
nodep->replaceWith(newp);
newp->widthSignedFrom(nodep);
pushDeletep(nodep); nodep=NULL;
}
public:
// CONSTRUCTORS
SignedRemoveVisitor() {}
virtual ~SignedRemoveVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
// Top Signed class
void V3Signed::signedAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
(void)signedParamsEdit(nodep);
}
AstNode* V3Signed::signedParamsEdit(AstNode* nodep) {
// Only called from V3Width::widthParamsEdit
UINFO(4,__FUNCTION__<<": "<<endl);
SignedVisitor visitor (true);
nodep = visitor.mainAcceptEdit(nodep);
SignedRemoveVisitor rvisitor;
nodep = rvisitor.mainAcceptEdit(nodep);
return nodep;
}

View File

@ -1,40 +0,0 @@
// -*- C++ -*-
//*************************************************************************
// DESCRIPTION: Verilator: Signed/unsigned resolution
//
// Code available from: http://www.veripool.org/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2005-2011 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.
//
// 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 _V3SIGNED_H_
#define _V3SIGNED_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
//============================================================================
class V3Signed {
public:
static void signedAll(AstNetlist* nodep);
protected:
friend class V3Width; // Use widthParamsEdit instead of signedParamsEdit
static AstNode* signedParamsEdit(AstNode* nodep); // May replace nodep
};
#endif // Guard

File diff suppressed because it is too large Load Diff

View File

@ -33,6 +33,37 @@
//######################################################################
/// Remove all $signed, $unsigned, we're done with them.
class WidthRemoveVisitor : public AstNVisitor {
private:
// VISITORS
virtual void visit(AstSigned* nodep, AstNUser*) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
}
virtual void visit(AstUnsigned* nodep, AstNUser*) {
replaceWithSignedVersion(nodep, nodep->lhsp()->unlinkFrBack()); nodep=NULL;
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) {
UINFO(6," Replace "<<nodep<<" w/ "<<newp<<endl);
nodep->replaceWith(newp);
newp->widthSignedFrom(nodep);
pushDeletep(nodep); nodep=NULL;
}
public:
// CONSTRUCTORS
WidthRemoveVisitor() {}
virtual ~WidthRemoveVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
class WidthCommitVisitor : public AstNVisitor {
// Now that all widthing is complete,
// Copy all width() to widthMin(). V3Const expects this

View File

@ -111,12 +111,12 @@ private:
// We must make sure sub gets sign of original value
AstNode* newp = new AstSub(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), rhs));
newp->signedFrom(lhsp);
newp->numericFrom(lhsp);
return newp;
} else { // rhs < 0;
AstNode* newp = new AstAdd(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
newp->signedFrom(lhsp);
newp->numericFrom(lhsp);
return newp;
}
}
@ -126,7 +126,7 @@ private:
AstNode* newp = new AstSub(rhsp->fileline(),
new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs),
rhsp);
newp->signedFrom(rhsp); // Important as AstSub default is lhs's sign
newp->numericFrom(rhsp); // Important as AstSub default is lhs's sign
return newp;
}

View File

@ -74,7 +74,6 @@
#include "V3PreShell.h"
#include "V3Premit.h"
#include "V3Scope.h"
#include "V3Signed.h"
#include "V3Slice.h"
#include "V3Split.h"
#include "V3SplitAs.h"
@ -168,9 +167,6 @@ void process () {
V3Width::width(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("width.tree"));
// Compute signed/unsigned
V3Signed::signedAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("signed.tree"));
V3Error::abortIfErrors();
// Commit to the widths we've chosen; Make widthMin==width

View File

@ -9,7 +9,7 @@ use Pod::Usage;
use strict;
use vars qw ($Debug $VERSION);
$VERSION = '3.202';
$VERSION = '3.307';
our $Self;
@ -74,9 +74,10 @@ sub parameter {
sub process {
remove_outputs();
clean_input($Opt_Input, tmp_prefix().".y");
$Self->{bison_version} = bison_version_check();
my $supports_report = ($Self->{bison_version} >= 2.3);
my $supports_report = (bison_version_check() >= 2.3);
clean_input($Opt_Input, tmp_prefix().".y");
# Run bison
my $command = ($Opt_Yacc
@ -100,11 +101,11 @@ sub process {
die "bisonpre: %Error: $Opt_Yacc version $v run failed due to errors\n";
}
clean_output(tmp_prefix().".output",output_prefix().".output", 1);
clean_output(tmp_prefix().".output",output_prefix().".output", 1,0);
warning_check(output_prefix().".output");
clean_output(tmp_prefix().".c", output_prefix().".c", 0);
clean_output(tmp_prefix().".h", output_prefix().".h", 0);
clean_output(tmp_prefix().".c", output_prefix().".c", 0,1);
clean_output(tmp_prefix().".h", output_prefix().".h", 0,1);
remove_tmp();
}
@ -150,15 +151,17 @@ sub clean_output {
my $filename = shift;
my $outname = shift || $filename;
my $is_output = shift;
my $is_c = shift;
print " edit $filename $outname\n";
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
my @lines = $fh->getlines;
$fh->close;
(my $basename = tmp_prefix().".y") =~ s!.*/!!;
(my $basename = tmp_prefix().".") =~ s!.*/!!;
$basename = quotemeta($basename);
(my $newbase = $Opt_Input) =~ s!.*/!!;
$newbase =~ s/\.y/./;
if ($is_output) {
my %state_line; my $l=0;
@ -178,6 +181,28 @@ sub clean_output {
}
@lines = @out; @out = ();
}
if ($is_c) {
my %token_values;
my $in_en=0;
foreach my $line (@lines) {
$in_en=1 if $line =~ /enum\s+yytokentype/;
$in_en=0 if $line =~ /;/;
$token_values{$2} = $1 if $in_en && $line =~ /\b(\S+) = (\d+)/;
}
my @out;
foreach my $line (@lines) {
if ($line =~ /BISONPRE_TOKEN_NAMES/) {
push @out, $line;
foreach my $tv (sort keys %token_values) {
push @out, sprintf("\tcase %d: return \"%s\";\n",
$tv, $token_values{$tv});
}
next;
}
push @out, $line;
}
@lines = @out; @out = ();
}
$fh = IO::File->new(">$outname") or die "%Error: $! writing $outname\n";
foreach my $line (@lines) {
@ -211,6 +236,7 @@ sub clean_input {
my $outname = shift || $filename; # Can == filename if desired
print " edit $filename $outname\n";
$Self->{filename} = $filename;
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
my @lines = $fh->getlines;
$fh->close;
@ -232,7 +258,7 @@ sub clean_input {
$section++;
if ($section==2) { $last_rule = undef; }
}
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S+)>:/$1:/) {
elsif ($line =~ s/^([a-zA-Z0-9_]+)<(\S*)>:/$1:/) {
!$rules{$1}{name} or die "%Error: $filename:$l: Redeclaring '$1': $line\n";
$types{$2}{$1} = 1;
$rules{$1}{name} = $1;
@ -272,6 +298,25 @@ sub clean_input {
#use Data::Dumper; print Dumper(\%rules);
# Replace BISONPRE_VERSION(ver,,...) with expanded list
{
my @linesin = @lines; @lines=(); my $l=0;
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_VERSION/) {
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*([^\),]+)\)\s*$/)
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
my $ver=$1; my $cmd=$2;
if ($Self->{bison_version} >= $1) {
$line = $cmd."\n";
} else {
$line = "//NOP: $line";
}
}
push @lines, $line;
}
}
# Replace BISONPRE_NOT(type,...) with expanded list
{
my @linesin = @lines; @lines=(); my $l=0;
@ -308,20 +353,7 @@ sub clean_input {
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_COPY/) {
($line =~ s/BISONPRE_COPY\((\S+)\s*,\s*{([^}]*)}\s*\)/{HERE}/)
or die "%Error: $filename:$l: Bad form of BISONPRE_NOT: $line\n";
my $rule = $1; my $code = $2;
$rules{$rule} or die "%Error: $filename:$l: Can't find definition for rule: $rule\n";
# Push it all onto one line to avoid error messages changing
my $insert = $rules{$rule}{rules_and_productions};
$insert =~ s/^\S+://g; # Strip rule name
#print "COPY code $code\n";
#print "COPY in $insert\n";
$_=$insert; eval("$code; \$_;"); $insert = $_;
#print "COPY out $insert\n";
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
$line =~ s/{HERE}/$insert/;
$line = _bisonpre_copy($line,$l,0);
}
push @lines, $line;
}
@ -346,6 +378,7 @@ sub clean_input {
if ($line =~ m!//BISONPRE_TYPES!) {
push @lines, $line;
foreach my $type (sort keys %types) {
next if !$type;
my $line = "%type<$type>\t";
foreach my $rule (sort keys %{$types{$type}}) {
$line.=" ".$rule;
@ -372,6 +405,37 @@ sub clean_input {
$fh->close;
}
sub _bisonpre_copy {
my $text = shift;
my $l = shift;
my $depth = shift;
while ($text =~ /BISONPRE_COPY/) {
($text =~ s/BISONPRE_COPY(_ONCE)?\((\S+)\s*,\s*{([^}]*)}\s*\)/{HERE}/)
or die "%Error: $Self->{filename}:$l: Bad form of BISONPRE_NOT: $text\n";
my $once = $1; my $rule = $2; my $code = $3;
$Self->{rules}{$rule} or die "%Error: $Self->{filename}:$l: Can't find definition for rule: $rule\n";
if ($depth > 0 && $once) {
# _ONCE means don't inherit
$text =~ s/\|[ \t]+{HERE}//; # Don't OR in nothing
$text =~ s/{HERE}//;
} else {
# Push it all onto one line to avoid error messages changing
my $insert = $Self->{rules}{$rule}{rules_and_productions};
$insert =~ s/^\S+://g; # Strip rule name
# Recurse so BISONPRE under B
#print "COPY $l code $code\n";
#print "COPY $l in $insert\n";
$_=$insert; eval("$code; \$_;"); $insert = $_;
#print "COPY $l out $insert\n";
while ($insert =~ s/[ \t\n]+\n/\n/go) {}
while ($insert =~ s/\n/ /go) {} # Optional - preserve line numbering
$text =~ s/{HERE}/$insert/;
}
$depth++;
}
return $text;
}
#######################################################################
__END__
@ -416,10 +480,19 @@ rule. The type will be inserted where /*BISONPRE_TYPES*/ is encountered.
Copy the rules and productions from the specified rule, filter through the
Perl code provided in the {} and insert here into the output file.
=item BISONPRE_COPY_ONCE(rule, {code})
As with BISONPRE_COPY, but if called from underneath another BISONPRE_COPY
rule, ignore it.
=item BISONPRE_NOT(token[, token...])
Create a rule that matches every token except for those specified.
=item BISONPRE_VERSION(ver, cmd)
If the bison version is >= the specified version, include the given command.
=back
=head1 ARGUMENTS

View File

@ -174,6 +174,7 @@ word [a-zA-Z0-9_]+
/* Extensions to Verilog set, some specified by PSL */
"$c"[0-9]* { FL; return yD_C; } /*Verilator only*/
/* System Tasks */
"$bitstoreal" { FL; return yD_BITSTOREAL; }
"$display" { FL; return yD_DISPLAY; }
"$fclose" { FL; return yD_FCLOSE; }
"$fdisplay" { FL; return yD_FDISPLAY; }
@ -187,15 +188,18 @@ word [a-zA-Z0-9_]+
"$fullskew" { FL; return yaTIMINGSPEC; }
"$fwrite" { FL; return yD_FWRITE; }
"$hold" { FL; return yaTIMINGSPEC; }
"$itor" { FL; return yD_ITOR; }
"$nochange" { FL; return yaTIMINGSPEC; }
"$period" { FL; return yaTIMINGSPEC; }
"$random" { FL; return yD_RANDOM; }
"$readmemb" { FL; return yD_READMEMB; }
"$readmemh" { FL; return yD_READMEMH; }
"$realtime" { FL; return yD_TIME; }
"$realtime" { FL; return yD_REALTIME; }
"$realtobits" { FL; return yD_REALTOBITS; }
"$recovery" { FL; return yaTIMINGSPEC; }
"$recrem" { FL; return yaTIMINGSPEC; }
"$removal" { FL; return yaTIMINGSPEC; }
"$rtoi" { FL; return yD_RTOI; }
"$setup" { FL; return yaTIMINGSPEC; }
"$setuphold" { FL; return yaTIMINGSPEC; }
"$sformat" { FL; return yD_SFORMAT; }
@ -261,6 +265,8 @@ word [a-zA-Z0-9_]+
"pulldown" { FL; return yPULLDOWN; }
"pullup" { FL; return yPULLUP; }
"rcmos" { FL; return yRCMOS; }
"real" { FL; return yREAL; }
"realtime" { FL; return yREALTIME; }
"reg" { FL; return yREG; }
"repeat" { FL; return yREPEAT; }
"rnmos" { FL; return yRNMOS; }
@ -310,8 +316,6 @@ word [a-zA-Z0-9_]+
"medium" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"pull0" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"pull1" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"real" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"realtime" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"release" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"small" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"strong0" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
@ -812,11 +816,11 @@ word [a-zA-Z0-9_]+
return yaINTNUM;
}
[0-9][_0-9]*(\.[_0-9]+)([eE][-+]?[_0-9]+)? {
FL; yylval.cdouble = 0; /* Only for delays, not used yet */
FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng);
return yaFLOATNUM;
}
[0-9][_0-9]*(\.[_0-9]+)?([eE][-+]?[_0-9]+) {
FL; yylval.cdouble = 0; /* Only for delays, not used yet */
FL; yylval.cdouble = PARSEP->parseDouble(yytext, yyleng);
return yaFLOATNUM;
}
[0-9][_0-9]*(\.[_0-9]+)?(fs|ps|ns|us|ms|s|step) {
@ -949,6 +953,21 @@ word [a-zA-Z0-9_]+
%%
int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; }
double V3ParseImp::parseDouble(const char* textp, size_t length) {
char* strgp = new char[length+1];
char* dp=strgp;
for (const char* sp=textp; sp<(textp+length);) {
if (*sp != '_') *dp++ = *sp++;
else sp++;
}
*dp++ = '\0';
char* endp = strgp;
double d = strtod(strgp, &endp);
if ((endp-strgp) != length) { yyerrorf("Syntax error parsing real: %s",strgp); }
delete strgp;
return d;
}
int V3ParseImp::lexToken() {
// called from lexToBison, has a "this"
// Fetch next token from prefetch or real lexer

View File

@ -342,6 +342,8 @@ class AstSenTree;
%token<fl> yPULLUP "pullup"
%token<fl> yPURE "pure"
%token<fl> yRCMOS "rcmos"
%token<fl> yREAL "real"
%token<fl> yREALTIME "realtime"
%token<fl> yREG "reg"
%token<fl> yREPEAT "repeat"
%token<fl> yRETURN "return"
@ -382,6 +384,7 @@ class AstSenTree;
%token<fl> yXOR "xor"
%token<fl> yD_BITS "$bits"
%token<fl> yD_BITSTOREAL "$bitstoreal"
%token<fl> yD_C "$c"
%token<fl> yD_CLOG2 "$clog2"
%token<fl> yD_COUNTONES "$countones"
@ -400,11 +403,15 @@ class AstSenTree;
%token<fl> yD_FWRITE "$fwrite"
%token<fl> yD_INFO "$info"
%token<fl> yD_ISUNKNOWN "$isunknown"
%token<fl> yD_ITOR "$itor"
%token<fl> yD_ONEHOT "$onehot"
%token<fl> yD_ONEHOT0 "$onehot0"
%token<fl> yD_RANDOM "$random"
%token<fl> yD_READMEMB "$readmemb"
%token<fl> yD_READMEMH "$readmemh"
%token<fl> yD_REALTIME "$realtime"
%token<fl> yD_REALTOBITS "$realtobits"
%token<fl> yD_RTOI "$rtoi"
%token<fl> yD_SFORMAT "$sformat"
%token<fl> yD_SIGNED "$signed"
%token<fl> yD_SSCANF "$sscanf"
@ -1067,6 +1074,12 @@ integer_vector_type<bdtypep>: // ==IEEE: integer_atom_type
| yREG { $$ = new AstBasicDType($1,AstBasicDTypeKwd::LOGIC); } // logic==reg
;
non_integer_type<bdtypep>: // ==IEEE: non_integer_type
yREAL { $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); }
| yREALTIME { $$ = new AstBasicDType($1,AstBasicDTypeKwd::DOUBLE); }
//UNSUP ySHORTREAL { $$ = new AstBasicDType($1,AstBasicDTypeKwd::FLOAT); }
;
signingE<signstate>: // IEEE: signing - plus empty
/*empty*/ { $$ = signedst_NOP; }
| signing { $$ = $1; }
@ -1097,7 +1110,7 @@ simple_type<dtypep>: // ==IEEE: simple_type
// // IEEE: integer_type
integer_atom_type { $$ = $1; }
| integer_vector_type { $$ = $1; }
//UNSUP non_integer_type { $$ = $1; }
| non_integer_type { $$ = $1; }
// // IEEE: ps_type_identifier
// // IEEE: ps_parameter_identifier (presumably a PARAMETER TYPE)
| ps_type { $$ = $1; }
@ -1120,7 +1133,7 @@ data_type<dtypep>: // ==IEEE: data_type
data_typeBasic<dtypep>: // IEEE: part of data_type
integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
//UNSUP non_integer_type { UNSUP }
| non_integer_type { $$ = $1; }
;
data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc references
@ -1527,8 +1540,7 @@ delay_value: // ==IEEE:delay_value
delayExpr:
expr { }
// // Verilator doesn't support yaFLOATNUM/yaTIMENUM, so not in expr
| yaFLOATNUM { }
// // Verilator doesn't support yaTIMENUM, so not in expr
| yaTIMENUM { }
;
@ -1713,8 +1725,6 @@ cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment
| expr { $$ = new AstPin($1->fileline(),PINNUMINC(),"",$1); }
//UNSUP expr ':' expr { }
//UNSUP expr ':' expr ':' expr { }
// // Floatnum should only occur with UDPs, but since ports aren't floats, it's legal to round always
| yaFLOATNUM { $$ = new AstPin($<fl>1,PINNUMINC(),"",new AstConst($<fl>1,AstConst::Unsized32(),(int)(($1<0)?($1-0.5):($1+0.5)))); }
;
//************************************************
@ -2144,6 +2154,7 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
//
| yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::EXPR_BITS,$3); }
| yD_BITS '(' data_type ')' { $$ = new AstAttrOf($1,AstAttrType::EXPR_BITS,$3); }
| yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); }
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); }
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); }
| yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); }
@ -2153,10 +2164,14 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); }
| yD_ITOR '(' expr ')' { $$ = new AstIToRD($1,$3); }
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
| yD_RANDOM '(' expr ')' { $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")"); }
| yD_RANDOM parenE { $$ = new AstRand($1); }
| yD_REALTIME parenE { $$ = new AstTimeD($1); }
| yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); }
| yD_RTOI '(' expr ')' { $$ = new AstRToIS($1,$3); }
//| yD_SFORMATF '(' str commaEListE ')' { $$ = new AstSFormatF($1,*$3,false,$4); } // Have AST, just need testing and debug
| yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); }
| yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); }
@ -2455,7 +2470,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
//
// // IEEE: primary_literal (minus string, which is handled specially)
| yaINTNUM { $$ = new AstConst($<fl>1,*$1); }
//UNSUP yaFLOATNUM { UNSUP }
| yaFLOATNUM { $$ = new AstConst($<fl>1,AstConst::RealDouble(),$1); }
//UNSUP yaTIMENUM { UNSUP }
| strAsInt~noStr__IGNORE~ { $$ = $1; }
//

View File

@ -165,7 +165,7 @@ sub one_test {
if ($opt_stop) { die "%Error: --stop and errors found\n"; }
}
$leftcnt--;
print "==SUMMARY: Left $leftcnt Passed $okcnt Skipped $skcnt Failed $failcnt\n";
print STDERR "==SUMMARY: Left $leftcnt Passed $okcnt Skipped $skcnt Failed $failcnt\n";
},
)->ready();
}

View File

@ -59,7 +59,9 @@ module t (/*AUTOARG*/
reg [7:0] cyc; initial cyc=0;
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] rs %x cyc %d cg1f %x cnt %x cg %x\n",$time,reset_l,cyc,clkgate_e1f,count,countgated);
`endif
cyc <= cyc + 8'd1;
case (cyc)
8'd00: begin

View File

@ -19,10 +19,12 @@ execute (
[0] In top.v.sub2
[0] In top.v.sub2.subblock2
[0] Back \ Quote "
[0] %X=0c %D=12 %0X=c %0O=14 %B=001100
[0] %x=0c %d=12 %0x=c %0o=14 %b=001100
[0] %X=00c %0X=c %0O=14 %B=000001100
[0] %x=00c %0x=c %0o=14 %b=000001100
[0] %D= 12 %d= 12 %01d=12 %06d=000012 %6d= 12
[0] %x=00abbbbcccc %0x=abbbbcccc %o=00527356746314 %b=00000101010111011101110111100110011001100
[0] %x=00abc1234567812345678 %0x=abc1234567812345678 %o=012570110642547402215053170 %b=000001010101111000001001000110100010101100111100000010010001101000101011001111000
[0] %t= 0 %03t= 0 %0t=0
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.

View File

@ -9,6 +9,7 @@ module t;
reg [31:0] str; initial str = "\000\277\021\n";
reg [47:0] str2; initial str2 = "\000what!";
reg [79:0] str3; initial str3 = "\000hmmm!1234";
reg [8:0] nine;
sub sub ();
sub2 sub2 ();
@ -22,14 +23,19 @@ module t;
$display("[%0t] Back \\ Quote \"", $time); // Old bug when \" last on the line.
// Display formatting
$display("[%0t] %%X=%X %%D=%D %%0X=%0X %%0O=%0O %%B=%B", $time,
quad[5:0], quad[5:0], quad[5:0], quad[5:0], quad[5:0]);
$display("[%0t] %%x=%x %%d=%d %%0x=%0x %%0o=%0o %%b=%b", $time,
quad[5:0], quad[5:0], quad[5:0], quad[5:0], quad[5:0]);
nine = {3'd0,quad[5:0]};
$display("[%0t] %%X=%X %%0X=%0X %%0O=%0O %%B=%B", $time,
nine, nine, nine, nine);
$display("[%0t] %%x=%x %%0x=%0x %%0o=%0o %%b=%b", $time,
nine, nine, nine, nine);
$display("[%0t] %%D=%D %%d=%d %%01d=%01d %%06d=%06d %%6d=%6d", $time,
nine, nine, nine, nine, nine);
$display("[%0t] %%x=%x %%0x=%0x %%o=%o %%b=%b", $time,
quad, quad, quad, quad);
$display("[%0t] %%x=%x %%0x=%0x %%o=%o %%b=%b", $time,
wide, wide, wide, wide);
$display("[%0t] %%t=%t %%03t=%03t %%0t=%0t", $time,
$time, $time, $time);
$display;
// Not testing %0s, it does different things in different simulators
$display("[%0t] %%s=%s %%s=%s %%s=%s", $time,

View File

@ -22,10 +22,12 @@ execute (
[0] In top.v.sub2
[0] In top.v.sub2.subblock2
[0] Back \ Quote "
[0] %X=0c %D=12 %0X=c %0O=14 %B=001100
[0] %x=0c %d=12 %0x=c %0o=14 %b=001100
[0] %X=00c %0X=c %0O=14 %B=000001100
[0] %x=00c %0x=c %0o=14 %b=000001100
[0] %D= 12 %d= 12 %01d=12 %06d=000012 %6d= 12
[0] %x=00abbbbcccc %0x=abbbbcccc %o=00527356746314 %b=00000101010111011101110111100110011001100
[0] %x=00abc1234567812345678 %0x=abc1234567812345678 %o=012570110642547402215053170 %b=000001010101111000001001000110100010101100111100000010010001101000101011001111000
[0] %t= 0 %03t= 0 %0t=0
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.

View File

@ -0,0 +1,39 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# 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
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
expect=> quotemeta(
'[0] e=0.000000e+00 e1=0.000000e+00 e30=0e+00 e32=0.00e+00
[0] f=0.000000 f1=0.000000e+00 f30=0e+00 f32=0.00e+00
[0] g=0 g1=0.000000e+00 g30=0e+00 g32=0.00e+00
[0] e=1.000000e+00 e1=1.000000e+00 e30=1e+00 e32=1.00e+00
[0] f=1.000000 f1=1.000000e+00 f30=1e+00 f32=1.00e+00
[0] g=1 g1=1.000000e+00 g30=1e+00 g32=1.00e+00
[0] e=1.000000e-01 e1=1.000000e-01 e30=1e-01 e32=1.00e-01
[0] f=0.100000 f1=1.000000e-01 f30=1e-01 f32=1.00e-01
[0] g=0.1 g1=1.000000e-01 g30=1e-01 g32=1.00e-01
[0] e=1.234500e-15 e1=1.234500e-15 e30=1e-15 e32=1.23e-15
[0] f=0.000000 f1=1.234500e-15 f30=1e-15 f32=1.23e-15
[0] g=1.2345e-15 g1=1.234500e-15 g30=1e-15 g32=1.23e-15
[0] e=2.579000e+15 e1=2.579000e+15 e30=3e+15 e32=2.58e+15
[0] f=2579000000000000.000000 f1=2.579000e+15 f30=3e+15 f32=2.58e+15
[0] g=2.579e+15 g1=2.579000e+15 g30=3e+15 g32=2.58e+15
'),
);
ok(1);
1;

View File

@ -0,0 +1,37 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t;
real n0; initial n0 = 0.0;
real n1; initial n1 = 1.0;
real n2; initial n2 = 0.1;
real n3; initial n3 = 1.2345e-15;
real n4; initial n4 = 2.579e+15;
initial begin
// Display formatting
$display("[%0t] e=%e e1=%1e e30=%3.0e e32=%3.2e", $time, n0,n0,n0,n0);
$display("[%0t] f=%f f1=%1e f30=%3.0e f32=%3.2e", $time, n0,n0,n0,n0);
$display("[%0t] g=%g g1=%1e g30=%3.0e g32=%3.2e", $time, n0,n0,n0,n0);
$display;
$display("[%0t] e=%e e1=%1e e30=%3.0e e32=%3.2e", $time, n1,n1,n1,n1);
$display("[%0t] f=%f f1=%1e f30=%3.0e f32=%3.2e", $time, n1,n1,n1,n1);
$display("[%0t] g=%g g1=%1e g30=%3.0e g32=%3.2e", $time, n1,n1,n1,n1);
$display;
$display("[%0t] e=%e e1=%1e e30=%3.0e e32=%3.2e", $time, n2,n2,n2,n2);
$display("[%0t] f=%f f1=%1e f30=%3.0e f32=%3.2e", $time, n2,n2,n2,n2);
$display("[%0t] g=%g g1=%1e g30=%3.0e g32=%3.2e", $time, n2,n2,n2,n2);
$display;
$display("[%0t] e=%e e1=%1e e30=%3.0e e32=%3.2e", $time, n3,n3,n3,n3);
$display("[%0t] f=%f f1=%1e f30=%3.0e f32=%3.2e", $time, n3,n3,n3,n3);
$display("[%0t] g=%g g1=%1e g30=%3.0e g32=%3.2e", $time, n3,n3,n3,n3);
$display;
$display("[%0t] e=%e e1=%1e e30=%3.0e e32=%3.2e", $time, n4,n4,n4,n4);
$display("[%0t] f=%f f1=%1e f30=%3.0e f32=%3.2e", $time, n4,n4,n4,n4);
$display("[%0t] g=%g g1=%1e g30=%3.0e g32=%3.2e", $time, n4,n4,n4,n4);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,42 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# 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
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
top_filename("t/t_display_real.v");
compile (
v_flags2 => [$Self->{v3}?"-O0":""],
);
execute (
check_finished=>1,
expect=> quotemeta(
'[0] e=0.000000e+00 e1=0.000000e+00 e30=0e+00 e32=0.00e+00
[0] f=0.000000 f1=0.000000e+00 f30=0e+00 f32=0.00e+00
[0] g=0 g1=0.000000e+00 g30=0e+00 g32=0.00e+00
[0] e=1.000000e+00 e1=1.000000e+00 e30=1e+00 e32=1.00e+00
[0] f=1.000000 f1=1.000000e+00 f30=1e+00 f32=1.00e+00
[0] g=1 g1=1.000000e+00 g30=1e+00 g32=1.00e+00
[0] e=1.000000e-01 e1=1.000000e-01 e30=1e-01 e32=1.00e-01
[0] f=0.100000 f1=1.000000e-01 f30=1e-01 f32=1.00e-01
[0] g=0.1 g1=1.000000e-01 g30=1e-01 g32=1.00e-01
[0] e=1.234500e-15 e1=1.234500e-15 e30=1e-15 e32=1.23e-15
[0] f=0.000000 f1=1.234500e-15 f30=1e-15 f32=1.23e-15
[0] g=1.2345e-15 g1=1.234500e-15 g30=1e-15 g32=1.23e-15
[0] e=2.579000e+15 e1=2.579000e+15 e30=3e+15 e32=2.58e+15
[0] f=2579000000000000.000000 f1=2.579000e+15 f30=3e+15 f32=2.58e+15
[0] g=2.579e+15 g1=2.579000e+15 g30=3e+15 g32=2.58e+15
'),
);
ok(1);
1;

View File

@ -39,9 +39,7 @@ module t ();
import "DPI-C" pure function longint dpii_f_longint (input longint i);
import "DPI-C" pure function chandle dpii_f_chandle (input chandle i);
import "DPI-C" pure function string dpii_f_string (input string i);
`ifndef VERILATOR
import "DPI-C" pure function real dpii_f_real (input real i);
`endif
`ifndef NO_SHORTREAL
import "DPI-C" pure function shortreal dpii_f_shortreal(input shortreal i);
`endif
@ -53,9 +51,7 @@ module t ();
import "DPI-C" pure function void dpii_v_longint (input longint i, output longint o);
import "DPI-C" pure function void dpii_v_chandle (input chandle i, output chandle o);
import "DPI-C" pure function void dpii_v_string (input string i, output string o);
`ifndef VERILATOR
import "DPI-C" pure function void dpii_v_real (input real i, output real o);
`endif
`ifndef NO_SHORTREAL
import "DPI-C" pure function void dpii_v_shortreal(input shortreal i, output shortreal o);
`endif
@ -93,9 +89,7 @@ module t ();
longint i_l, o_l;
chandle i_c, o_c;
string i_n, o_n;
`ifndef VERILATOR
real i_d, o_d;
`endif
`ifndef NO_SHORTREAL
shortreal i_f, o_f;
`endif
@ -122,6 +116,10 @@ module t ();
i_y = {1'b1,wide[8-2:0]};
i_s = {1'b1,wide[16-2:0]};
i_l = {1'b1,wide[64-2:0]};
i_d = 32.1;
`ifndef NO_SHORTREAL
i_f = 30.2;
`endif
if (dpii_f_bit (i_b) !== ~i_b) $stop;
if (dpii_f_bit8 (i_b8) !== ~i_b8) $stop;
@ -145,9 +143,7 @@ module t ();
if (dpii_f_longint (i_l) !== ~i_l) $stop;
if (dpii_f_chandle (i_c) !== i_c) $stop;
if (dpii_f_string (i_n) != i_n) $stop;
`ifndef VERILATOR
if (dpii_f_real (i_d) != i_d+1.5) $stop;
`endif
`ifndef NO_SHORTREAL
if (dpii_f_shortreal(i_f) != i_f+1.5) $stop;
`endif
@ -159,9 +155,7 @@ module t ();
dpii_v_longint (i_l,o_l); if (o_l !== ~i_l) $stop;
dpii_v_chandle (i_c,o_c); if (o_c !== i_c) $stop;
dpii_v_string (i_n,o_n); if (o_n != i_n) $stop;
`ifndef VERILATOR
dpii_v_real (i_d,o_d); if (o_d != i_d+1.5) $stop;
`endif
`ifndef NO_SHORTREAL
dpii_v_shortreal(i_f,o_f); if (o_f != i_f+1.5) $stop;
`endif

View File

@ -13,8 +13,6 @@ compile (
expect=>
q{%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to FUNC 'add'
%Error: t/t_func_bad.v:\d+: Too many arguments in function call to FUNC 'add'
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to TASK 'x'
%Error: t/t_func_bad.v:\d+: Too few arguments in function call to TASK 'x'

View File

@ -0,0 +1,23 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-2009 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.
compile (
make_top_shell => 0,
make_main => 0,
v_flags2 => ["--lint-only -Wwarn-REALCVT"],
verilator_make_gcc => 0,
fails=>1,
expect=>
'%Warning-REALCVT: t/t_lint_realcvt_bad.v:\d+: Implicit conversion of real to integer
%Warning-REALCVT: Use .* to disable this message.
%Error: Exiting due to.*',
) if $Self->{v3};
ok(1);
1;

View File

@ -0,0 +1,11 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2011 by Wilson Snyder.
module sub;
integer i;
initial begin
i = 23.2;
end
endmodule

18
test_regress/t/t_math_real.pl Executable file
View File

@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# 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
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;

View File

@ -0,0 +1,136 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// Copyright 2011 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.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer i;
reg [63:0] b;
real r, r2;
integer cyc=0;
realtime uninit;
initial if (uninit != 0.0) $stop;
initial begin
// rtoi truncates
if ($rtoi(36.7) != 36) $stop;
if ($rtoi(36.5) != 36) $stop;
if ($rtoi(36.4) != 36) $stop;
// casting rounds
if ((integer '(36.7)) != 37) $stop;
if ((integer '(36.5)) != 37) $stop;
if ((integer '(36.4)) != 36) $stop;
// assignment rounds
// verilator lint_off REALCVT
i = 36.7; if (i != 37) $stop;
i = 36.5; if (i != 37) $stop;
i = 36.4; if (i != 36) $stop;
r = 10'd38; if (r!=38.0) $stop;
// verilator lint_on REALCVT
// operators
if ((-(1.5)) != -1.5) $stop;
if ((+(1.5)) != 1.5) $stop;
if (((1.5)+(1.25)) != 2.75) $stop;
if (((1.5)-(1.25)) != 0.25) $stop;
if (((1.5)*(1.25)) != 1.875) $stop;
if (((1.5)/(1.25)) != 1.2) $stop;
//
if (((1.5)==(2)) != 1'b0) $stop; // note 2 becomes real 2.0
if (((1.5)!=(2)) != 1'b1) $stop;
if (((1.5)> (2)) != 1'b0) $stop;
if (((1.5)>=(2)) != 1'b0) $stop;
if (((1.5)< (2)) != 1'b1) $stop;
if (((1.5)<=(2)) != 1'b1) $stop;
if (((1.5)==(1.5)) != 1'b1) $stop;
if (((1.5)!=(1.5)) != 1'b0) $stop;
if (((1.5)> (1.5)) != 1'b0) $stop;
if (((1.5)>=(1.5)) != 1'b1) $stop;
if (((1.5)< (1.5)) != 1'b0) $stop;
if (((1.5)<=(1.5)) != 1'b1) $stop;
if (((1.6)==(1.5)) != 1'b0) $stop;
if (((1.6)!=(1.5)) != 1'b1) $stop;
if (((1.6)> (1.5)) != 1'b1) $stop;
if (((1.6)>=(1.5)) != 1'b1) $stop;
if (((1.6)< (1.5)) != 1'b0) $stop;
if (((1.6)<=(1.5)) != 1'b0) $stop;
//
if (((0.0)?(2.0):(1.1)) != 1.1) $stop;
if (((1.5)?(2.0):(1.1)) != 2.0) $stop;
//
if (!1.7) $stop;
if (!(!0.0)) $stop;
if (1.8 && 0.0) $stop;
if (!(1.8 || 0.0)) $stop;
//
i=0;
for (r=1.0; r<2.0; r=r+0.1) i++;
if (i!=10) $stop;
end
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`endif
cyc <= cyc + 1;
if (cyc==0) begin
// Setup
end
else if (cyc<90) begin
if ($time != {32'h0, $rtoi($realtime)}) $stop;
if ($itor(cyc) != cyc) $stop;
//Unsup: if ((real `($time)) != $realtime) $stop;
r = $itor(cyc*2);
i = $rtoi(r);
if (i!=cyc*2) $stop;
//
r = $itor(cyc)/1.5;
b = $realtobits(r);
r2 = $bitstoreal(b);
if (r != r2) $stop;
//
// Trust the integer math as a comparison
r = $itor(cyc);
if ($rtoi(-r) != -cyc) $stop;
if ($rtoi(+r) != cyc) $stop;
if ($rtoi(r+2.0) != (cyc+2)) $stop;
if ($rtoi(r-2.0) != (cyc-2)) $stop;
if ($rtoi(r*2.0) != (cyc*2)) $stop;
if ($rtoi(r/2.0) != (cyc/2)) $stop;
r2 = (2.0/(r-60)); // When zero, result indeterminate, but no crash
//
r2 = $itor(cyc);
case (r)
(r2-1.0): $stop;
r2: ;
default: $stop;
endcase
//
r = $itor(cyc);
if ((r==50.0) != (cyc==50)) $stop;
if ((r!=50.0) != (cyc!=50)) $stop;
if ((r> 50.0) != (cyc> 50)) $stop;
if ((r>=50.0) != (cyc>=50)) $stop;
if ((r< 50.0) != (cyc< 50)) $stop;
if ((r<=50.0) != (cyc<=50)) $stop;
//
if ($rtoi((r-50.0) ? 10.0 : 20.0)
!= (((cyc-50)!=0) ? 10 : 20)) $stop;
//
if ((!(r-50.0)) != (!((cyc-50) != 0))) $stop;
end
else if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

View File

@ -43,8 +43,10 @@ module t (/*AUTOARG*/
integer i;
initial begin
if ((-1 >>> 3) != -1) $stop; // Decimals are signed
// verilator lint_off WIDTH
if ((3'b111 >>> 3) != 0) $stop; // Based numbers are unsigned
if ((3'sb111 >>> 3) != -1) $stop; // Signed based numbers
// verilator lint_on WIDTH
if ( (3'sb000 > 3'sb000)) $stop;
if (!(3'sb000 > 3'sb111)) $stop;
if ( (3'sb111 > 3'sb000)) $stop;

View File

@ -16,6 +16,8 @@ module t;
reg [48*8:1] str;
reg [48*8:1] str2;
real r;
initial begin
n = 4'b1100;
q = 64'h1234_5678_abcd_0123;
@ -29,6 +31,15 @@ module t;
`ifdef TEST_VERBOSE $display("str2=%0s",str2); `endif
if (str2 !== "n=1100 q= 2623536935500120647 w=hello-there12345") $stop;
$swrite(str2, "e=%e", r);
$swrite(str2, "e=%f", r);
$swrite(str2, "e=%g", r);
r = 0.01;
$swrite(str2, "e=%e f=%f g=%g", r, r, r);
`ifdef TEST_VERBOSE $display("str2=%0s",str2); `endif
if (str2 !== "e=1.000000e-02 f=0.010000 g=0.01") $stop;
$swrite(str2, "mod=%m");
`ifdef TEST_VERBOSE $display("str2=%0s",str2); `endif
`ifdef verilator

View File

@ -15,12 +15,14 @@ module t (/*AUTOARG*/
integer b_trace_off;
// verilator tracing_on
integer c_trace_on;
real r;
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
b_trace_off <= cyc;
c_trace_on <= b_trace_off;
r <= r + 0.1;
if (cyc==4) begin
if (c_trace_on != 2) $stop;
end

View File

@ -25,8 +25,8 @@ module t (/*AUTOARG*/);
// IEEE: non_integer_type
//UNSUP shortreal d_shortreal;
//UNSUP real d_real;
//UNSUP realtime d_realtime;
real d_real;
realtime d_realtime;
// Declarations using var
var byte v_b;