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

This commit is contained in:
Wilson Snyder
2011-07-11 08:10:28 -04:00
46 changed files with 763 additions and 564 deletions
+6
View File
@@ -5,8 +5,14 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.814**** * Verilator 3.814****
*** Support 'const' variables in limited cases; similar to enums. [Alex Solomatnikov]
*** Support disable for loop escapes. *** Support disable for loop escapes.
*** Support $fopen and I/O with integer instead of `verilator_file_descriptor.
**** Use 'vluint64_t' for SystemC instead of (same sized) 'uint64' for MSVC++.
* Verilator 3.813 2011/06/28 * Verilator 3.813 2011/06/28
*** Support bit vectors > 64 bits wide in DPI import and exports. *** Support bit vectors > 64 bits wide in DPI import and exports.
+8 -13
View File
@@ -268,7 +268,7 @@ descriptions in the next sections for more information.
--MP Create phony dependency targets --MP Create phony dependency targets
--Mdir <directory> Name of output object directory --Mdir <directory> Name of output object directory
--mod-prefix <topname> Name to prepend to lower classes --mod-prefix <topname> Name to prepend to lower classes
--no-pins64 Don't use uint64_t's for 33-64 bit sigs --no-pins64 Don't use vluint64_t's for 33-64 bit sigs
--no-skip-identical Disable skipping identical output --no-skip-identical Disable skipping identical output
+notimingchecks Ignored +notimingchecks Ignored
-O0 Disable optimizations -O0 Disable optimizations
@@ -713,7 +713,7 @@ Backward compatible alias for "--pins-bv 65". Note that's a 65, not a 64.
=item --pins-bv I<width> =item --pins-bv I<width>
Specifies SystemC inputs/outputs of greater than or equal to I<width> bits Specifies SystemC inputs/outputs of greater than or equal to I<width> bits
wide should use sc_bv's instead of uint32/uint64_t's. The default is wide should use sc_bv's instead of uint32/vluint64_t's. The default is
"--pins-bv 65". Versions before Verilator 3.671 defaulted to "--pins-bv "--pins-bv 65". Versions before Verilator 3.671 defaulted to "--pins-bv
33". The more sc_bv is used, the worse for performance. 33". The more sc_bv is used, the worse for performance.
@@ -1352,7 +1352,7 @@ will plug directly into a SystemC netlist.
The SC_MODULE gets the same pinout as the Verilog module, with the The SC_MODULE gets the same pinout as the Verilog module, with the
following type conversions: Pins of a single bit become bool. Pins 2-32 following type conversions: Pins of a single bit become bool. Pins 2-32
bits wide become uint32_t's. Pins 33-64 bits wide become sc_bv's or bits wide become uint32_t's. Pins 33-64 bits wide become sc_bv's or
uint64_t's depending on the --no-pins64 switch. Wider pins become sc_bv's. vluint64_t's depending on the --no-pins64 switch. Wider pins become sc_bv's.
(Uints simulate the fastest so are used where possible.) (Uints simulate the fastest so are used where possible.)
Lower modules are not pure SystemC code. This is a feature, as using the Lower modules are not pure SystemC code. This is a feature, as using the
@@ -1661,7 +1661,7 @@ please file a bug if a feature you need is missing.
Verilator supports ==? and !=? operators, ++ and -- in some contexts, Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0, $bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle, $unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
do-while, enum, export, final, import, int, logic, longint, package, const, do-while, enum, export, final, import, int, logic, longint, package,
program, shortint, time, typedef, var, void, priority case/if, and unique program, shortint, time, typedef, var, void, priority case/if, and unique
case/if. case/if.
@@ -1711,8 +1711,8 @@ assertion clocks.
=head2 Synthesis Directive Assertion Support =head2 Synthesis Directive Assertion Support
With the --assert switch, Verilator reads any "//synopsys full_case" or "// With the --assert switch, Verilator reads any "//synopsys full_case" or "//
synopsys parallel_case" directives. The same applies to any "//cadence" or synopsys parallel_case" directives. The same applies to any "// ambit
"// ambit synthesis" directives of the same form. synthesis", "//cadence" or "//pragma" directives of the same form.
When these synthesis directives are discovered, Verilator will either When these synthesis directives are discovered, Verilator will either
formally prove the directive to be true, or failing that, will insert the formally prove the directive to be true, or failing that, will insert the
@@ -2261,7 +2261,7 @@ specified as illegal on chandles.
=item disable =item disable
Disable statements may be used only if the block being disabled is a block Disable statements may be used only if the block being disabled is a block
the disable statement itself is inside. This is commonly used to provide the disable statement itself is inside. This was commonly used to provide
loop break and continue functionality before SystemVerilog added the break loop break and continue functionality before SystemVerilog added the break
and continue keywords. and continue keywords.
@@ -2313,11 +2313,6 @@ The rarely used optional parameter to $finish and $stop is ignored.
File descriptors passed to the file PLI calls must be file descriptors, not File descriptors passed to the file PLI calls must be file descriptors, not
MCDs, which includes the mode parameter to $fopen being mandatory. MCDs, which includes the mode parameter to $fopen being mandatory.
Verilator will convert the integer used to hold the file descriptor into a
internal FILE*. To prevent core dumps due to mis-use, and because integers
are 32 bits while FILE*s may be 64 bits, the descriptor must be stored in a
reg [63:0] rather than an integer. The define `verilator_file_descriptor in
verilated.v can be used to hide this difference.
=item $fscanf, $sscanf =item $fscanf, $sscanf
@@ -3182,7 +3177,7 @@ as you would any other member variable.
Signals are the smallest of 8 bit chars, 16 bit shorts, 32 bit longs, or 64 Signals are the smallest of 8 bit chars, 16 bit shorts, 32 bit longs, or 64
bit long longs that fits the width of the signal. Generally, you can use bit long longs that fits the width of the signal. Generally, you can use
just uint32_t's for 1 to 32 bits, or uint64_t for 1 to 64 bits, and the just uint32_t's for 1 to 32 bits, or vluint64_t for 1 to 64 bits, and the
compiler will properly up-convert smaller entities. compiler will properly up-convert smaller entities.
Signals wider than 64 bits are stored as an array of 32-bit uint32_t's. Signals wider than 64 bits are stored as an array of 32-bit uint32_t's.
+17 -8
View File
@@ -26,7 +26,6 @@
#define _VERILATED_CPP_ #define _VERILATED_CPP_
#include "verilated_imp.h" #include "verilated_imp.h"
#include <cctype> #include <cctype>
#include <vector>
#define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING #define VL_VALUE_STRING_MAX_WIDTH 1024 ///< Max static char array for VL_VALUE_STRING
@@ -628,6 +627,10 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
//=========================================================================== //===========================================================================
// File I/O // File I/O
FILE* VL_CVT_I_FP(IData lhs) {
return VerilatedImp::fdToFp(lhs);
}
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) { void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
// See also VL_DATA_TO_STRING_NW // See also VL_DATA_TO_STRING_NW
int lsb=obits-1; int lsb=obits-1;
@@ -655,8 +658,8 @@ void _VL_STRING_TO_VINT(int obits, void* destp, int srclen, const char* srcp) {
for (; i<bytes; i++) { *op++ = 0; } for (; i<bytes; i++) { *op++ = 0; }
} }
IData VL_FGETS_IXQ(int obits, void* destp, QData fpq) { IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
FILE* fp = VL_CVT_Q_FP(fpq); FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0; if (VL_UNLIKELY(!fp)) return 0;
// The string needs to be padded with 0's in unused spaces in front of // The string needs to be padded with 0's in unused spaces in front of
@@ -692,7 +695,13 @@ QData VL_FOPEN_WI(int fnwords, WDataInP filenamep, IData mode) {
_VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep); _VL_VINT_TO_STRING(fnwords*VL_WORDSIZE, filenamez, filenamep);
char modez[5]; char modez[5];
_VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode); _VL_VINT_TO_STRING(VL_WORDSIZE, modez, &mode);
return VL_CVT_FP_Q(fopen(filenamez,modez)); return VerilatedImp::fdNew(fopen(filenamez,modez));
}
void VL_FCLOSE_I(IData fdi) {
FILE* fp = VL_CVT_I_FP(fdi);
if (VL_UNLIKELY(!fp)) return;
fclose(fp);
VerilatedImp::fdDelete(fdi);
} }
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) { void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
@@ -726,8 +735,8 @@ void VL_WRITEF(const char* formatp, ...) {
VL_PRINTF("%s", output.c_str()); VL_PRINTF("%s", output.c_str());
} }
void VL_FWRITEF(QData fpq, const char* formatp, ...) { void VL_FWRITEF(IData fpi, const char* formatp, ...) {
FILE* fp = VL_CVT_Q_FP(fpq); FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return; if (VL_UNLIKELY(!fp)) return;
va_list ap; va_list ap;
@@ -739,8 +748,8 @@ void VL_FWRITEF(QData fpq, const char* formatp, ...) {
fputs(output.c_str(), fp); fputs(output.c_str(), fp);
} }
IData VL_FSCANF_IX(QData fpq, const char* formatp, ...) { IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) {
FILE* fp = VL_CVT_Q_FP(fpq); FILE* fp = VL_CVT_I_FP(fpi);
if (VL_UNLIKELY(!fp)) return 0; if (VL_UNLIKELY(!fp)) return 0;
va_list ap; va_list ap;
+21 -20
View File
@@ -321,12 +321,14 @@ extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus); extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
/// File I/O /// File I/O
extern IData VL_FGETS_IXQ(int obits, void* destp, QData fpq); extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode); extern QData VL_FOPEN_WI(int fnwords, WDataInP ofilename, IData mode);
extern QData VL_FOPEN_QI(QData ofilename, IData mode); extern QData VL_FOPEN_QI(QData ofilename, IData mode);
inline QData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); } inline QData VL_FOPEN_II(IData ofilename, IData mode) { return VL_FOPEN_QI(ofilename,mode); }
extern void VL_FCLOSE_I(IData fdi);
extern void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords, extern void VL_READMEM_W(bool hex, int width, int depth, int array_lsb, int fnwords,
WDataInP ofilename, void* memp, IData start, IData end); WDataInP ofilename, void* memp, IData start, IData end);
extern void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords, extern void VL_READMEM_Q(bool hex, int width, int depth, int array_lsb, int fnwords,
@@ -336,9 +338,9 @@ inline void VL_READMEM_I(bool hex, int width, int depth, int array_lsb, int fnwo
VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); } VL_READMEM_Q(hex, width,depth,array_lsb,fnwords, ofilename,memp,start,end); }
extern void VL_WRITEF(const char* formatp, ...); extern void VL_WRITEF(const char* formatp, ...);
extern void VL_FWRITEF(QData fpq, const char* formatp, ...); extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
extern IData VL_FSCANF_IX(QData fpq, const char* formatp, ...); extern IData VL_FSCANF_IX(IData fpi, const char* formatp, ...);
extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...); extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...); extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...); extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
@@ -364,13 +366,12 @@ extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) )) #define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
#define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) ) #define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) )
/// Return FILE* from IData
extern FILE* VL_CVT_I_FP(IData lhs);
// Use a union to avoid cast-to-different-size warnings // Use a union to avoid cast-to-different-size warnings
/// Return FILE* from QData
static inline FILE* VL_CVT_Q_FP(QData lhs) { union { FILE* fp; QData q; } u; u.q=lhs; return u.fp; }
/// Return void* from QData /// Return void* from QData
static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; } static inline void* VL_CVT_Q_VP(QData lhs) { union { void* fp; QData q; } u; u.q=lhs; return u.fp; }
/// Return QData from FILE*
static inline QData VL_CVT_FP_Q(FILE* fp) { union { FILE* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
/// Return QData from void* /// 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; } static inline QData VL_CVT_VP_Q(void* fp) { union { void* fp; QData q; } u; u.q=0; u.fp=fp; return u.q; }
@@ -947,11 +948,11 @@ static inline WDataOutP VL_SUB_W(int words, WDataOutP owp,WDataInP lwp,WDataInP
// Optimization bug in GCC 2.96 and presumably all-pre GCC 3 versions need this workaround, // Optimization bug in GCC 2.96 and presumably all-pre GCC 3 versions need this workaround,
// we can't just // we can't just
//# define VL_UNARYMIN_I(data) (-(data)) //# define VL_NEGATE_I(data) (-(data))
static inline IData VL_UNARYMIN_I(IData data) { return -data; } static inline IData VL_NEGATE_I(IData data) { return -data; }
static inline QData VL_UNARYMIN_Q(QData data) { return -data; } static inline QData VL_NEGATE_Q(QData data) { return -data; }
static inline WDataOutP VL_UNARYMIN_W(int words, WDataOutP owp,WDataInP lwp){ static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp,WDataInP lwp){
QData carry = 0; QData carry = 0;
for (int i=0; i<words; i++) { for (int i=0; i<words; i++) {
carry = carry + (QData)(IData)(~lwp[i]); carry = carry + (QData)(IData)(~lwp[i]);
@@ -998,18 +999,18 @@ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lw
IData lneg = VL_SIGN_I(lbits,lwp[words-1]); IData lneg = VL_SIGN_I(lbits,lwp[words-1]);
if (lneg) { // Negate lhs if (lneg) { // Negate lhs
lwusp = lwstore; lwusp = lwstore;
VL_UNARYMIN_W(words, lwstore, lwp); VL_NEGATE_W(words, lwstore, lwp);
lwstore[words-1] &= VL_MASK_I(lbits); // Clean it lwstore[words-1] &= VL_MASK_I(lbits); // Clean it
} }
IData rneg = VL_SIGN_I(lbits,rwp[words-1]); IData rneg = VL_SIGN_I(lbits,rwp[words-1]);
if (rneg) { // Negate rhs if (rneg) { // Negate rhs
rwusp = rwstore; rwusp = rwstore;
VL_UNARYMIN_W(words, rwstore, rwp); VL_NEGATE_W(words, rwstore, rwp);
rwstore[words-1] &= VL_MASK_I(lbits); // Clean it rwstore[words-1] &= VL_MASK_I(lbits); // Clean it
} }
VL_MUL_W(words,owp,lwusp,rwusp); VL_MUL_W(words,owp,lwusp,rwusp);
owp[words-1] &= VL_MASK_I(lbits); // Clean. Note it's ok for the multiply to overflow into the sign bit owp[words-1] &= VL_MASK_I(lbits); // Clean. Note it's ok for the multiply to overflow into the sign bit
if ((lneg ^ rneg) & 1) { // Negate output (not using UNARYMIN, as owp==lwp) if ((lneg ^ rneg) & 1) { // Negate output (not using NEGATE, as owp==lwp)
QData carry = 0; QData carry = 0;
for (int i=0; i<words; i++) { for (int i=0; i<words; i++) {
carry = carry + (QData)(IData)(~owp[i]); carry = carry + (QData)(IData)(~owp[i]);
@@ -1056,12 +1057,12 @@ static inline WDataOutP VL_DIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDataI
IData rwstore[VL_MULS_MAX_WORDS]; IData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp; WDataInP ltup = lwp;
WDataInP rtup = rwp; WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); } if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); } if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
if ((lsign && !rsign) || (!lsign && rsign)) { if ((lsign && !rsign) || (!lsign && rsign)) {
IData qNoSign[VL_MULS_MAX_WORDS]; IData qNoSign[VL_MULS_MAX_WORDS];
VL_DIV_WWW(lbits,qNoSign,ltup,rtup); VL_DIV_WWW(lbits,qNoSign,ltup,rtup);
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign)); _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), owp, qNoSign));
return owp; return owp;
} else { } else {
return VL_DIV_WWW(lbits,owp,ltup,rtup); return VL_DIV_WWW(lbits,owp,ltup,rtup);
@@ -1075,12 +1076,12 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDa
IData rwstore[VL_MULS_MAX_WORDS]; IData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp; WDataInP ltup = lwp;
WDataInP rtup = rwp; WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); } if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), lwstore, lwp)); }
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); } if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
if (lsign) { // Only dividend sign matters for modulus if (lsign) { // Only dividend sign matters for modulus
IData qNoSign[VL_MULS_MAX_WORDS]; IData qNoSign[VL_MULS_MAX_WORDS];
VL_MODDIV_WWW(lbits,qNoSign,ltup,rtup); VL_MODDIV_WWW(lbits,qNoSign,ltup,rtup);
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign)); _VL_CLEAN_INPLACE_W(lbits, VL_NEGATE_W(VL_WORDS_I(lbits), owp, qNoSign));
return owp; return owp;
} else { } else {
return VL_MODDIV_WWW(lbits,owp,ltup,rtup); return VL_MODDIV_WWW(lbits,owp,ltup,rtup);
+2 -6
View File
@@ -27,11 +27,7 @@
`define coverage_block_off `define coverage_block_off
`endif `endif
// Hide file descriptor difference // Hide file descriptor difference - deprecated - for older versions
`ifdef verilator `define verilator_file_descriptor integer
`define verilator_file_descriptor reg [63:0]
`else
`define verilator_file_descriptor integer
`endif
`endif // guard `endif // guard
+39 -1
View File
@@ -35,6 +35,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
#include <deque>
#include <string> #include <string>
class VerilatedScope; class VerilatedScope;
@@ -62,9 +63,18 @@ class VerilatedImp {
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number> ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
int m_exportNext; ///< Next export funcnum int m_exportNext; ///< Next export funcnum
// File I/O
vector<FILE*> m_fdps; ///< File descriptors
deque<IData> m_fdFree; ///< List of free descriptors (SLOW - FOPEN/CLOSE only)
public: // But only for verilated*.cpp public: // But only for verilated*.cpp
// CONSTRUCTORS // CONSTRUCTORS
VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {} VerilatedImp() : m_argVecLoaded(false), m_exportNext(0) {
m_fdps.resize(3);
m_fdps[0] = stdin;
m_fdps[1] = stdout;
m_fdps[2] = stderr;
}
~VerilatedImp() {} ~VerilatedImp() {}
// METHODS - arguments // METHODS - arguments
@@ -184,6 +194,34 @@ public: // But only for verilated*.cpp
} }
// We don't free up m_exportMap until the end, because we can't be sure // We don't free up m_exportMap until the end, because we can't be sure
// what other models are using the assigned funcnum's. // what other models are using the assigned funcnum's.
public: // But only for verilated*.cpp
// METHODS - file IO
static IData fdNew(FILE* fp) {
if (VL_UNLIKELY(!fp)) return 0;
// Bit 31 indicates it's a descriptor not a MCD
if (s_s.m_fdFree.empty()) {
// Need to create more space in m_fdps and m_fdFree
size_t start = s_s.m_fdps.size();
s_s.m_fdps.resize(start*2);
for (size_t i=start; i<start*2; i++) s_s.m_fdFree.push_back((IData)i);
}
IData idx = s_s.m_fdFree.back(); s_s.m_fdFree.pop_back();
s_s.m_fdps[idx] = fp;
return (idx | (1UL<<31)); // bit 31 indicates not MCD
}
static void fdDelete(IData fdi) {
IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return;
if (VL_UNLIKELY(!s_s.m_fdps[idx])) return; // Already free
s_s.m_fdps[idx] = NULL;
s_s.m_fdFree.push_back(idx);
}
static inline FILE* fdToFp(IData fdi) {
IData idx = VL_MASK_I(31) & fdi;
if (VL_UNLIKELY(!(fdi & (1ULL<<31)) || idx >= s_s.m_fdps.size())) return NULL;
return s_s.m_fdps[idx];
}
}; };
#endif // Guard #endif // Guard
+1 -1
View File
@@ -256,7 +256,7 @@ sub gentree {
'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; }, 'TRACE' => sub { p "TRACE what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; }, 'UCFUNC' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ")"; },
'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; }, 'UCSTMT' => sub { p '$c(';p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p ");";nl; },
'UNARYMIN' => sub { p " -";p1; }, 'NEGATE' => sub { p " -";p1; },
'VAR' => sub { p_var(); }, 'VAR' => sub { p_var(); },
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; }, 'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
'VARREF' => sub { a1; }, 'VARREF' => sub { a1; },
+11 -6
View File
@@ -209,7 +209,7 @@ class AstBasicDTypeKwd {
public: public:
enum en { enum en {
BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT, BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT,
REAL, REALTIME, SHORTINT, SHORTREAL, TIME, REAL, SHORTINT, SHORTREAL, TIME,
// Closer to a class type, but limited usage // Closer to a class type, but limited usage
STRING, STRING,
// Internal types for mid-steps // Internal types for mid-steps
@@ -221,7 +221,7 @@ public:
const char* ascii() const { const char* ascii() const {
static const char* names[] = { static const char* names[] = {
"bit", "byte", "chandle", "int", "integer", "logic", "longint", "bit", "byte", "chandle", "int", "integer", "logic", "longint",
"real", "realtime", "shortint", "shortreal", "time", "real", "shortint", "shortreal", "time",
"string", "string",
"VerilatedScope*", "char*", "VerilatedScope*", "char*",
"LOGIC_IMPLICIT" "LOGIC_IMPLICIT"
@@ -231,7 +231,7 @@ public:
const char* dpiType() const { const char* dpiType() const {
static const char* names[] = { static const char* names[] = {
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long", "unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
"double", "double", "short int", "float", "long long", "double", "short int", "float", "long long",
"const char*", "const char*",
"dpiScope", "const char*", "dpiScope", "const char*",
"" ""
@@ -251,6 +251,8 @@ public:
case INTEGER: return 32; case INTEGER: return 32;
case LOGIC: return 1; case LOGIC: return 1;
case LONGINT: return 64; case LONGINT: return 64;
case REAL: return 64;
case SHORTREAL: return 32;
case SHORTINT: return 16; case SHORTINT: return 16;
case TIME: return 64; case TIME: return 64;
case STRING: return 64; // Just the pointer, for today case STRING: return 64; // Just the pointer, for today
@@ -265,7 +267,7 @@ public:
} }
bool isZeroInit() const { // Otherwise initializes to X 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 return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT
|| m_e==STRING); || m_e==STRING || m_e==REAL || m_e==SHORTREAL);
} }
bool isSloppy() const { // Don't be as anal about width warnings bool isSloppy() const { // Don't be as anal about width warnings
return !(m_e==LOGIC || m_e==BIT); return !(m_e==LOGIC || m_e==BIT);
@@ -274,10 +276,13 @@ public:
return (m_e==LOGIC || m_e==BIT); return (m_e==LOGIC || m_e==BIT);
} }
bool isDpiUnsupported() const { bool isDpiUnsupported() const {
return (m_e==LOGIC || m_e==TIME || m_e==REALTIME); return (m_e==LOGIC || m_e==TIME);
} }
bool isOpaque() const { // IE not a simple number we can bit optimize bool isOpaque() const { // IE not a simple number we can bit optimize
return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR); return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==REAL || m_e==SHORTREAL);
}
bool isReal() const {
return (m_e==REAL);
} }
}; };
inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); } inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
+8 -3
View File
@@ -113,6 +113,10 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
arg += "const char*"; arg += "const char*";
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) { } else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
arg += "const VerilatedScope*"; arg += "const VerilatedScope*";
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::REAL) {
arg += "double";
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SHORTREAL) {
arg += "float";
} else if (strtype) { } else if (strtype) {
if (isInOnly()) arg += "const "; if (isInOnly()) arg += "const ";
arg += "string"; arg += "string";
@@ -185,7 +189,7 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
} else if (isWide()) { } else if (isWide()) {
arg += "uint32_t"; // []'s added later arg += "uint32_t"; // []'s added later
} else { } else {
arg += "uint64_t"; arg += "vluint64_t";
} }
if (isWide()) { if (isWide()) {
if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead"); if (forReturn) v3error("Unsupported: Public functions with >64 bit outputs; make an output of a public task instead");
@@ -237,7 +241,7 @@ string AstVar::scType() const {
return "uint32_t"; return "uint32_t";
} }
} else { } else {
return "uint64_t"; return "vluint64_t";
} }
} }
@@ -608,7 +612,8 @@ void AstVar::dump(ostream& str) {
else if (isInput()) str<<" [I]"; else if (isInput()) str<<" [I]";
else if (isOutput()) str<<" [O]"; else if (isOutput()) str<<" [O]";
} }
if (isUsedClock()) str<<" [C]"; if (isConst()) str<<" [CONST]";
if (isUsedClock()) str<<" [CLK]";
if (isSigPublic()) str<<" [P]"; if (isSigPublic()) str<<" [P]";
if (isUsedLoopIdx()) str<<" [LOOP]"; if (isUsedLoopIdx()) str<<" [LOOP]";
if (attrClockEn()) str<<" [aCLKEN]"; if (attrClockEn()) str<<" [aCLKEN]";
+27 -8
View File
@@ -300,6 +300,25 @@ public:
void implicit(bool flag) { m_implicit = flag; } void implicit(bool flag) { m_implicit = flag; }
}; };
struct AstConstDType : public AstNodeDType {
// const data type, ie "const some_dtype var_name [2:0]"
// ConstDType are removed in V3LinkLValue and become AstVar::isConst.
// When more generic types are supported AstConstDType will be propagated further.
AstConstDType(FileLine* fl, AstNodeDType* dtypep)
: AstNodeDType(fl) {
setOp1p(dtypep);
widthSignedFrom(dtypep);
}
ASTNODE_NODE_FUNCS(ConstDType, CONSTDTYPE)
AstNodeDType* dtypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
void dtypep(AstNodeDType* nodep) { setOp1p(nodep); }
// METHODS
virtual AstBasicDType* basicp() const { return dtypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return dtypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return dtypep()->widthTotalBytes(); }
};
struct AstRefDType : public AstNodeDType { struct AstRefDType : public AstNodeDType {
private: private:
AstTypedef* m_defp; AstTypedef* m_defp;
@@ -677,7 +696,7 @@ public:
bool isToggleCoverable() const { return ((isIO() || isSignal()) bool isToggleCoverable() const { return ((isIO() || isSignal())
&& (isIO() || isBitLogic()) && (isIO() || isBitLogic())
// Wrapper would otherwise duplicate wrapped module's coverage // Wrapper would otherwise duplicate wrapped module's coverage
&& !isSc() && !isPrimaryIO()); } && !isSc() && !isPrimaryIO() && !isConst()); }
bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); } bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); }
bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); } bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); }
bool isPure() const { return (varType()==AstVarType::XTEMP); } bool isPure() const { return (varType()==AstVarType::XTEMP); }
@@ -2453,13 +2472,13 @@ struct AstUCFunc : public AstNodeMath {
//====================================================================== //======================================================================
// Unary ops // Unary ops
struct AstUnaryMin : public AstNodeUniop { struct AstNegate : public AstNodeUniop {
AstUnaryMin(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) { AstNegate(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
if (lhsp) widthSignedFrom(lhsp); } if (lhsp) widthSignedFrom(lhsp); }
ASTNODE_NODE_FUNCS(UnaryMin, UNARYMIN) ASTNODE_NODE_FUNCS(Negate, NEGATE)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opUnaryMin(lhs); } virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegate(lhs); }
virtual string emitVerilog() { return "%f(- %l)"; } virtual string emitVerilog() { return "%f(- %l)"; }
virtual string emitC() { return "VL_UNARYMIN_%lq(%lW, %P, %li)"; } virtual string emitC() { return "VL_NEGATE_%lq(%lW, %P, %li)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;} virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return false;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersLhs() {return true;}
}; };
@@ -2697,7 +2716,7 @@ struct AstFEof : public AstNodeUniop {
ASTNODE_NODE_FUNCS(FEof, FEOF) ASTNODE_NODE_FUNCS(FEof, FEOF)
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
virtual string emitVerilog() { return "%f$feof(%l)"; } virtual string emitVerilog() { return "%f$feof(%l)"; }
virtual string emitC() { return "(%li ? feof(VL_CVT_Q_FP(%li)) : true)"; } virtual string emitC() { return "(%li ? feof(VL_CVT_I_FP(%li)) : true)"; }
virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;} virtual bool cleanOut() {return true;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return widthInstrs()*16; } virtual int instrCount() const { return widthInstrs()*16; }
@@ -2710,7 +2729,7 @@ struct AstFGetC : public AstNodeUniop {
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; } virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
virtual string emitVerilog() { return "%f$fgetc(%l)"; } virtual string emitVerilog() { return "%f$fgetc(%l)"; }
// Non-existent filehandle returns EOF // Non-existent filehandle returns EOF
virtual string emitC() { return "(%li ? fgetc(VL_CVT_Q_FP(%li)) : -1)"; } virtual string emitC() { return "(%li ? fgetc(VL_CVT_I_FP(%li)) : -1)"; }
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;} virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersLhs() {return false;}
virtual int instrCount() const { return widthInstrs()*64; } virtual int instrCount() const { return widthInstrs()*64; }
+1 -1
View File
@@ -135,7 +135,7 @@ private:
insureLower32Cast(nodep); insureLower32Cast(nodep);
nodep->user1(1); nodep->user1(1);
} }
virtual void visit(AstUnaryMin* nodep, AstNUser*) { virtual void visit(AstNegate* nodep, AstNUser*) {
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
nodep->user1(nodep->lhsp()->user1()); nodep->user1(nodep->lhsp()->user1());
if (nodep->lhsp()->widthMin()==1) { if (nodep->lhsp()->widthMin()==1) {
+2 -2
View File
@@ -1519,7 +1519,7 @@ private:
if (!inPct && ch=='%') { if (!inPct && ch=='%') {
inPct = true; inPct = true;
fmt = ch; fmt = ch;
} else if (inPct && isdigit(ch)) { } else if (inPct && (isdigit(ch) || ch=='.')) {
fmt += ch; fmt += ch;
} else if (inPct) { } else if (inPct) {
inPct = false; inPct = false;
@@ -1664,7 +1664,7 @@ private:
TREEOP ("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZero(nodep)"); TREEOP ("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
TREEOP ("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)"); TREEOP ("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
TREEOP ("AstXnor {$lhsp.isZero, $rhsp}", "AstNot{$rhsp}"); TREEOP ("AstXnor {$lhsp.isZero, $rhsp}", "AstNot{$rhsp}");
TREEOP ("AstSub {$lhsp.isZero, $rhsp}", "AstUnaryMin{$rhsp}"); TREEOP ("AstSub {$lhsp.isZero, $rhsp}", "AstNegate{$rhsp}");
TREEOP ("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)"); TREEOP ("AstAdd {$lhsp, $rhsp.isZero}", "replaceWLhs(nodep)");
TREEOP ("AstAnd {$lhsp, $rhsp.isZero}", "replaceZero(nodep)"); TREEOP ("AstAnd {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
TREEOP ("AstLogAnd{$lhsp, $rhsp.isZero}", "replaceZero(nodep)"); TREEOP ("AstLogAnd{$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
+4 -6
View File
@@ -344,13 +344,11 @@ public:
puts(");\n"); puts(");\n");
} }
virtual void visit(AstFClose* nodep, AstNUser*) { virtual void visit(AstFClose* nodep, AstNUser*) {
puts("if ("); puts("VL_FCLOSE_I(");
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(") { fclose (VL_CVT_Q_FP("); puts("); ");
nodep->filep()->iterateAndNext(*this);
puts(")); ");
nodep->filep()->iterateAndNext(*this); // For saftey, so user doesn't later WRITE with it. nodep->filep()->iterateAndNext(*this); // For saftey, so user doesn't later WRITE with it.
puts("=0; }\n"); puts("=0;\n");
} }
virtual void visit(AstFFlush* nodep, AstNUser*) { virtual void visit(AstFFlush* nodep, AstNUser*) {
if (!nodep->filep()) { if (!nodep->filep()) {
@@ -358,7 +356,7 @@ public:
} else { } else {
puts("if ("); puts("if (");
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(") { fflush (VL_CVT_Q_FP("); puts(") { fflush (VL_CVT_I_FP(");
nodep->filep()->iterateAndNext(*this); nodep->filep()->iterateAndNext(*this);
puts(")); }\n"); puts(")); }\n");
} }
+4
View File
@@ -483,6 +483,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
putfs(nodep,nodep->prettyName()); putfs(nodep,nodep->prettyName());
if (nodep->rangep()) { puts(" "); nodep->rangep()->iterateAndNext(*this); puts(" "); } if (nodep->rangep()) { puts(" "); nodep->rangep()->iterateAndNext(*this); puts(" "); }
} }
virtual void visit(AstConstDType* nodep, AstNUser*) {
putfs(nodep,"const ");
nodep->dtypep()->iterateAndNext(*this);
}
virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) { virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
if (nodep->dotted()!="") { putfs(nodep,nodep->dotted()); puts("."); puts(nodep->prettyName()); } if (nodep->dotted()!="") { putfs(nodep,nodep->dotted()); puts("."); puts(nodep->prettyName()); }
else { putfs(nodep,nodep->prettyName()); } else { putfs(nodep,nodep->prettyName()); }
+2 -3
View File
@@ -696,8 +696,7 @@ private:
int lhswidth = lhsp->widthMin(); int lhswidth = lhsp->widthMin();
if (lhswidth==1) { if (lhswidth==1) {
UINFO(8," REPLICATE(w1) "<<nodep<<endl); UINFO(8," REPLICATE(w1) "<<nodep<<endl);
newp = new AstUnaryMin (nodep->fileline(), newp = new AstNegate (nodep->fileline(), lhsp);
lhsp);
} else { } else {
UINFO(8," REPLICATE "<<nodep<<endl); UINFO(8," REPLICATE "<<nodep<<endl);
AstConst* constp = nodep->rhsp()->castConst(); AstConst* constp = nodep->rhsp()->castConst();
@@ -731,7 +730,7 @@ private:
for (int w=0; w<rhsp->widthWords(); w++) { for (int w=0; w<rhsp->widthWords(); w++) {
AstNode* newp; AstNode* newp;
if (lhswidth==1) { if (lhswidth==1) {
newp = new AstUnaryMin (nodep->fileline(), lhsp->cloneTree(true)); newp = new AstNegate (nodep->fileline(), lhsp->cloneTree(true));
newp->width(VL_WORDSIZE,VL_WORDSIZE); newp->width(VL_WORDSIZE,VL_WORDSIZE);
} else { } else {
newp = newAstWordSelClone (lhsp, w); newp = newAstWordSelClone (lhsp, w);
+11
View File
@@ -45,6 +45,7 @@ private:
// STATE // STATE
bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments bool m_setRefLvalue; // Set VarRefs to lvalues for pin assignments
AstInitial* m_initialp; // In an initial block
AstNodeFTask* m_ftaskp; // Function or task we're inside AstNodeFTask* m_ftaskp; // Function or task we're inside
// METHODS // METHODS
@@ -67,6 +68,10 @@ private:
nodep->v3error("Assigning to input variable: "<<nodep->prettyName()); nodep->v3error("Assigning to input variable: "<<nodep->prettyName());
} }
} }
if (nodep->lvalue() && nodep->varp()->isConst()
&& !m_initialp) { // Too loose, but need to allow our generated first assignment
nodep->v3error("Assigning to const variable: "<<nodep->prettyName());
}
} }
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }
@@ -222,6 +227,11 @@ private:
} }
m_setRefLvalue = last_setRefLvalue; m_setRefLvalue = last_setRefLvalue;
} }
virtual void visit(AstInitial* nodep, AstNUser*) {
m_initialp = nodep;
nodep->iterateChildren(*this);
m_initialp = NULL;
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) { virtual void visit(AstNodeFTask* nodep, AstNUser*) {
m_ftaskp = nodep; m_ftaskp = nodep;
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
@@ -259,6 +269,7 @@ public:
LinkLValueVisitor(AstNode* nodep, bool start) { LinkLValueVisitor(AstNode* nodep, bool start) {
m_setRefLvalue = start; m_setRefLvalue = start;
m_ftaskp = NULL; m_ftaskp = NULL;
m_initialp = NULL;
nodep->accept(*this); nodep->accept(*this);
} }
virtual ~LinkLValueVisitor() {} virtual ~LinkLValueVisitor() {}
+3
View File
@@ -95,6 +95,9 @@ private:
nodep->dtypeSkipRefp()->castArrayDType())) { nodep->dtypeSkipRefp()->castArrayDType())) {
nodep->v3error("Unsupported: Inputs and outputs must be simple data types"); nodep->v3error("Unsupported: Inputs and outputs must be simple data types");
} }
if (nodep->dtypeSkipRefp()->castConstDType()) {
nodep->isConst(true);
}
if (m_ftaskp) nodep->funcLocal(true); if (m_ftaskp) nodep->funcLocal(true);
if (nodep->isSigModPublic()) { if (nodep->isSigModPublic()) {
nodep->sigModPublic(false); // We're done with this attribute nodep->sigModPublic(false); // We're done with this attribute
+12 -12
View File
@@ -1079,12 +1079,12 @@ V3Number& V3Number::opAbsS (const V3Number& lhs) {
// op i, L(lhs) bit return // op i, L(lhs) bit return
if (lhs.isFourState()) return setAllBitsX(); if (lhs.isFourState()) return setAllBitsX();
if (lhs.isNegative()) { if (lhs.isNegative()) {
return opUnaryMin(lhs); return opNegate(lhs);
} else { } else {
return opAssign(lhs); return opAssign(lhs);
} }
} }
V3Number& V3Number::opUnaryMin (const V3Number& lhs) { V3Number& V3Number::opNegate (const V3Number& lhs) {
// op i, L(lhs) bit return // op i, L(lhs) bit return
if (lhs.isFourState()) return setAllBitsX(); if (lhs.isFourState()) return setAllBitsX();
V3Number notlhs (lhs.m_fileline, width()); V3Number notlhs (lhs.m_fileline, width());
@@ -1112,7 +1112,7 @@ V3Number& V3Number::opSub (const V3Number& lhs, const V3Number& rhs) {
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return // i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
V3Number negrhs (rhs.m_fileline, rhs.width()); V3Number negrhs (rhs.m_fileline, rhs.width());
negrhs.opUnaryMin(rhs); negrhs.opNegate(rhs);
return opAdd(lhs, negrhs); return opAdd(lhs, negrhs);
} }
V3Number& V3Number::opMul (const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opMul (const V3Number& lhs, const V3Number& rhs) {
@@ -1140,12 +1140,12 @@ V3Number& V3Number::opMul (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opMulS (const V3Number& lhs, const V3Number& rhs) { V3Number& V3Number::opMulS (const V3Number& lhs, const V3Number& rhs) {
// Signed multiply // Signed multiply
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs); V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs); V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
V3Number qNoSign = opMul(lhsNoSign,rhsNoSign); V3Number qNoSign = opMul(lhsNoSign,rhsNoSign);
if ((lhs.isNegative() && !rhs.isNegative()) if ((lhs.isNegative() && !rhs.isNegative())
|| (!lhs.isNegative() && rhs.isNegative())) { || (!lhs.isNegative() && rhs.isNegative())) {
opUnaryMin(qNoSign); opNegate(qNoSign);
} else { } else {
opAssign(qNoSign); opAssign(qNoSign);
} }
@@ -1169,13 +1169,13 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl); //UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX(); if (rhs.isEqZero()) return setAllBitsX();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs); V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs); V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign); V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
//UINFO(9, " >divs-mid "<<lhs<<" "<<rhs<<" "<<qNoSign<<endl); //UINFO(9, " >divs-mid "<<lhs<<" "<<rhs<<" "<<qNoSign<<endl);
if ((lhs.isNegative() && !rhs.isNegative()) if ((lhs.isNegative() && !rhs.isNegative())
|| (!lhs.isNegative() && rhs.isNegative())) { || (!lhs.isNegative() && rhs.isNegative())) {
opUnaryMin(qNoSign); opNegate(qNoSign);
} else { } else {
opAssign(qNoSign); opAssign(qNoSign);
} }
@@ -1198,11 +1198,11 @@ V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
// Signed moddiv // Signed moddiv
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX(); if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX(); if (rhs.isEqZero()) return setAllBitsX();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs); V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs); V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign); V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign);
if (lhs.isNegative()) { // Just lhs' sign (*DIFFERENT FROM PERL, which uses rhs sign*) if (lhs.isNegative()) { // Just lhs' sign (*DIFFERENT FROM PERL, which uses rhs sign*)
opUnaryMin(qNoSign); opNegate(qNoSign);
} else { } else {
opAssign(qNoSign); opAssign(qNoSign);
} }
+1 -1
View File
@@ -203,7 +203,7 @@ public:
V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs); V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs);
V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs); V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs);
V3Number& opAbsS (const V3Number& lhs); V3Number& opAbsS (const V3Number& lhs);
V3Number& opUnaryMin(const V3Number& lhs); V3Number& opNegate (const V3Number& lhs);
V3Number& opAdd (const V3Number& lhs, const V3Number& rhs); V3Number& opAdd (const V3Number& lhs, const V3Number& rhs);
V3Number& opSub (const V3Number& lhs, const V3Number& rhs); V3Number& opSub (const V3Number& lhs, const V3Number& rhs);
V3Number& opMul (const V3Number& lhs, const V3Number& rhs); V3Number& opMul (const V3Number& lhs, const V3Number& rhs);
+3 -3
View File
@@ -51,7 +51,7 @@ void test(string lhss, string op, string rhss, string exps) {
else if (op=="repl") gotnum.opRepl (lhnum,rhnum); else if (op=="repl") gotnum.opRepl (lhnum,rhnum);
else if (op=="~") gotnum.opNot (lhnum); else if (op=="~") gotnum.opNot (lhnum);
else if (op=="!") gotnum.opLogNot (lhnum); else if (op=="!") gotnum.opLogNot (lhnum);
else if (op=="unaryMin") gotnum.opUnaryMin (lhnum); else if (op=="negate") gotnum.opNegate (lhnum);
else if (op=="+") gotnum.opAdd (lhnum,rhnum); else if (op=="+") gotnum.opAdd (lhnum,rhnum);
else if (op=="-") gotnum.opSub (lhnum,rhnum); else if (op=="-") gotnum.opSub (lhnum,rhnum);
else if (op=="*") gotnum.opMul (lhnum,rhnum); else if (op=="*") gotnum.opMul (lhnum,rhnum);
@@ -96,8 +96,8 @@ int main() {
test("32'b0x","|","32'b10","32'b1x"); test("32'b0x","|","32'b10","32'b1x");
test("32'b10","&","32'b11","32'b10"); test("32'b10","&","32'b11","32'b10");
test("32'b10","+","32'b10","32'b100"); test("32'b10","+","32'b10","32'b100");
test("3'b000","unaryMin","","3'b000"); test("3'b000","negate","","3'b000");
test("3'b001","unaryMin","","3'b111"); test("3'b001","negate","","3'b111");
test("32'b11","-","32'b001","32'b10"); test("32'b11","-","32'b001","32'b10");
test("3'b000","-","3'b111","3'b001"); test("3'b000","-","3'b111","3'b001");
test("3'b000","-","3'b000","3'b000"); test("3'b000","-","3'b000","3'b000");
+3
View File
@@ -393,6 +393,9 @@ void V3PreProcImp::comment(const string& text) {
} else if (0==(strncmp(cp,"cadence",strlen("cadence")))) { } else if (0==(strncmp(cp,"cadence",strlen("cadence")))) {
cp+=strlen("cadence"); cp+=strlen("cadence");
synth = true; synth = true;
} else if (0==(strncmp(cp,"pragma",strlen("pragma")))) {
cp+=strlen("pragma");
synth = true;
} else if (0==(strncmp(cp,"ambit synthesis",strlen("ambit synthesis")))) { } else if (0==(strncmp(cp,"ambit synthesis",strlen("ambit synthesis")))) {
cp+=strlen("ambit synthesis"); cp+=strlen("ambit synthesis");
synth = true; synth = true;
+6 -6
View File
@@ -208,12 +208,12 @@ private:
// Then over shifting gives the sign bit, not all zeros // Then over shifting gives the sign bit, not all zeros
// Note *NOT* clean output -- just like normal shift! // Note *NOT* clean output -- just like normal shift!
// Create equivalent of VL_SIGNONES_(node_width) // Create equivalent of VL_SIGNONES_(node_width)
constzerop = new AstUnaryMin (nodep->fileline(), constzerop = new AstNegate (nodep->fileline(),
new AstShiftR(nodep->fileline(), new AstShiftR(nodep->fileline(),
nodep->lhsp()->cloneTree(false), nodep->lhsp()->cloneTree(false),
new AstConst(nodep->fileline(), new AstConst(nodep->fileline(),
nodep->widthMin()-1), nodep->widthMin()-1),
nodep->width())); nodep->width()));
} else { } else {
V3Number zeronum (nodep->fileline(), nodep->width(), 0); V3Number zeronum (nodep->fileline(), nodep->width(), 0);
constzerop = new AstConst(nodep->fileline(), zeronum); constzerop = new AstConst(nodep->fileline(), zeronum);
+14 -13
View File
@@ -48,7 +48,6 @@ class SignedVisitor : public AstNVisitor {
private: private:
// NODE STATE/TYPES // NODE STATE/TYPES
// STATE // STATE
int m_taskDepth; // Recursion check
bool m_paramsOnly; // Computing parameter value; limit operation bool m_paramsOnly; // Computing parameter value; limit operation
// METHODS - special type detection // METHODS - special type detection
@@ -62,8 +61,8 @@ private:
// VISITORS // VISITORS
//======== //========
// Signed: Output explicit by user, Lhs either // Signed: Output explicit by user, Lhs either
virtual void visit(AstSigned* nodep, AstNUser*) { signed_Os_Ix(nodep); }
virtual void visit(AstUnsigned* nodep, AstNUser*) { signed_Ou_Ix(nodep); } 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 // Signed: Output unsigned, Operands either
@@ -121,7 +120,7 @@ private:
//======= //=======
// Signed: Output signed iff LHS signed; unary operator // Signed: Output signed iff LHS signed; unary operator
virtual void visit(AstNot* nodep, AstNUser*) { signed_Olhs(nodep); } virtual void visit(AstNot* nodep, AstNUser*) { signed_Olhs(nodep); }
virtual void visit(AstUnaryMin* 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(AstShiftL* nodep, AstNUser*) { signed_Olhs(nodep); }
virtual void visit(AstShiftR* nodep, AstNUser*) { signed_Olhs(nodep); } virtual void visit(AstShiftR* nodep, AstNUser*) { signed_Olhs(nodep); }
@@ -291,6 +290,18 @@ private:
// ShiftRS converts to ShiftR, but not vice-versa // ShiftRS converts to ShiftR, but not vice-versa
virtual void visit(AstShiftRS* nodep, AstNUser*) { checkReplace_Olhs(nodep); } 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) { void checkReplace_Ou_FlavLhsAndRhs(AstNodeBiop* nodep) {
// For compares, the output of the comparison is unsigned. // For compares, the output of the comparison is unsigned.
// However, we need the appropriate type of compare selected by RHS & LHS // However, we need the appropriate type of compare selected by RHS & LHS
@@ -336,15 +347,6 @@ private:
} }
} }
// 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);
}
// COMMON SCHEMES // COMMON SCHEMES
// Signed: Output signed, Lhs/Rhs/etc either // Signed: Output signed, Lhs/Rhs/etc either
void signed_Os_Ix(AstNode* nodep) { void signed_Os_Ix(AstNode* nodep) {
@@ -392,7 +394,6 @@ public:
// CONSTRUCTORS // CONSTRUCTORS
SignedVisitor(bool paramsOnly) { SignedVisitor(bool paramsOnly) {
m_paramsOnly = paramsOnly; m_paramsOnly = paramsOnly;
m_taskDepth = 0;
} }
virtual ~SignedVisitor() {} virtual ~SignedVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) { AstNode* mainAcceptEdit(AstNode* nodep) {
+348 -399
View File
@@ -57,6 +57,10 @@
#include "V3Const.h" #include "V3Const.h"
#include "V3Task.h" #include "V3Task.h"
// More code; this file was getting too large; see actions there
#define _V3WIDTH_CPP_
#include "V3WidthCommit.h"
//###################################################################### //######################################################################
// Width state, as a visitor of each AstNode // Width state, as a visitor of each AstNode
@@ -99,19 +103,16 @@ private:
// VISITORS // VISITORS
// Naming: width_{output size rule}_{lhs rule}_{rhs rule} // Naming: width_{output size rule}_{lhs rule}_{rhs rule}
// Widths: 1 bit out, lhs 1 bit // Widths: 1 bit out, lhs 1 bit
void width_O1_L1(AstNode* nodep, AstNUser* vup);
virtual void visit(AstLogNot* nodep, AstNUser* vup) { width_O1_L1(nodep,vup); } virtual void visit(AstLogNot* nodep, AstNUser* vup) { width_O1_L1(nodep,vup); }
virtual void visit(AstPslBool* nodep, AstNUser* vup) { width_O1_L1(nodep,vup); } virtual void visit(AstPslBool* nodep, AstNUser* vup) { width_O1_L1(nodep,vup); }
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit // Widths: 1 bit out, lhs 1 bit, rhs 1 bit
void width_O1_L1_R1(AstNode* nodep, AstNUser* vup);
virtual void visit(AstLogAnd* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); } virtual void visit(AstLogAnd* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
virtual void visit(AstLogOr* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); } virtual void visit(AstLogOr* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
virtual void visit(AstLogIf* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); } virtual void visit(AstLogIf* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
virtual void visit(AstLogIff* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); } virtual void visit(AstLogIff* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
// Widths: 1 bit out, Any width lhs // Widths: 1 bit out, Any width lhs
void width_O1_L(AstNode* nodep, AstNUser* vup);
virtual void visit(AstRedAnd* nodep, AstNUser* vup) { width_O1_L(nodep,vup); } virtual void visit(AstRedAnd* nodep, AstNUser* vup) { width_O1_L(nodep,vup); }
virtual void visit(AstRedOr* nodep, AstNUser* vup) { width_O1_L(nodep,vup); } virtual void visit(AstRedOr* nodep, AstNUser* vup) { width_O1_L(nodep,vup); }
virtual void visit(AstRedXnor* nodep, AstNUser* vup){ width_O1_L(nodep,vup); } virtual void visit(AstRedXnor* nodep, AstNUser* vup){ width_O1_L(nodep,vup); }
@@ -121,7 +122,6 @@ private:
virtual void visit(AstOneHot0* nodep,AstNUser* vup) { width_O1_L(nodep,vup); } virtual void visit(AstOneHot0* nodep,AstNUser* vup) { width_O1_L(nodep,vup); }
// Widths: 1 bit out, lhs width == rhs width // Widths: 1 bit out, lhs width == rhs width
void width_O1_L_Rlhs(AstNode* nodep, AstNUser* vup);
virtual void visit(AstEq* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstEq* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); }
virtual void visit(AstEqCase* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstEqCase* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); }
virtual void visit(AstEqWild* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstEqWild* nodep, AstNUser* vup) { width_O1_L_Rlhs(nodep,vup); }
@@ -138,7 +138,6 @@ private:
virtual void visit(AstNeqWild* nodep, AstNUser* vup){ width_O1_L_Rlhs(nodep,vup); } virtual void visit(AstNeqWild* nodep, AstNUser* vup){ width_O1_L_Rlhs(nodep,vup); }
// Widths: out width = lhs width = rhs width // Widths: out width = lhs width = rhs width
void width_Omax_L_Rlhs(AstNode* nodep, AstNUser* vup);
virtual void visit(AstAnd* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); } virtual void visit(AstAnd* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
virtual void visit(AstOr* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); } virtual void visit(AstOr* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
virtual void visit(AstXnor* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); } virtual void visit(AstXnor* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
@@ -156,23 +155,25 @@ private:
virtual void visit(AstMulS* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); } virtual void visit(AstMulS* nodep, AstNUser* vup) { width_Omax_L_Rlhs(nodep,vup); }
// Widths: out width = lhs width, but upper matters // Widths: out width = lhs width, but upper matters
void width_Olhs_L(AstNodeUniop* nodep, AstNUser* vup);
virtual void visit(AstNot* nodep, AstNUser* vup) { width_Olhs_L(nodep,vup); } virtual void visit(AstNot* nodep, AstNUser* vup) { width_Olhs_L(nodep,vup); }
virtual void visit(AstUnaryMin* nodep, AstNUser* vup) { width_Olhs_L(nodep,vup); } virtual void visit(AstNegate* nodep, AstNUser* vup) { width_Olhs_L(nodep,vup); }
// Widths: out width = lhs width, upper doesn't matter // Widths: out width = lhs width, upper doesn't matter
void width_Olhs_Lforce(AstNodeUniop* nodep, AstNUser* vup);
virtual void visit(AstSigned* nodep, AstNUser* vup) { width_Olhs_Lforce(nodep,vup); } virtual void visit(AstSigned* nodep, AstNUser* vup) { width_Olhs_Lforce(nodep,vup); }
virtual void visit(AstUnsigned* nodep, AstNUser* vup) { width_Olhs_Lforce(nodep,vup); } virtual void visit(AstUnsigned* nodep, AstNUser* vup) { width_Olhs_Lforce(nodep,vup); }
// Widths: Output width from lhs, rhs<33 bits // Widths: Output width from lhs, rhs<33 bits
void width_Olhs_L_R32(AstNode* nodep, AstNUser* vup);
virtual void visit(AstPow* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); } virtual void visit(AstPow* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
virtual void visit(AstPowS* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); } virtual void visit(AstPowS* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
virtual void visit(AstShiftL* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); } virtual void visit(AstShiftL* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
virtual void visit(AstShiftR* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); } virtual void visit(AstShiftR* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
virtual void visit(AstShiftRS* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); } virtual void visit(AstShiftRS* nodep, AstNUser* vup) { width_Olhs_L_R32(nodep,vup); }
// Widths: Constant, terminal
virtual void visit(AstTime* nodep, AstNUser*) { nodep->width(64,64); }
virtual void visit(AstTestPlusArgs* nodep, AstNUser*) { nodep->width(32,32); }
virtual void visit(AstScopeName* nodep, AstNUser* vup) { nodep->width(64,1); } // A pointer, but not that it matters
// Special cases. So many.... // Special cases. So many....
virtual void visit(AstNodeCond* nodep, AstNUser* vup) { virtual void visit(AstNodeCond* nodep, AstNUser* vup) {
// op=cond?expr1:expr2 is a Good large example of the propagation mess // op=cond?expr1:expr2 is a Good large example of the propagation mess
@@ -431,9 +432,6 @@ private:
nodep->width(32,32); // Says the spec nodep->width(32,32); // Says the spec
} }
} }
virtual void visit(AstTime* nodep, AstNUser*) {
nodep->width(64,64);
}
virtual void visit(AstUCFunc* nodep, AstNUser* vup) { virtual void visit(AstUCFunc* nodep, AstNUser* vup) {
// Give it the size the user wants. // Give it the size the user wants.
if (vup && vup->c()->prelim()) { if (vup && vup->c()->prelim()) {
@@ -470,9 +468,6 @@ private:
virtual void visit(AstText* nodep, AstNUser* vup) { virtual void visit(AstText* nodep, AstNUser* vup) {
// Only used in CStmts which don't care.... // Only used in CStmts which don't care....
} }
virtual void visit(AstScopeName* nodep, AstNUser* vup) {
nodep->width(64,1); // A pointer, but not that it matters
}
virtual void visit(AstArrayDType* nodep, AstNUser* vup) { virtual void visit(AstArrayDType* nodep, AstNUser* vup) {
// Lower datatype determines the width // Lower datatype determines the width
nodep->dtypep()->iterateAndNext(*this,vup); nodep->dtypep()->iterateAndNext(*this,vup);
@@ -488,6 +483,10 @@ private:
// else width in node is correct; it was set based on keyword().width() // else width in node is correct; it was set based on keyword().width()
// at construction time // at construction time
} }
virtual void visit(AstConstDType* nodep, AstNUser* vup) {
nodep->iterateChildren(*this, vup);
nodep->widthFrom(nodep->dtypep());
}
virtual void visit(AstRefDType* nodep, AstNUser* vup) { virtual void visit(AstRefDType* nodep, AstNUser* vup) {
nodep->iterateChildren(*this, vup); nodep->iterateChildren(*this, vup);
if (nodep->defp()) nodep->defp()->iterate(*this,vup); if (nodep->defp()) nodep->defp()->iterate(*this,vup);
@@ -759,55 +758,55 @@ private:
} }
virtual void visit(AstDisplay* nodep, AstNUser*) { virtual void visit(AstDisplay* nodep, AstNUser*) {
if (nodep->filep()) { if (nodep->filep()) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
// Just let all arguments seek their natural sizes // Just let all arguments seek their natural sizes
nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p());
} }
virtual void visit(AstFOpen* nodep, AstNUser*) { virtual void visit(AstFOpen* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->modep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->modep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFClose* nodep, AstNUser*) { virtual void visit(AstFClose* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFEof* nodep, AstNUser*) { virtual void visit(AstFEof* nodep, AstNUser*) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->width(1,1); nodep->width(1,1);
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFFlush* nodep, AstNUser*) { virtual void visit(AstFFlush* nodep, AstNUser*) {
if (nodep->filep()) { if (nodep->filep()) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
} }
virtual void visit(AstFGetC* nodep, AstNUser* vup) { virtual void visit(AstFGetC* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
if (vup->c()->prelim()) { if (vup->c()->prelim()) {
nodep->width(32,8); nodep->width(32,8);
} }
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFGetS* nodep, AstNUser* vup) { virtual void visit(AstFGetS* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->strgp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->strgp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (vup->c()->prelim()) { if (vup->c()->prelim()) {
nodep->width(32,32); nodep->width(32,32);
} }
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstFScanF* nodep, AstNUser* vup) { virtual void visit(AstFScanF* nodep, AstNUser* vup) {
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p()); nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (vup->c()->prelim()) { if (vup->c()->prelim()) {
nodep->width(32,32); nodep->width(32,32);
} }
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64); widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
} }
virtual void visit(AstSScanF* nodep, AstNUser* vup) { virtual void visit(AstSScanF* nodep, AstNUser* vup) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
@@ -825,9 +824,6 @@ private:
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
} }
virtual void visit(AstTestPlusArgs* nodep, AstNUser* vup) {
nodep->width(32,32);
}
virtual void visit(AstValuePlusArgs* nodep, AstNUser* vup) { virtual void visit(AstValuePlusArgs* nodep, AstNUser* vup) {
nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->width(32,32); nodep->width(32,32);
@@ -1044,18 +1040,328 @@ private:
nodep->iterateChildren(*this); nodep->iterateChildren(*this);
} }
// METHODS //----------------------------------------------------------------------
bool widthBad (AstNode* nodep, int expWidth, int expWidthMin); // METHODs
bool widthBad (AstNode* nodep, int expWidth, int expWidthMin) {
if (nodep->width()==0) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
if (expWidthMin==0) expWidthMin = expWidth;
if (nodep->widthSized() && nodep->width() != expWidthMin) return true;
if (!nodep->widthSized() && nodep->widthMin() > expWidthMin) return true;
return false;
}
void fixWidthExtend (AstNode* nodep, int expWidth) {
// Fix the width mismatch by extending or truncating bits
// Truncation is rarer, but can occur: parameter [3:0] FOO = 64'h12312;
// A(CONSTwide)+B becomes A(CONSTwidened)+B
// A(somewide)+B becomes A(TRUNC(somewide,width))+B
// or A(EXTRACT(somewide,width,0))+B
UINFO(4," widthExtend_old: "<<nodep<<endl);
AstConst* constp = nodep->castConst();
if (constp && !nodep->isSigned()) {
// Save later constant propagation work, just right-size it.
V3Number num (nodep->fileline(), expWidth);
num.opAssign(constp->num());
num.isSigned(nodep->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
constp->replaceWith(newp);
pushDeletep(constp); constp=NULL;
nodep=newp;
} else if (expWidth<nodep->width()) {
// Trunc - Extract
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
AstNode* newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
linker.relink(newp);
nodep=newp;
} else {
// Extend
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
AstNode* newp = (nodep->isSigned()
? (new AstExtendS(nodep->fileline(), nodep))->castNode()
: (new AstExtend (nodep->fileline(), nodep))->castNode());
linker.relink(newp);
nodep=newp;
}
nodep->width(expWidth,expWidth);
UINFO(4," _new: "<<nodep<<endl);
}
void fixWidthReduce (AstNode* nodep, int expWidth) {
// Fix the width mismatch by adding a reduction OR operator
// IF (A(CONSTwide)) becomes IF (A(CONSTreduced))
// IF (A(somewide)) becomes IF (A(REDOR(somewide)))
// Attempt to fix it quietly
UINFO(4," widthReduce_old: "<<nodep<<endl);
AstConst* constp = nodep->castConst();
if (constp) {
V3Number num (nodep->fileline(), expWidth);
num.opRedOr(constp->num());
num.isSigned(constp->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
constp->replaceWith(newp);
nodep=newp;
} else {
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
AstNode* newp = new AstRedOr(nodep->fileline(), nodep);
linker.relink(newp);
nodep=newp;
}
nodep->width(expWidth,expWidth);
UINFO(4," _new: "<<nodep<<endl);
}
bool fixAutoExtend (AstNode*& nodepr, int expWidth) {
// For SystemVerilog '0,'1,'x,'z, autoextend and don't warn
if (AstConst* constp = nodepr->castConst()) {
if (constp->num().autoExtend() && !constp->num().sized() && constp->width()==1) {
// Make it the proper size. Careful of proper extension of 0's/1's
V3Number num (constp->fileline(), expWidth);
num.opRepl(constp->num(), expWidth); // {width{'1}}
AstNode* newp = new AstConst(constp->fileline(), num);
// Spec says always unsigned with proper width
if (debug()>4) constp->dumpTree(cout," fixAutoExtend_old: ");
if (debug()>4) newp->dumpTree(cout," _new: ");
constp->replaceWith(newp);
constp->deleteTree(); constp=NULL;
// Tell caller the new constp, and that we changed it.
nodepr = newp;
return true;
}
}
return false; // No change
}
void widthCheck (AstNode* nodep, const char* side, void widthCheck (AstNode* nodep, const char* side,
AstNode* underp, int expWidth, int expWidthMin, AstNode* underp, int expWidth, int expWidthMin,
bool ignoreWarn=false); bool ignoreWarn=false) {
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e"<<expWidth<<" m"<<expWidthMin<<" i"<<ignoreWarn<<endl);
if (expWidthMin==0) expWidthMin = expWidth;
bool bad = widthBad(underp,expWidth,expWidthMin);
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
if (underp->castConst() && underp->castConst()->num().isFromString()
&& expWidth > underp->width()
&& (((expWidth - underp->width()) % 8) == 0)) { // At least it's character sized
// reg [31:0] == "foo" we'll consider probably fine.
// Maybe this should be a special warning? Not for now.
ignoreWarn = true;
}
if ((nodep->castAdd() && underp->width()==1 && underp->isOne())
|| (nodep->castSub() && underp->width()==1 && underp->isOne() && 0==strcmp(side,"RHS"))) {
// "foo + 1'b1", or "foo - 1'b1" are very common, people assume they extend correctly
ignoreWarn = true;
}
if (bad && !ignoreWarn) {
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
nodep->v3warn(WIDTH,"Operator "<<nodep->prettyTypeName()
<<" expects "<<expWidth
<<(expWidth!=expWidthMin?" or "+cvtToStr(expWidthMin):"")
<<" bits on the "<<side<<", but "<<side<<"'s "
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
}
if (bad || underp->width()!=expWidth) {
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
}
}
void widthCheckReduce (AstNode* nodep, const char* side, void widthCheckReduce (AstNode* nodep, const char* side,
AstNode* underp, int expWidth, int expWidthMin, AstNode* underp, int expWidth, int expWidthMin,
bool ignoreWarn=false); bool ignoreWarn=false) {
void widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin); // Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
bool fixAutoExtend (AstNode*& nodepr, int expWidth); if (expWidthMin==0) expWidthMin = expWidth;
void fixWidthExtend (AstNode* nodep, int expWidth); if (expWidth!=1) nodep->v3fatalSrc("Only for binary functions");
void fixWidthReduce (AstNode* nodep, int expWidth); bool bad = widthBad(underp,expWidth,expWidthMin);
if (bad) {
if (!ignoreWarn) {
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
nodep->v3warn(WIDTH,"Logical Operator "<<nodep->prettyTypeName()
<<" expects 1 bit on the "<<side<<", but "<<side<<"'s "
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
}
fixWidthReduce(underp, expWidth); underp=NULL;//Changed
}
}
void widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin) {
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
bool bad = widthBad(underp,expWidth,expWidth);
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
if (bad) {
nodep->v3warn(WIDTH,(inputPin?"Input":"Output")
<<" port connection "<<nodep->prettyName()
<<" expects "<<expWidth
<<" bits but connection's "
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
}
// We only fix input mismatches
if (bad && inputPin) {
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
}
}
void width_O1_L1(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, lhs 1 bit
// We calculate the width of the UNDER expression.
// We then check its width to see if it's legal, and edit if not
// We finally set the width of our output
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
}
nodep->width(1,1);
if (vup->c()->final()) {
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
}
}
void width_O1_L1_R1(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
}
nodep->width(1,1);
if (vup->c()->final()) {
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
widthCheckReduce(nodep,"RHS",nodep->op2p(),1,1);
}
}
void width_O1_L(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, Any width lhs
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
}
nodep->width(1,1);
}
void width_O1_L_Rlhs(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, lhs width == rhs width
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = max(nodep->op1p()->width(), nodep->op2p()->width());
int ewidth = max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin());
nodep->width(1,1);
if (vup->c()->final()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
widthCheck(nodep,"RHS",nodep->op2p(),width,ewidth);
}
}
void width_Ofixed_L(AstNodeUniop* nodep, AstNUser* vup, int width) {
// Widths: out width = specified width
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
}
nodep->width(width,width);
}
void width_Olhs_L(AstNodeUniop* nodep, AstNUser* vup) {
// Widths: out width = lhs width
// "Interim results shall take the max of operands, including LHS of assignments"
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = max(vup->c()->width(), nodep->lhsp()->width());
int ewidth = max(vup->c()->widthMin(), nodep->lhsp()->widthMin());
nodep->width(width,ewidth);
if (vup->c()->final()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
}
}
void width_Olhs_Lforce(AstNodeUniop* nodep, AstNUser* vup) {
// Widths: out width = lhs width
// It always comes exactly from LHS; ignores any upper operand
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = nodep->lhsp()->width();
int ewidth = nodep->lhsp()->width(); // Not minWidth; force it.
nodep->width(width,ewidth);
if (vup->c()->final()) {
// Final call, so make sure children check their sizes
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
}
}
void width_Olhs_L_R32(AstNode* nodep, AstNUser* vup) {
// Widths: Output width from lhs, rhs<33 bits
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
}
int width = max(vup->c()->width(), nodep->op1p()->width());
int ewidth = max(vup->c()->widthMin(), nodep->op1p()->widthMin());
nodep->width(width,ewidth);
if (vup->c()->final()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
if (nodep->op2p()->width()>32)
nodep->op2p()->v3error("Unsupported: Shifting of by a over 32 bit number isn't supported."
<<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
}
}
void width_Omax_L_Rlhs(AstNode* nodep, AstNUser* vup) {
// Widths: out width = lhs width = rhs width
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
// If errors are off, we need to follow the spec; thus we really need to do the max()
// because the rhs could be larger, and we need to have proper editing to get the widths
// to be the same for our operations.
if (vup->c()->prelim()) { // First stage evaluation
// Determine expression widths only relying on what's in the subops
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = max(vup->c()->width(), max(nodep->op1p()->width(), nodep->op2p()->width()));
int mwidth = max(vup->c()->widthMin(), max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin()));
nodep->width(width,mwidth);
if (vup->c()->final()) {
// Final call, so make sure children check their sizes
nodep->op1p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
// Some warning suppressions
bool lhsOk=false; bool rhsOk = false;
if (nodep->castAdd() || nodep->castSub()) {
lhsOk = (mwidth == (nodep->op1p()->widthMin()+1)); // Ok if user wants extra bit from carry
rhsOk = (mwidth == (nodep->op2p()->widthMin()+1)); // Ok if user wants extra bit from carry
} else if (nodep->castMul() || nodep->castMulS()) {
lhsOk = (mwidth >= (nodep->op1p()->widthMin()));
rhsOk = (mwidth >= (nodep->op2p()->widthMin()));
}
// Error report and change sizes for suboperands of this node.
widthCheck(nodep,"LHS",nodep->op1p(),width,mwidth,lhsOk);
widthCheck(nodep,"RHS",nodep->op2p(),width,mwidth,rhsOk);
}
}
public: public:
// CONSTUCTORS // CONSTUCTORS
@@ -1072,356 +1378,6 @@ public:
virtual ~WidthVisitor() {} virtual ~WidthVisitor() {}
}; };
//----------------------------------------------------------------------
// METHODs
bool WidthVisitor::widthBad (AstNode* nodep, int expWidth, int expWidthMin) {
if (nodep->width()==0) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
if (expWidthMin==0) expWidthMin = expWidth;
if (nodep->widthSized() && nodep->width() != expWidthMin) return true;
if (!nodep->widthSized() && nodep->widthMin() > expWidthMin) return true;
return false;
}
void WidthVisitor::fixWidthExtend (AstNode* nodep, int expWidth) {
// Fix the width mismatch by extending or truncating bits
// Truncation is rarer, but can occur: parameter [3:0] FOO = 64'h12312;
// A(CONSTwide)+B becomes A(CONSTwidened)+B
// A(somewide)+B becomes A(TRUNC(somewide,width))+B
// or A(EXTRACT(somewide,width,0))+B
UINFO(4," widthExtend_old: "<<nodep<<endl);
AstConst* constp = nodep->castConst();
if (constp && !nodep->isSigned()) {
// Save later constant propagation work, just right-size it.
V3Number num (nodep->fileline(), expWidth);
num.opAssign(constp->num());
num.isSigned(nodep->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
constp->replaceWith(newp);
pushDeletep(constp); constp=NULL;
nodep=newp;
} else if (expWidth<nodep->width()) {
// Trunc - Extract
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
AstNode* newp = new AstSel(nodep->fileline(), nodep, 0, expWidth);
linker.relink(newp);
nodep=newp;
} else {
// Extend
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
AstNode* newp = (nodep->isSigned()
? (new AstExtendS(nodep->fileline(), nodep))->castNode()
: (new AstExtend (nodep->fileline(), nodep))->castNode());
linker.relink(newp);
nodep=newp;
}
nodep->width(expWidth,expWidth);
UINFO(4," _new: "<<nodep<<endl);
}
void WidthVisitor::fixWidthReduce (AstNode* nodep, int expWidth) {
// Fix the width mismatch by adding a reduction OR operator
// IF (A(CONSTwide)) becomes IF (A(CONSTreduced))
// IF (A(somewide)) becomes IF (A(REDOR(somewide)))
// Attempt to fix it quietly
UINFO(4," widthReduce_old: "<<nodep<<endl);
AstConst* constp = nodep->castConst();
if (constp) {
V3Number num (nodep->fileline(), expWidth);
num.opRedOr(constp->num());
num.isSigned(constp->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
constp->replaceWith(newp);
nodep=newp;
} else {
AstNRelinker linker;
nodep->unlinkFrBack(&linker);
AstNode* newp = new AstRedOr(nodep->fileline(), nodep);
linker.relink(newp);
nodep=newp;
}
nodep->width(expWidth,expWidth);
UINFO(4," _new: "<<nodep<<endl);
}
bool WidthVisitor::fixAutoExtend (AstNode*& nodepr, int expWidth) {
// For SystemVerilog '0,'1,'x,'z, autoextend and don't warn
if (AstConst* constp = nodepr->castConst()) {
if (constp->num().autoExtend() && !constp->num().sized() && constp->width()==1) {
// Make it the proper size. Careful of proper extension of 0's/1's
V3Number num (constp->fileline(), expWidth);
num.opRepl(constp->num(), expWidth); // {width{'1}}
AstNode* newp = new AstConst(constp->fileline(), num);
// Spec says always unsigned with proper width
if (debug()>4) constp->dumpTree(cout," fixAutoExtend_old: ");
if (debug()>4) newp->dumpTree(cout," _new: ");
constp->replaceWith(newp);
constp->deleteTree(); constp=NULL;
// Tell caller the new constp, and that we changed it.
nodepr = newp;
return true;
}
}
return false; // No change
}
void WidthVisitor::widthCheck (AstNode* nodep, const char* side,
AstNode* underp, int expWidth, int expWidthMin,
bool ignoreWarn) {
//UINFO(9,"wchk "<<side<<endl<<" "<<nodep<<endl<<" "<<underp<<endl<<" e"<<expWidth<<" m"<<expWidthMin<<" i"<<ignoreWarn<<endl);
if (expWidthMin==0) expWidthMin = expWidth;
bool bad = widthBad(underp,expWidth,expWidthMin);
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
if (underp->castConst() && underp->castConst()->num().isFromString()
&& expWidth > underp->width()
&& (((expWidth - underp->width()) % 8) == 0)) { // At least it's character sized
// reg [31:0] == "foo" we'll consider probably fine.
// Maybe this should be a special warning? Not for now.
ignoreWarn = true;
}
if ((nodep->castAdd() && underp->width()==1 && underp->isOne())
|| (nodep->castSub() && underp->width()==1 && underp->isOne() && 0==strcmp(side,"RHS"))) {
// "foo + 1'b1", or "foo - 1'b1" are very common, people assume they extend correctly
ignoreWarn = true;
}
if (bad && !ignoreWarn) {
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
nodep->v3warn(WIDTH,"Operator "<<nodep->prettyTypeName()
<<" expects "<<expWidth
<<(expWidth!=expWidthMin?" or "+cvtToStr(expWidthMin):"")
<<" bits on the "<<side<<", but "<<side<<"'s "
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
}
if (bad || underp->width()!=expWidth) {
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
}
}
void WidthVisitor::widthCheckReduce (AstNode* nodep, const char* side,
AstNode* underp, int expWidth, int expWidthMin,
bool ignoreWarn) {
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
if (expWidthMin==0) expWidthMin = expWidth;
if (expWidth!=1) nodep->v3fatalSrc("Only for binary functions");
bool bad = widthBad(underp,expWidth,expWidthMin);
if (bad) {
if (!ignoreWarn) {
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
nodep->v3warn(WIDTH,"Logical Operator "<<nodep->prettyTypeName()
<<" expects 1 bit on the "<<side<<", but "<<side<<"'s "
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
}
fixWidthReduce(underp, expWidth); underp=NULL;//Changed
}
}
void WidthVisitor::widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin) {
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
bool bad = widthBad(underp,expWidth,expWidth);
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
if (bad) {
nodep->v3warn(WIDTH,(inputPin?"Input":"Output")
<<" port connection "<<nodep->prettyName()
<<" expects "<<expWidth
<<" bits but connection's "
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
}
// We only fix input mismatches
if (bad && inputPin) {
fixWidthExtend(underp, expWidth); underp=NULL;//Changed
}
}
void WidthVisitor::width_O1_L1(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, lhs 1 bit
// We calculate the width of the UNDER expression.
// We then check its width to see if it's legal, and edit if not
// We finally set the width of our output
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
}
nodep->width(1,1);
if (vup->c()->final()) {
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
}
}
void WidthVisitor::width_O1_L1_R1(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, lhs 1 bit, rhs 1 bit
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(1,0,BOTH).p());
}
nodep->width(1,1);
if (vup->c()->final()) {
widthCheckReduce(nodep,"LHS",nodep->op1p(),1,1);
widthCheckReduce(nodep,"RHS",nodep->op2p(),1,1);
}
}
void WidthVisitor::width_O1_L(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, Any width lhs
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
}
nodep->width(1,1);
}
void WidthVisitor::width_O1_L_Rlhs(AstNode* nodep, AstNUser* vup) {
// Widths: 1 bit out, lhs width == rhs width
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = max(nodep->op1p()->width(), nodep->op2p()->width());
int ewidth = max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin());
nodep->width(1,1);
if (vup->c()->final()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
widthCheck(nodep,"RHS",nodep->op2p(),width,ewidth);
}
}
void WidthVisitor::width_Olhs_L(AstNodeUniop* nodep, AstNUser* vup) {
// Widths: out width = lhs width
// "Interim results shall take the max of operands, including LHS of assignments"
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = max(vup->c()->width(), nodep->lhsp()->width());
int ewidth = max(vup->c()->widthMin(), nodep->lhsp()->widthMin());
nodep->width(width,ewidth);
if (vup->c()->final()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
}
}
void WidthVisitor::width_Olhs_Lforce(AstNodeUniop* nodep, AstNUser* vup) {
// Widths: out width = lhs width
// It always comes exactly from LHS; ignores any upper operand
if (nodep->op2p()) nodep->v3fatalSrc("For unary ops only!");
if (vup->c()->prelim()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = nodep->lhsp()->width();
int ewidth = nodep->lhsp()->width(); // Not minWidth; force it.
nodep->width(width,ewidth);
if (vup->c()->final()) {
// Final call, so make sure children check their sizes
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->lhsp(),width,ewidth);
}
}
void WidthVisitor::width_Olhs_L_R32(AstNode* nodep, AstNUser* vup) {
// Widths: Output width from lhs, rhs<33 bits
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
if (vup->c()->prelim()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
}
int width = max(vup->c()->width(), nodep->op1p()->width());
int ewidth = max(vup->c()->widthMin(), nodep->op1p()->widthMin());
nodep->width(width,ewidth);
if (vup->c()->final()) {
nodep->op1p()->iterateAndNext(*this,WidthVP(width,ewidth,FINAL).p());
widthCheck(nodep,"LHS",nodep->op1p(),width,ewidth);
if (nodep->op2p()->width()>32)
nodep->op2p()->v3error("Unsupported: Shifting of by a over 32 bit number isn't supported."
<<" (This isn't a shift of 32 bits, but a shift of 2^32, or 4 billion!)\n");
}
}
void WidthVisitor::width_Omax_L_Rlhs(AstNode* nodep, AstNUser* vup) {
// Widths: out width = lhs width = rhs width
if (!nodep->op2p()) nodep->v3fatalSrc("For binary ops only!");
// If errors are off, we need to follow the spec; thus we really need to do the max()
// because the rhs could be larger, and we need to have proper editing to get the widths
// to be the same for our operations.
if (vup->c()->prelim()) { // First stage evaluation
// Determine expression widths only relying on what's in the subops
nodep->op1p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
}
int width = max(vup->c()->width(), max(nodep->op1p()->width(), nodep->op2p()->width()));
int mwidth = max(vup->c()->widthMin(), max(nodep->op1p()->widthMin(), nodep->op2p()->widthMin()));
nodep->width(width,mwidth);
if (vup->c()->final()) {
// Final call, so make sure children check their sizes
nodep->op1p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
nodep->op2p()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
// Some warning suppressions
bool lhsOk=false; bool rhsOk = false;
if (nodep->castAdd() || nodep->castSub()) {
lhsOk = (mwidth == (nodep->op1p()->widthMin()+1)); // Ok if user wants extra bit from carry
rhsOk = (mwidth == (nodep->op2p()->widthMin()+1)); // Ok if user wants extra bit from carry
} else if (nodep->castMul() || nodep->castMulS()) {
lhsOk = (mwidth >= (nodep->op1p()->widthMin()));
rhsOk = (mwidth >= (nodep->op2p()->widthMin()));
}
// Error report and change sizes for suboperands of this node.
widthCheck(nodep,"LHS",nodep->op1p(),width,mwidth,lhsOk);
widthCheck(nodep,"RHS",nodep->op2p(),width,mwidth,rhsOk);
}
}
//######################################################################
class WidthCommitVisitor : public AstNVisitor {
// Now that all widthing is complete,
// Copy all width() to widthMin(). V3Const expects this
private:
// VISITORS
virtual void visit(AstConst* nodep, AstNUser*) {
nodep->width(nodep->width(),nodep->width());
if ((nodep->width() != nodep->num().width()) || !nodep->num().sized()) {
V3Number num (nodep->fileline(), nodep->width());
num.opAssign(nodep->num());
num.isSigned(nodep->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
nodep->replaceWith(newp);
//if (debug()>4) nodep->dumpTree(cout," fixConstSize_old: ");
//if (debug()>4) newp->dumpTree(cout," _new: ");
pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->width(nodep->width(),nodep->width());
nodep->iterateChildren(*this);
}
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
// This check could go anywhere after V3Param
nodep->v3fatalSrc("Presels should have been removed before this point");
}
public:
// CONSTUCTORS
WidthCommitVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~WidthCommitVisitor() {}
};
//###################################################################### //######################################################################
// Width class functions // Width class functions
@@ -1441,13 +1397,6 @@ AstNode* V3Width::widthParamsEdit(AstNode* nodep) {
return nodep; return nodep;
} }
AstNode* V3Width::widthParamsEditIfNeed(AstNode* nodep) {
if (!nodep->width()) {
nodep = V3Width::widthParamsEdit(nodep);
}
return nodep;
}
void V3Width::widthCommit(AstNetlist* nodep) { void V3Width::widthCommit(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl); UINFO(2,__FUNCTION__<<": "<<endl);
WidthCommitVisitor visitor (nodep); WidthCommitVisitor visitor (nodep);
-1
View File
@@ -34,7 +34,6 @@ public:
static void width(AstNetlist* nodep); static void width(AstNetlist* nodep);
// Smaller step... Only do a single node for parameter propagation // Smaller step... Only do a single node for parameter propagation
static AstNode* widthParamsEdit(AstNode* nodep); static AstNode* widthParamsEdit(AstNode* nodep);
static AstNode* widthParamsEditIfNeed(AstNode* nodep);
// Final step... Mark all widths as equal // Final step... Mark all widths as equal
static void widthCommit(AstNetlist* nodep); static void widthCommit(AstNetlist* nodep);
+72
View File
@@ -0,0 +1,72 @@
// -*- C++ -*-
//*************************************************************************
// DESCRIPTION: Verilator: Cleanup stage in V3Width
//
// Code available from: http://www.veripool.org/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2003-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 _V3WIDTHCOMMIT_H_
#define _V3WIDTHCOMMIT_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
#ifndef _V3WIDTH_CPP_
# error "V3WidthCommit for V3Width internal use only"
#endif
//######################################################################
class WidthCommitVisitor : public AstNVisitor {
// Now that all widthing is complete,
// Copy all width() to widthMin(). V3Const expects this
private:
// VISITORS
virtual void visit(AstConst* nodep, AstNUser*) {
nodep->width(nodep->width(),nodep->width());
if ((nodep->width() != nodep->num().width()) || !nodep->num().sized()) {
V3Number num (nodep->fileline(), nodep->width());
num.opAssign(nodep->num());
num.isSigned(nodep->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
nodep->replaceWith(newp);
//if (debug()>4) nodep->dumpTree(cout," fixConstSize_old: ");
//if (debug()>4) newp->dumpTree(cout," _new: ");
pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->width(nodep->width(),nodep->width());
nodep->iterateChildren(*this);
}
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
// This check could go anywhere after V3Param
nodep->v3fatalSrc("Presels should have been removed before this point");
}
public:
// CONSTUCTORS
WidthCommitVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~WidthCommitVisitor() {}
};
//######################################################################
#endif // Guard
+8 -3
View File
@@ -478,12 +478,12 @@ word [a-zA-Z0-9_]+
<S05,S09>{ <S05,S09>{
/* Keywords */ /* Keywords */
"assert" { FL; return yASSERT; } "assert" { FL; return yASSERT; }
"const" { FL; return yCONST__LEX; }
"cover" { FL; return yCOVER; } "cover" { FL; return yCOVER; }
"property" { FL; return yPROPERTY; } "property" { FL; return yPROPERTY; }
/* Generic unsupported warnings */ /* Generic unsupported warnings */
"assume" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); } "assume" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"before" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); } "before" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"const" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"sequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); } "sequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"union" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); } "union" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
"within" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); } "within" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
@@ -964,7 +964,8 @@ int V3ParseImp::lexToken() {
//yylval // Set by yylexThis() //yylval // Set by yylexThis()
} }
// If a paren, read another // If a paren, read another
if (token == yGLOBAL__LEX if (token == yCONST__LEX
|| token == yGLOBAL__LEX
// Never put yID_* here; below symbol table resolution would break // Never put yID_* here; below symbol table resolution would break
) { ) {
if (debugFlex()) { cout<<" lexToken: reading ahead to find possible strength"<<endl; } if (debugFlex()) { cout<<" lexToken: reading ahead to find possible strength"<<endl; }
@@ -975,7 +976,11 @@ int V3ParseImp::lexToken() {
m_aheadVal = yylval; m_aheadVal = yylval;
yylval = curValue; yylval = curValue;
// Now potentially munge the current token // Now potentially munge the current token
if (token == yGLOBAL__LEX) { if (token == yCONST__LEX) {
//UNSUP if (nexttok == yREF) token = yCONST__REF;
token = yCONST__ETC;
}
else if (token == yGLOBAL__LEX) {
if (nexttok == yCLOCKING) token = yGLOBAL__CLOCKING; if (nexttok == yCLOCKING) token = yGLOBAL__CLOCKING;
else { token = yaID__LEX; yylval.strp = PARSEP->newString("global"); } // Avoid 2009 "global" conflicting with old code when we can else { token = yaID__LEX; yylval.strp = PARSEP->newString("global"); } // Avoid 2009 "global" conflicting with old code when we can
} }
+13 -10
View File
@@ -274,6 +274,8 @@ class AstSenTree;
%token<fl> yCASEZ "casez" %token<fl> yCASEZ "casez"
%token<fl> yCHANDLE "chandle" %token<fl> yCHANDLE "chandle"
%token<fl> yCLOCKING "clocking" %token<fl> yCLOCKING "clocking"
%token<fl> yCONST__ETC "const"
%token<fl> yCONST__LEX "const-in-lex"
%token<fl> yCMOS "cmos" %token<fl> yCMOS "cmos"
%token<fl> yCONTEXT "context" %token<fl> yCONTEXT "context"
%token<fl> yCONTINUE "continue" %token<fl> yCONTINUE "continue"
@@ -1269,23 +1271,24 @@ data_declarationVar<nodep>: // IEEE: part of data_declaration
; ;
data_declarationVarFront: // IEEE: part of data_declaration data_declarationVarFront: // IEEE: part of data_declaration
// // Expanded: "constE yVAR lifetimeE data_type"
// // implicit_type expanded into /*empty*/ or "signingE rangeList" // // implicit_type expanded into /*empty*/ or "signingE rangeList"
constE yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($4); } /**/ yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($3); }
| constE yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT)); } | /**/ yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT)); }
| constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4),$5,false)); } | /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $3), $4,false)); }
//
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
| yCONST__ETC yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, $4)); }
| yCONST__ETC yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, new AstBasicDType($<fl>2, LOGIC_IMPLICIT))); }
| yCONST__ETC yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4), $5,false))); }
// //
// // Expanded: "constE lifetimeE data_type" // // Expanded: "constE lifetimeE data_type"
| /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); } | /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); }
| /**/ lifetime data_type { /*VARRESET-in-ddVar*/ VARDTYPE($2); } | /**/ lifetime data_type { /*VARRESET-in-ddVar*/ VARDTYPE($2); }
//UNSUP yCONST__ETC lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($3); } | yCONST__ETC lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE(new AstConstDType($<fl>1, $3)); }
// // = class_new is in variable_decl_assignment // // = class_new is in variable_decl_assignment
; ;
constE: // IEEE: part of data_declaration
/* empty */ { }
//UNSUP yCONST__ETC { UNSUP }
;
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
// // Also expanded in data_declaration // // Also expanded in data_declaration
/* empty */ { $$ = NULL; } /* empty */ { $$ = NULL; }
@@ -2374,7 +2377,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
// //
// // IEEE: unary_operator primary // // IEEE: unary_operator primary
'+' ~r~expr %prec prUNARYARITH { $$ = $2; } '+' ~r~expr %prec prUNARYARITH { $$ = $2; }
| '-' ~r~expr %prec prUNARYARITH { $$ = new AstUnaryMin ($1,$2); } | '-' ~r~expr %prec prUNARYARITH { $$ = new AstNegate ($1,$2); }
| '!' ~r~expr %prec prNEGATION { $$ = new AstLogNot ($1,$2); } | '!' ~r~expr %prec prNEGATION { $$ = new AstLogNot ($1,$2); }
| '&' ~r~expr %prec prREDUCTION { $$ = new AstRedAnd ($1,$2); } | '&' ~r~expr %prec prREDUCTION { $$ = new AstRedAnd ($1,$2); }
| '~' ~r~expr %prec prNEGATION { $$ = new AstNot ($1,$2); } | '~' ~r~expr %prec prNEGATION { $$ = new AstNot ($1,$2); }
+7 -4
View File
@@ -336,6 +336,7 @@ sub new {
$self->{run_log_filename} ||= "$self->{obj_dir}/vlt_sim.log"; $self->{run_log_filename} ||= "$self->{obj_dir}/vlt_sim.log";
$self->{coverage_filename} ||= "$self->{obj_dir}/vlt_coverage.pl"; $self->{coverage_filename} ||= "$self->{obj_dir}/vlt_coverage.pl";
$self->{vcd_filename} ||= "$self->{obj_dir}/sim.vcd"; $self->{vcd_filename} ||= "$self->{obj_dir}/sim.vcd";
$self->{main_filename} ||= "$self->{obj_dir}/$self->{VM_PREFIX}__main.cpp";
($self->{top_filename} = $self->{pl_filename}) =~ s/\.pl$/\.v/; ($self->{top_filename} = $self->{pl_filename}) =~ s/\.pl$/\.v/;
if (!$self->{make_top_shell}) { if (!$self->{make_top_shell}) {
$self->{top_shell_filename} = $self->{top_filename}; $self->{top_shell_filename} = $self->{top_filename};
@@ -536,6 +537,11 @@ sub compile {
return 1; return 1;
} }
if (!$param{fails} && $param{verilator_make_gcc}
&& $param{make_main}) {
$self->_make_main();
}
$self->_run(logfile=>"$self->{obj_dir}/vlt_compile.log", $self->_run(logfile=>"$self->{obj_dir}/vlt_compile.log",
fails=>$param{fails}, fails=>$param{fails},
expect=>$param{expect}, expect=>$param{expect},
@@ -543,9 +549,6 @@ sub compile {
return 1 if $self->errors || $self->skips; return 1 if $self->errors || $self->skips;
if (!$param{fails} && $param{verilator_make_gcc}) { if (!$param{fails} && $param{verilator_make_gcc}) {
if ($param{make_main}) {
$self->_make_main();
}
if ($self->sp) { if ($self->sp) {
$self->_sp_preproc(%param); $self->_sp_preproc(%param);
} }
@@ -806,7 +809,7 @@ sub _make_main {
$self->_read_inputs(); $self->_read_inputs();
my $filename = "$self->{obj_dir}/$self->{VM_PREFIX}__main.cpp"; my $filename = $self->{main_filename};
my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,"; my $fh = IO::File->new(">$filename") or die "%Error: $! $filename,";
print $fh "// Test defines\n"; print $fh "// Test defines\n";
+1 -1
View File
@@ -47,7 +47,7 @@ module t (/*AUTOARG*/
endcase endcase
end end
`ifdef NOT_YET_verilator `ifdef NOT_YET_VERILATOR // Unsupported
// ambit synthesis one_hot "a, b_oh" // ambit synthesis one_hot "a, b_oh"
// cadence one_cold "a_l, b_oc_l" // cadence one_cold "a_l, b_oc_l"
`endif `endif
+1 -1
View File
@@ -25,7 +25,7 @@ module t_case_huge_sub2 (/*AUTOARG*/
always @(/*AS*/index) begin always @(/*AS*/index) begin
case (index[7:0]) case (index[7:0])
`ifdef verilator `ifdef VERILATOR // Harder test
8'h00: begin outa = $c("0"); end // Makes whole table non-optimizable 8'h00: begin outa = $c("0"); end // Makes whole table non-optimizable
`else `else
8'h00: begin outa = 10'h0; end 8'h00: begin outa = 10'h0; end
-4
View File
@@ -2497,11 +2497,7 @@ module t_case_write1_tasks ();
endtask endtask
task big_case; task big_case;
`ifdef verilator
input [ 63:0] fd;
`else
input [ 31:0] fd; input [ 31:0] fd;
`endif
input [ 31:0] foo; input [ 31:0] foo;
reg [STRLEN*8: 1] foobar; reg [STRLEN*8: 1] foobar;
// verilator no_inline_task // verilator no_inline_task
-4
View File
@@ -10,11 +10,7 @@ module t_case_write2_tasks ();
// verilator lint_off WIDTH // verilator lint_off WIDTH
// verilator lint_off CASEINCOMPLETE // verilator lint_off CASEINCOMPLETE
`ifdef verilator
`define FD_BITS 63:0
`else
`define FD_BITS 31:0 `define FD_BITS 31:0
`endif
parameter STRLEN = 78; parameter STRLEN = 78;
task ozonerab; task ozonerab;
+1 -1
View File
@@ -86,7 +86,7 @@ module Test (/*AUTOARG*/
end end
reg displayit; reg displayit;
`ifdef verilator `ifdef VERILATOR // Harder test
initial displayit = $c1("0"); // Something that won't optimize away initial displayit = $c1("0"); // Something that won't optimize away
`else `else
initial displayit = '0; initial displayit = '0;
+1 -1
View File
@@ -11,7 +11,7 @@
`ifdef NC `ifdef NC
`define NO_SHORTREAL `define NO_SHORTREAL
`endif `endif
`ifdef VERILATOR `ifdef VERILATOR // Unsupported
`define NO_SHORTREAL `define NO_SHORTREAL
`endif `endif
+1 -1
View File
@@ -55,7 +55,7 @@ module t (/*AUTOARG*/
#error "`systemc_header didn't work" #error "`systemc_header didn't work"
#endif #endif
bool m_did_ctor; bool m_did_ctor;
uint32_t my_function() { vluint32_t my_function() {
if (!m_did_ctor) vl_fatal(__FILE__,__LINE__,__FILE__,"`systemc_ctor didn't work"); if (!m_did_ctor) vl_fatal(__FILE__,__LINE__,__FILE__,"`systemc_ctor didn't work");
return 1; return 1;
} }
+1 -1
View File
@@ -100,7 +100,7 @@ module tpub (
if (1'b1 != got_bool) $stop; if (1'b1 != got_bool) $stop;
$c("publicGetLong(got_long);"); $c("publicGetLong(got_long);");
if (24'h11bca != got_long) $stop; if (24'h11bca != got_long) $stop;
$c("{ uint64_t qq; publicGetQuad(qq); got_quad=qq; }"); $c("{ vluint64_t qq; publicGetQuad(qq); got_quad=qq; }");
if (60'haaaa_bbbb_cccc != got_quad) $stop; if (60'haaaa_bbbb_cccc != got_quad) $stop;
$c("{ WData gw[3]; publicGetWide(gw); VL_ASSIGN_W(72,got_wide,gw); }"); $c("{ WData gw[3]; publicGetWide(gw); VL_ASSIGN_W(72,got_wide,gw); }");
if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop; if (72'hac_abca_aaaa_bbbb_1234 != got_wide) $stop;
+7 -4
View File
@@ -10,12 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
unlink("$Self->{obj_dir}/t_sys_file_basic_test.log"); unlink("$Self->{obj_dir}/t_sys_file_basic_test.log");
compile ( compile (
v_flags2 => ['+incdir+../include'], v_flags2 => ['+incdir+../include',
); # Build without cached objects, see bug363
"--exe ../$Self->{main_filename}"],
make_flags=>'MAKE_MAIN=0 VM_PARALLEL_BUILDS=0',
);
execute ( execute (
check_finished=>1, check_finished=>1,
); );
file_grep ("$Self->{obj_dir}/t_sys_file_basic_test.log", file_grep ("$Self->{obj_dir}/t_sys_file_basic_test.log",
qr/\[0\] hello v=12345667 qr/\[0\] hello v=12345667
+18
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;
+21
View File
@@ -0,0 +1,21 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2011 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
const logic [2:0] five = 3'd5;
always @ (posedge clk) begin
if (five !== 3'd5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2005 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 (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_var_const_bad.v:\d+: Assigning to const variable: five
%Error: Exiting due to.*',
) if $Self->{v3};
ok(1);
1;
+22
View File
@@ -0,0 +1,22 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2011 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
const logic [2:0] five = 3'd5;
always @ (posedge clk) begin
five = 3'd4;
if (five !== 3'd5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+2 -2
View File
@@ -21,14 +21,14 @@ if ($Self->{v3}) {
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i8;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i8;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i16;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i16;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint64_t> \s+ i64;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<vluint64_t> \s+ i64;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o8;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o8;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o16;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o16;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint64_t> \s+ o64;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<vluint64_t> \s+ o64;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
} }
+2 -2
View File
@@ -21,14 +21,14 @@ if ($Self->{v3}) {
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint8_t> \s+ i8;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint8_t> \s+ i8;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint16_t> \s+ i16;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint16_t> \s+ i16;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint64_t> \s+ i64;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<vluint64_t> \s+ i64;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint8_t> \s+ o8;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint8_t> \s+ o8;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint16_t> \s+ o16;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint16_t> \s+ o16;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint64_t> \s+ o64;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<vluint64_t> \s+ o64;/x);
file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x); file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
} }
+4 -4
View File
@@ -60,11 +60,11 @@ int sc_main(int argc, char* argv[]) {
cout << "Defining Interconnect\n"; cout << "Defining Interconnect\n";
sc_signal<bool> reset_l; sc_signal<bool> reset_l;
sc_signal<bool> passed; sc_signal<bool> passed;
sc_signal<uint32_t> in_small; sc_signal<vluint32_t> in_small;
sc_signal<uint64_t> in_quad; sc_signal<vluint64_t> in_quad;
sc_signal<sc_bv<70> > in_wide; sc_signal<sc_bv<70> > in_wide;
sc_signal<uint32_t> out_small; sc_signal<vluint32_t> out_small;
sc_signal<uint64_t> out_quad; sc_signal<vluint64_t> out_quad;
sc_signal<sc_bv<70> > out_wide; sc_signal<sc_bv<70> > out_wide;
//========== //==========
+6 -6
View File
@@ -58,7 +58,7 @@ our $Raise_Weight_Max = 50;
'VREDXNOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(^~ %1)', }, 'VREDXNOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(^~ %1)', },
'VREDXOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(^ %1)', }, 'VREDXOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(^ %1)', },
'VNOT'=> {weight=>1&&3, width=>0, sc=>1, terminal=>0, v=>'(~ %1)', }, 'VNOT'=> {weight=>1&&3, width=>0, sc=>1, terminal=>0, v=>'(~ %1)', },
'VUNARYMIN'=> {weight=>1&&2, width=>0, sc=>1, terminal=>0, v=>'(- %1)', }, 'VNEGATE'=> {weight=>1&&2, width=>0, sc=>1, terminal=>0, v=>'(- %1)', },
'VCOUNTONES'=> {weight=>0&&2, width=>32, signed=>0, sc=>0, terminal=>0, v=>'\$countones(%1)', }, # No ncv support 'VCOUNTONES'=> {weight=>0&&2, width=>32, signed=>0, sc=>0, terminal=>0, v=>'\$countones(%1)', }, # No ncv support
'VONEHOT'=> {weight=>0&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'\$onehot(%1)', }, # No ncv support 'VONEHOT'=> {weight=>0&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'\$onehot(%1)', }, # No ncv support
'VONEHOT0'=> {weight=>0&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'\$onehot0(%1)', }, # No ncv support 'VONEHOT0'=> {weight=>0&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'\$onehot0(%1)', }, # No ncv support
@@ -143,7 +143,7 @@ my %ops2 =
'VREDXOR'=> {pl=>'VREDXOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, 'VREDXOR'=> {pl=>'VREDXOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'},
'VREDXNOR'=> {pl=>'VREDXNOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, 'VREDXNOR'=> {pl=>'VREDXNOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'},
'VNOT'=> {pl=>'VNOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg);'}, 'VNOT'=> {pl=>'VNOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg);'},
'VUNARYMIN'=> {pl=>'VUNARYMIN(%tr,%1v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg);'}, 'VNEGATE'=> {pl=>'VNEGATE (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg);'},
'VCOUNTONES'=> {pl=>'VCOUNTONES(%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, 'VCOUNTONES'=> {pl=>'VCOUNTONES(%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'},
'VONEHOT'=> {pl=>'VONEHOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, 'VONEHOT'=> {pl=>'VONEHOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'},
'VONEHOT0'=> {pl=>'VONEHOT0 (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, 'VONEHOT0'=> {pl=>'VONEHOT0 (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'},
@@ -832,8 +832,8 @@ sub decl_text {
my $varref = $Vars{$var}; my $varref = $Vars{$var};
if ($Opt_Sc) { if ($Opt_Sc) {
(!$varref->{signed}) or die "%Error: No signed SystemC yet\n"; (!$varref->{signed}) or die "%Error: No signed SystemC yet\n";
my $type = (( ($varref->{val}->Size == 32) && "uint32_t") my $type = (( ($varref->{val}->Size == 32) && "sc_dt::uint32")
|| (($varref->{val}->Size == 64) && "uint64_t")); || (($varref->{val}->Size == 64) && "sc_dt::uint64"));
$type or die "%Error: Unknown Size ".$varref->{val}->Size,","; $type or die "%Error: Unknown Size ".$varref->{val}->Size,",";
return sprintf " %s<%s> %s; //=%s" return sprintf " %s<%s> %s; //=%s"
, $decl_with, $type, $var, $varref->{val}->to_Hex; , $decl_with, $type, $var, $varref->{val}->to_Hex;
@@ -893,8 +893,8 @@ sub countones {
} }
sub VLOGNOT { $_[0]{val} = makebool(($_[1]->is_empty)?1:0); } sub VLOGNOT { $_[0]{val} = makebool(($_[1]->is_empty)?1:0); }
sub VUNARYMIN { $_[0]{val} = my $o = newsized($_[1]); $o->Negate($_[1]); } sub VNEGATE { $_[0]{val} = my $o = newsized($_[1]); $o->Negate($_[1]); }
sub VCOUNTONES { $_[0]{val} = Bit::Vector->new_Dec(32,countones($_[1])); } sub VCOUNTONES { $_[0]{val} = Bit::Vector->new_Dec(32,countones($_[1])); }
sub VONEHOT { $_[0]{val} = makebool((countones($_[1])==1)?1:0); } sub VONEHOT { $_[0]{val} = makebool((countones($_[1])==1)?1:0); }
sub VONEHOT0 { $_[0]{val} = makebool((countones($_[1])<=1)?1:0); } sub VONEHOT0 { $_[0]{val} = makebool((countones($_[1])<=1)?1:0); }