mirror of
https://github.com/verilator/verilator.git
synced 2026-08-22 14:06:52 +02:00
Merge branch 'master' of ssh://git-verilator-wsnyder/git/verilator
This commit is contained in:
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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() {}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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");
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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); }
|
||||||
|
|||||||
@@ -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";
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Executable
+18
@@ -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;
|
||||||
@@ -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
|
||||||
Executable
+19
@@ -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;
|
||||||
@@ -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
|
||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
@@ -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;
|
||||||
|
|
||||||
//==========
|
//==========
|
||||||
|
|||||||
@@ -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); }
|
||||||
|
|||||||
Reference in New Issue
Block a user