mirror of
https://github.com/verilator/verilator.git
synced 2025-04-15 17:16:55 +00:00
Support 'real' numbers and related functions.
This commit is contained in:
parent
d5478e6e08
commit
55906486d8
2
Changes
2
Changes
@ -5,6 +5,8 @@ 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.
|
||||
|
@ -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
|
||||
|
@ -209,7 +209,6 @@ RAW_OBJS = \
|
||||
V3PreShell.o \
|
||||
V3Premit.o \
|
||||
V3Scope.o \
|
||||
V3Signed.o \
|
||||
V3Slice.o \
|
||||
V3Split.o \
|
||||
V3SplitAs.o \
|
||||
|
@ -817,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
|
||||
|
||||
@ -1323,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
|
||||
@ -1334,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) {
|
||||
@ -1361,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; }
|
||||
|
@ -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());
|
||||
|
283
src/V3AstNodes.h
283
src/V3AstNodes.h
@ -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}
|
||||
@ -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); }
|
||||
|
@ -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 {
|
||||
|
@ -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)");
|
||||
|
@ -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);
|
||||
@ -2013,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 ");
|
||||
@ -2042,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 ");
|
||||
|
@ -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
|
||||
|
@ -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());
|
||||
|
@ -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();
|
||||
|
451
src/V3Signed.cpp
451
src/V3Signed.cpp
@ -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->numericFrom(nodep->dtypep());
|
||||
}
|
||||
virtual void visit(AstNodeVarRef* nodep, AstNUser*) {
|
||||
nodep->varp()->iterate(*this);
|
||||
nodep->numericFrom(nodep->varp());
|
||||
}
|
||||
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
|
||||
nodep->itemp()->iterate(*this);
|
||||
nodep->numericFrom(nodep->itemp());
|
||||
}
|
||||
virtual void visit(AstCast* nodep, AstNUser*) {
|
||||
nodep->lhsp()->iterate(*this);
|
||||
nodep->dtypep()->iterate(*this);
|
||||
nodep->numericFrom(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->numericFrom(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->numericFrom(nodep->taskp());
|
||||
}
|
||||
virtual void visit(AstRefDType* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
if (nodep->defp()) nodep->defp()->iterate(*this);
|
||||
nodep->numericFrom(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;
|
||||
}
|
@ -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
|
1056
src/V3Width.cpp
1056
src/V3Width.cpp
File diff suppressed because it is too large
Load Diff
@ -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
|
||||
|
@ -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
|
||||
|
@ -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); }
|
||||
@ -950,12 +954,13 @@ 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[strlen(textp)+1];
|
||||
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); }
|
||||
|
@ -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; }
|
||||
//
|
||||
|
39
test_regress/t/t_display_real.pl
Executable file
39
test_regress/t/t_display_real.pl
Executable 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;
|
37
test_regress/t/t_display_real.v
Normal file
37
test_regress/t/t_display_real.v
Normal 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
|
42
test_regress/t/t_display_real_noopt.pl
Executable file
42
test_regress/t/t_display_real_noopt.pl
Executable 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;
|
@ -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
|
||||
|
@ -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'
|
||||
|
23
test_regress/t/t_lint_realcvt_bad.pl
Executable file
23
test_regress/t/t_lint_realcvt_bad.pl
Executable 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;
|
11
test_regress/t/t_lint_realcvt_bad.v
Normal file
11
test_regress/t/t_lint_realcvt_bad.v
Normal 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
18
test_regress/t/t_math_real.pl
Executable 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;
|
136
test_regress/t/t_math_real.v
Normal file
136
test_regress/t/t_math_real.v
Normal 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
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user