Merge branch 'master' of ssh://git-verilator-wsnyder/git/verilator
This commit is contained in:
commit
73eccecbf8
6
Changes
6
Changes
|
|
@ -5,8 +5,14 @@ indicates the contributor was also the author of the fix; Thanks!
|
|||
|
||||
* Verilator 3.814****
|
||||
|
||||
*** Support 'const' variables in limited cases; similar to enums. [Alex Solomatnikov]
|
||||
|
||||
*** Support disable for loop escapes.
|
||||
|
||||
*** Support $fopen and I/O with integer instead of `verilator_file_descriptor.
|
||||
|
||||
**** Use 'vluint64_t' for SystemC instead of (same sized) 'uint64' for MSVC++.
|
||||
|
||||
* Verilator 3.813 2011/06/28
|
||||
|
||||
*** Support bit vectors > 64 bits wide in DPI import and exports.
|
||||
|
|
|
|||
|
|
@ -268,7 +268,7 @@ descriptions in the next sections for more information.
|
|||
--MP Create phony dependency targets
|
||||
--Mdir <directory> Name of output object directory
|
||||
--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
|
||||
+notimingchecks Ignored
|
||||
-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>
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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.)
|
||||
|
||||
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,
|
||||
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
|
||||
$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
|
||||
case/if.
|
||||
|
||||
|
|
@ -1711,8 +1711,8 @@ assertion clocks.
|
|||
=head2 Synthesis Directive Assertion Support
|
||||
|
||||
With the --assert switch, Verilator reads any "//synopsys full_case" or "//
|
||||
synopsys parallel_case" directives. The same applies to any "//cadence" or
|
||||
"// ambit synthesis" directives of the same form.
|
||||
synopsys parallel_case" directives. The same applies to any "// ambit
|
||||
synthesis", "//cadence" or "//pragma" directives of the same form.
|
||||
|
||||
When these synthesis directives are discovered, Verilator will either
|
||||
formally prove the directive to be true, or failing that, will insert the
|
||||
|
|
@ -2261,7 +2261,7 @@ specified as illegal on chandles.
|
|||
=item disable
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
|
||||
|
|
@ -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
|
||||
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.
|
||||
|
||||
Signals wider than 64 bits are stored as an array of 32-bit uint32_t's.
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@
|
|||
#define _VERILATED_CPP_
|
||||
#include "verilated_imp.h"
|
||||
#include <cctype>
|
||||
#include <vector>
|
||||
|
||||
#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* VL_CVT_I_FP(IData lhs) {
|
||||
return VerilatedImp::fdToFp(lhs);
|
||||
}
|
||||
|
||||
void _VL_VINT_TO_STRING(int obits, char* destoutp, WDataInP sourcep) {
|
||||
// See also VL_DATA_TO_STRING_NW
|
||||
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; }
|
||||
}
|
||||
|
||||
IData VL_FGETS_IXQ(int obits, void* destp, QData fpq) {
|
||||
FILE* fp = VL_CVT_Q_FP(fpq);
|
||||
IData VL_FGETS_IXI(int obits, void* destp, IData fpi) {
|
||||
FILE* fp = VL_CVT_I_FP(fpi);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
|
||||
// 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);
|
||||
char modez[5];
|
||||
_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, ...) {
|
||||
|
|
@ -726,8 +735,8 @@ void VL_WRITEF(const char* formatp, ...) {
|
|||
VL_PRINTF("%s", output.c_str());
|
||||
}
|
||||
|
||||
void VL_FWRITEF(QData fpq, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_Q_FP(fpq);
|
||||
void VL_FWRITEF(IData fpi, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_I_FP(fpi);
|
||||
if (VL_UNLIKELY(!fp)) return;
|
||||
|
||||
va_list ap;
|
||||
|
|
@ -739,8 +748,8 @@ void VL_FWRITEF(QData fpq, const char* formatp, ...) {
|
|||
fputs(output.c_str(), fp);
|
||||
}
|
||||
|
||||
IData VL_FSCANF_IX(QData fpq, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_Q_FP(fpq);
|
||||
IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) {
|
||||
FILE* fp = VL_CVT_I_FP(fpi);
|
||||
if (VL_UNLIKELY(!fp)) return 0;
|
||||
|
||||
va_list ap;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/// 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_QI(QData ofilename, IData 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,
|
||||
WDataInP ofilename, void* memp, IData start, IData end);
|
||||
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); }
|
||||
|
||||
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_IQX(int lbits, QData ld, 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_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
|
||||
/// 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
|
||||
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*
|
||||
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,
|
||||
// we can't just
|
||||
//# define VL_UNARYMIN_I(data) (-(data))
|
||||
static inline IData VL_UNARYMIN_I(IData data) { return -data; }
|
||||
static inline QData VL_UNARYMIN_Q(QData data) { return -data; }
|
||||
//# define VL_NEGATE_I(data) (-(data))
|
||||
static inline IData VL_NEGATE_I(IData 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;
|
||||
for (int i=0; i<words; 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]);
|
||||
if (lneg) { // Negate lhs
|
||||
lwusp = lwstore;
|
||||
VL_UNARYMIN_W(words, lwstore, lwp);
|
||||
VL_NEGATE_W(words, lwstore, lwp);
|
||||
lwstore[words-1] &= VL_MASK_I(lbits); // Clean it
|
||||
}
|
||||
IData rneg = VL_SIGN_I(lbits,rwp[words-1]);
|
||||
if (rneg) { // Negate rhs
|
||||
rwusp = rwstore;
|
||||
VL_UNARYMIN_W(words, rwstore, rwp);
|
||||
VL_NEGATE_W(words, rwstore, rwp);
|
||||
rwstore[words-1] &= VL_MASK_I(lbits); // Clean it
|
||||
}
|
||||
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
|
||||
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;
|
||||
for (int i=0; i<words; 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];
|
||||
WDataInP ltup = lwp;
|
||||
WDataInP rtup = rwp;
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_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 (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_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if ((lsign && !rsign) || (!lsign && rsign)) {
|
||||
IData qNoSign[VL_MULS_MAX_WORDS];
|
||||
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;
|
||||
} else {
|
||||
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];
|
||||
WDataInP ltup = lwp;
|
||||
WDataInP rtup = rwp;
|
||||
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_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 (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_NEGATE_W(VL_WORDS_I(lbits), rwstore, rwp)); }
|
||||
if (lsign) { // Only dividend sign matters for modulus
|
||||
IData qNoSign[VL_MULS_MAX_WORDS];
|
||||
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;
|
||||
} else {
|
||||
return VL_MODDIV_WWW(lbits,owp,ltup,rtup);
|
||||
|
|
|
|||
|
|
@ -27,11 +27,7 @@
|
|||
`define coverage_block_off
|
||||
`endif
|
||||
|
||||
// Hide file descriptor difference
|
||||
`ifdef verilator
|
||||
`define verilator_file_descriptor reg [63:0]
|
||||
`else
|
||||
`define verilator_file_descriptor integer
|
||||
`endif
|
||||
// Hide file descriptor difference - deprecated - for older versions
|
||||
`define verilator_file_descriptor integer
|
||||
|
||||
`endif // guard
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@
|
|||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <string>
|
||||
|
||||
class VerilatedScope;
|
||||
|
|
@ -62,9 +63,18 @@ class VerilatedImp {
|
|||
ExportNameMap m_exportMap; ///< Map of <export_func_proto, func number>
|
||||
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
|
||||
// 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() {}
|
||||
|
||||
// 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
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -256,7 +256,7 @@ sub gentree {
|
|||
'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 ")"; },
|
||||
'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(); },
|
||||
'VARPIN' => sub { p "VARPIN what{";p1;p ",";p2;p ",";p3;p ",";p4;p ",";p5;p "}";nl; },
|
||||
'VARREF' => sub { a1; },
|
||||
|
|
|
|||
17
src/V3Ast.h
17
src/V3Ast.h
|
|
@ -209,7 +209,7 @@ class AstBasicDTypeKwd {
|
|||
public:
|
||||
enum en {
|
||||
BIT, BYTE, CHANDLE, INT, INTEGER, LOGIC, LONGINT,
|
||||
REAL, REALTIME, SHORTINT, SHORTREAL, TIME,
|
||||
REAL, SHORTINT, SHORTREAL, TIME,
|
||||
// Closer to a class type, but limited usage
|
||||
STRING,
|
||||
// Internal types for mid-steps
|
||||
|
|
@ -221,7 +221,7 @@ public:
|
|||
const char* ascii() const {
|
||||
static const char* names[] = {
|
||||
"bit", "byte", "chandle", "int", "integer", "logic", "longint",
|
||||
"real", "realtime", "shortint", "shortreal", "time",
|
||||
"real", "shortint", "shortreal", "time",
|
||||
"string",
|
||||
"VerilatedScope*", "char*",
|
||||
"LOGIC_IMPLICIT"
|
||||
|
|
@ -231,7 +231,7 @@ public:
|
|||
const char* dpiType() const {
|
||||
static const char* names[] = {
|
||||
"unsigned char", "char", "void*", "int", "int", "svLogic", "long long",
|
||||
"double", "double", "short int", "float", "long long",
|
||||
"double", "short int", "float", "long long",
|
||||
"const char*",
|
||||
"dpiScope", "const char*",
|
||||
""
|
||||
|
|
@ -251,6 +251,8 @@ public:
|
|||
case INTEGER: return 32;
|
||||
case LOGIC: return 1;
|
||||
case LONGINT: return 64;
|
||||
case REAL: return 64;
|
||||
case SHORTREAL: return 32;
|
||||
case SHORTINT: return 16;
|
||||
case TIME: return 64;
|
||||
case STRING: return 64; // Just the pointer, for today
|
||||
|
|
@ -265,7 +267,7 @@ public:
|
|||
}
|
||||
bool isZeroInit() const { // Otherwise initializes to X
|
||||
return (m_e==BIT || m_e==BYTE || m_e==CHANDLE || m_e==INT || m_e==LONGINT || m_e==SHORTINT
|
||||
|| m_e==STRING);
|
||||
|| m_e==STRING || m_e==REAL || m_e==SHORTREAL);
|
||||
}
|
||||
bool isSloppy() const { // Don't be as anal about width warnings
|
||||
return !(m_e==LOGIC || m_e==BIT);
|
||||
|
|
@ -274,10 +276,13 @@ public:
|
|||
return (m_e==LOGIC || m_e==BIT);
|
||||
}
|
||||
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
|
||||
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); }
|
||||
|
|
|
|||
|
|
@ -113,6 +113,10 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
|
|||
arg += "const char*";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SCOPEPTR) {
|
||||
arg += "const VerilatedScope*";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::REAL) {
|
||||
arg += "double";
|
||||
} else if (bdtypep && bdtypep->keyword()==AstBasicDTypeKwd::SHORTREAL) {
|
||||
arg += "float";
|
||||
} else if (strtype) {
|
||||
if (isInOnly()) arg += "const ";
|
||||
arg += "string";
|
||||
|
|
@ -185,7 +189,7 @@ string AstVar::cPubArgType(bool named, bool forReturn) const {
|
|||
} else if (isWide()) {
|
||||
arg += "uint32_t"; // []'s added later
|
||||
} else {
|
||||
arg += "uint64_t";
|
||||
arg += "vluint64_t";
|
||||
}
|
||||
if (isWide()) {
|
||||
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";
|
||||
}
|
||||
} else {
|
||||
return "uint64_t";
|
||||
return "vluint64_t";
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -608,7 +612,8 @@ void AstVar::dump(ostream& str) {
|
|||
else if (isInput()) str<<" [I]";
|
||||
else if (isOutput()) str<<" [O]";
|
||||
}
|
||||
if (isUsedClock()) str<<" [C]";
|
||||
if (isConst()) str<<" [CONST]";
|
||||
if (isUsedClock()) str<<" [CLK]";
|
||||
if (isSigPublic()) str<<" [P]";
|
||||
if (isUsedLoopIdx()) str<<" [LOOP]";
|
||||
if (attrClockEn()) str<<" [aCLKEN]";
|
||||
|
|
|
|||
|
|
@ -300,6 +300,25 @@ public:
|
|||
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 {
|
||||
private:
|
||||
AstTypedef* m_defp;
|
||||
|
|
@ -677,7 +696,7 @@ public:
|
|||
bool isToggleCoverable() const { return ((isIO() || isSignal())
|
||||
&& (isIO() || isBitLogic())
|
||||
// Wrapper would otherwise duplicate wrapped module's coverage
|
||||
&& !isSc() && !isPrimaryIO()); }
|
||||
&& !isSc() && !isPrimaryIO() && !isConst()); }
|
||||
bool isStatementTemp() const { return (varType()==AstVarType::STMTTEMP); }
|
||||
bool isMovableToBlock() const { return (varType()==AstVarType::BLOCKTEMP || isFuncLocal()); }
|
||||
bool isPure() const { return (varType()==AstVarType::XTEMP); }
|
||||
|
|
@ -2453,13 +2472,13 @@ struct AstUCFunc : public AstNodeMath {
|
|||
//======================================================================
|
||||
// Unary ops
|
||||
|
||||
struct AstUnaryMin : public AstNodeUniop {
|
||||
AstUnaryMin(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
struct AstNegate : public AstNodeUniop {
|
||||
AstNegate(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
|
||||
if (lhsp) widthSignedFrom(lhsp); }
|
||||
ASTNODE_NODE_FUNCS(UnaryMin, UNARYMIN)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opUnaryMin(lhs); }
|
||||
ASTNODE_NODE_FUNCS(Negate, NEGATE)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { out.opNegate(lhs); }
|
||||
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 sizeMattersLhs() {return true;}
|
||||
};
|
||||
|
|
@ -2697,7 +2716,7 @@ struct AstFEof : public AstNodeUniop {
|
|||
ASTNODE_NODE_FUNCS(FEof, FEOF)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
|
||||
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 sizeMattersLhs() {return false;}
|
||||
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 string emitVerilog() { return "%f$fgetc(%l)"; }
|
||||
// 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 sizeMattersLhs() {return false;}
|
||||
virtual int instrCount() const { return widthInstrs()*64; }
|
||||
|
|
|
|||
|
|
@ -135,7 +135,7 @@ private:
|
|||
insureLower32Cast(nodep);
|
||||
nodep->user1(1);
|
||||
}
|
||||
virtual void visit(AstUnaryMin* nodep, AstNUser*) {
|
||||
virtual void visit(AstNegate* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
nodep->user1(nodep->lhsp()->user1());
|
||||
if (nodep->lhsp()->widthMin()==1) {
|
||||
|
|
|
|||
|
|
@ -1519,7 +1519,7 @@ private:
|
|||
if (!inPct && ch=='%') {
|
||||
inPct = true;
|
||||
fmt = ch;
|
||||
} else if (inPct && isdigit(ch)) {
|
||||
} else if (inPct && (isdigit(ch) || ch=='.')) {
|
||||
fmt += ch;
|
||||
} else if (inPct) {
|
||||
inPct = false;
|
||||
|
|
@ -1664,7 +1664,7 @@ private:
|
|||
TREEOP ("AstShiftRS{$lhsp.isZero, $rhsp}", "replaceZero(nodep)");
|
||||
TREEOP ("AstXor {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
|
||||
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 ("AstAnd {$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
TREEOP ("AstLogAnd{$lhsp, $rhsp.isZero}", "replaceZero(nodep)");
|
||||
|
|
|
|||
|
|
@ -344,13 +344,11 @@ public:
|
|||
puts(");\n");
|
||||
}
|
||||
virtual void visit(AstFClose* nodep, AstNUser*) {
|
||||
puts("if (");
|
||||
puts("VL_FCLOSE_I(");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(") { fclose (VL_CVT_Q_FP(");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(")); ");
|
||||
puts("); ");
|
||||
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*) {
|
||||
if (!nodep->filep()) {
|
||||
|
|
@ -358,7 +356,7 @@ public:
|
|||
} else {
|
||||
puts("if (");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(") { fflush (VL_CVT_Q_FP(");
|
||||
puts(") { fflush (VL_CVT_I_FP(");
|
||||
nodep->filep()->iterateAndNext(*this);
|
||||
puts(")); }\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -483,6 +483,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
|
|||
putfs(nodep,nodep->prettyName());
|
||||
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*) {
|
||||
if (nodep->dotted()!="") { putfs(nodep,nodep->dotted()); puts("."); puts(nodep->prettyName()); }
|
||||
else { putfs(nodep,nodep->prettyName()); }
|
||||
|
|
|
|||
|
|
@ -696,8 +696,7 @@ private:
|
|||
int lhswidth = lhsp->widthMin();
|
||||
if (lhswidth==1) {
|
||||
UINFO(8," REPLICATE(w1) "<<nodep<<endl);
|
||||
newp = new AstUnaryMin (nodep->fileline(),
|
||||
lhsp);
|
||||
newp = new AstNegate (nodep->fileline(), lhsp);
|
||||
} else {
|
||||
UINFO(8," REPLICATE "<<nodep<<endl);
|
||||
AstConst* constp = nodep->rhsp()->castConst();
|
||||
|
|
@ -731,7 +730,7 @@ private:
|
|||
for (int w=0; w<rhsp->widthWords(); w++) {
|
||||
AstNode* newp;
|
||||
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);
|
||||
} else {
|
||||
newp = newAstWordSelClone (lhsp, w);
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ private:
|
|||
|
||||
// STATE
|
||||
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
|
||||
|
||||
// METHODS
|
||||
|
|
@ -67,6 +68,10 @@ private:
|
|||
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);
|
||||
}
|
||||
|
|
@ -222,6 +227,11 @@ private:
|
|||
}
|
||||
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*) {
|
||||
m_ftaskp = nodep;
|
||||
nodep->iterateChildren(*this);
|
||||
|
|
@ -259,6 +269,7 @@ public:
|
|||
LinkLValueVisitor(AstNode* nodep, bool start) {
|
||||
m_setRefLvalue = start;
|
||||
m_ftaskp = NULL;
|
||||
m_initialp = NULL;
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~LinkLValueVisitor() {}
|
||||
|
|
|
|||
|
|
@ -95,6 +95,9 @@ private:
|
|||
nodep->dtypeSkipRefp()->castArrayDType())) {
|
||||
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 (nodep->isSigModPublic()) {
|
||||
nodep->sigModPublic(false); // We're done with this attribute
|
||||
|
|
|
|||
|
|
@ -1079,12 +1079,12 @@ V3Number& V3Number::opAbsS (const V3Number& lhs) {
|
|||
// op i, L(lhs) bit return
|
||||
if (lhs.isFourState()) return setAllBitsX();
|
||||
if (lhs.isNegative()) {
|
||||
return opUnaryMin(lhs);
|
||||
return opNegate(lhs);
|
||||
} else {
|
||||
return opAssign(lhs);
|
||||
}
|
||||
}
|
||||
V3Number& V3Number::opUnaryMin (const V3Number& lhs) {
|
||||
V3Number& V3Number::opNegate (const V3Number& lhs) {
|
||||
// op i, L(lhs) bit return
|
||||
if (lhs.isFourState()) return setAllBitsX();
|
||||
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
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
V3Number negrhs (rhs.m_fileline, rhs.width());
|
||||
negrhs.opUnaryMin(rhs);
|
||||
negrhs.opNegate(rhs);
|
||||
return opAdd(lhs, negrhs);
|
||||
}
|
||||
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) {
|
||||
// Signed multiply
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs);
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||
V3Number qNoSign = opMul(lhsNoSign,rhsNoSign);
|
||||
if ((lhs.isNegative() && !rhs.isNegative())
|
||||
|| (!lhs.isNegative() && rhs.isNegative())) {
|
||||
opUnaryMin(qNoSign);
|
||||
opNegate(qNoSign);
|
||||
} else {
|
||||
opAssign(qNoSign);
|
||||
}
|
||||
|
|
@ -1169,13 +1169,13 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
|
|||
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
if (rhs.isEqZero()) return setAllBitsX();
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs);
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
|
||||
//UINFO(9, " >divs-mid "<<lhs<<" "<<rhs<<" "<<qNoSign<<endl);
|
||||
if ((lhs.isNegative() && !rhs.isNegative())
|
||||
|| (!lhs.isNegative() && rhs.isNegative())) {
|
||||
opUnaryMin(qNoSign);
|
||||
opNegate(qNoSign);
|
||||
} else {
|
||||
opAssign(qNoSign);
|
||||
}
|
||||
|
|
@ -1198,11 +1198,11 @@ V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
|
|||
// Signed moddiv
|
||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||
if (rhs.isEqZero()) return setAllBitsX();
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs);
|
||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||
V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign);
|
||||
if (lhs.isNegative()) { // Just lhs' sign (*DIFFERENT FROM PERL, which uses rhs sign*)
|
||||
opUnaryMin(qNoSign);
|
||||
opNegate(qNoSign);
|
||||
} else {
|
||||
opAssign(qNoSign);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -203,7 +203,7 @@ public:
|
|||
V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opAbsS (const V3Number& lhs);
|
||||
V3Number& opUnaryMin(const V3Number& lhs);
|
||||
V3Number& opNegate (const V3Number& lhs);
|
||||
V3Number& opAdd (const V3Number& lhs, const V3Number& rhs);
|
||||
V3Number& opSub (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=="~") gotnum.opNot (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.opSub (lhnum,rhnum);
|
||||
else if (op=="*") gotnum.opMul (lhnum,rhnum);
|
||||
|
|
@ -96,8 +96,8 @@ int main() {
|
|||
test("32'b0x","|","32'b10","32'b1x");
|
||||
test("32'b10","&","32'b11","32'b10");
|
||||
test("32'b10","+","32'b10","32'b100");
|
||||
test("3'b000","unaryMin","","3'b000");
|
||||
test("3'b001","unaryMin","","3'b111");
|
||||
test("3'b000","negate","","3'b000");
|
||||
test("3'b001","negate","","3'b111");
|
||||
test("32'b11","-","32'b001","32'b10");
|
||||
test("3'b000","-","3'b111","3'b001");
|
||||
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")))) {
|
||||
cp+=strlen("cadence");
|
||||
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")))) {
|
||||
cp+=strlen("ambit synthesis");
|
||||
synth = true;
|
||||
|
|
|
|||
|
|
@ -208,12 +208,12 @@ private:
|
|||
// Then over shifting gives the sign bit, not all zeros
|
||||
// Note *NOT* clean output -- just like normal shift!
|
||||
// Create equivalent of VL_SIGNONES_(node_width)
|
||||
constzerop = new AstUnaryMin (nodep->fileline(),
|
||||
new AstShiftR(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false),
|
||||
new AstConst(nodep->fileline(),
|
||||
nodep->widthMin()-1),
|
||||
nodep->width()));
|
||||
constzerop = new AstNegate (nodep->fileline(),
|
||||
new AstShiftR(nodep->fileline(),
|
||||
nodep->lhsp()->cloneTree(false),
|
||||
new AstConst(nodep->fileline(),
|
||||
nodep->widthMin()-1),
|
||||
nodep->width()));
|
||||
} else {
|
||||
V3Number zeronum (nodep->fileline(), nodep->width(), 0);
|
||||
constzerop = new AstConst(nodep->fileline(), zeronum);
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ class SignedVisitor : public AstNVisitor {
|
|||
private:
|
||||
// NODE STATE/TYPES
|
||||
// STATE
|
||||
int m_taskDepth; // Recursion check
|
||||
bool m_paramsOnly; // Computing parameter value; limit operation
|
||||
|
||||
// METHODS - special type detection
|
||||
|
|
@ -62,8 +61,8 @@ private:
|
|||
// VISITORS
|
||||
//========
|
||||
// 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(AstSigned* nodep, AstNUser*) { signed_Os_Ix(nodep); }
|
||||
|
||||
//========
|
||||
// Signed: Output unsigned, Operands either
|
||||
|
|
@ -121,7 +120,7 @@ private:
|
|||
//=======
|
||||
// Signed: Output signed iff LHS signed; unary operator
|
||||
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(AstShiftR* nodep, AstNUser*) { signed_Olhs(nodep); }
|
||||
|
||||
|
|
@ -291,6 +290,18 @@ private:
|
|||
// ShiftRS converts to ShiftR, but not vice-versa
|
||||
virtual void visit(AstShiftRS* nodep, AstNUser*) { checkReplace_Olhs(nodep); }
|
||||
|
||||
// VISITORS - defaults
|
||||
virtual void visit(AstNodeMath* nodep, AstNUser*) {
|
||||
nodep->v3fatalSrc("Visit function missing? Signedness unknown for this node: "<<nodep);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
|
||||
//=======
|
||||
// Lower level functions
|
||||
|
||||
void checkReplace_Ou_FlavLhsAndRhs(AstNodeBiop* nodep) {
|
||||
// For compares, the output of the comparison is unsigned.
|
||||
// However, we need the appropriate type of compare selected by RHS & LHS
|
||||
|
|
@ -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
|
||||
// Signed: Output signed, Lhs/Rhs/etc either
|
||||
void signed_Os_Ix(AstNode* nodep) {
|
||||
|
|
@ -392,7 +394,6 @@ public:
|
|||
// CONSTRUCTORS
|
||||
SignedVisitor(bool paramsOnly) {
|
||||
m_paramsOnly = paramsOnly;
|
||||
m_taskDepth = 0;
|
||||
}
|
||||
virtual ~SignedVisitor() {}
|
||||
AstNode* mainAcceptEdit(AstNode* nodep) {
|
||||
|
|
|
|||
751
src/V3Width.cpp
751
src/V3Width.cpp
|
|
@ -57,6 +57,10 @@
|
|||
#include "V3Const.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
|
||||
|
||||
|
|
@ -99,19 +103,16 @@ private:
|
|||
// VISITORS
|
||||
// Naming: width_{output size rule}_{lhs rule}_{rhs rule}
|
||||
// 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(AstPslBool* nodep, AstNUser* vup) { width_O1_L1(nodep,vup); }
|
||||
|
||||
// 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(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(AstLogIff* nodep, AstNUser* vup) { width_O1_L1_R1(nodep,vup); }
|
||||
|
||||
// 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(AstRedOr* 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); }
|
||||
|
||||
// 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(AstEqCase* 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); }
|
||||
|
||||
// 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(AstOr* 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); }
|
||||
|
||||
// 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(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
|
||||
void width_Olhs_Lforce(AstNodeUniop* nodep, AstNUser* 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); }
|
||||
|
||||
// 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(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(AstShiftR* 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....
|
||||
virtual void visit(AstNodeCond* nodep, AstNUser* vup) {
|
||||
// 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
|
||||
}
|
||||
}
|
||||
virtual void visit(AstTime* nodep, AstNUser*) {
|
||||
nodep->width(64,64);
|
||||
}
|
||||
virtual void visit(AstUCFunc* nodep, AstNUser* vup) {
|
||||
// Give it the size the user wants.
|
||||
if (vup && vup->c()->prelim()) {
|
||||
|
|
@ -459,7 +457,7 @@ private:
|
|||
int selwidth = V3Number::log2b(nodep->lhsp()->width())+1;
|
||||
nodep->width(selwidth,selwidth);
|
||||
}
|
||||
}
|
||||
}
|
||||
virtual void visit(AstCvtPackString* nodep, AstNUser* vup) {
|
||||
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
|
|
@ -470,9 +468,6 @@ private:
|
|||
virtual void visit(AstText* nodep, AstNUser* vup) {
|
||||
// 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) {
|
||||
// Lower datatype determines the width
|
||||
nodep->dtypep()->iterateAndNext(*this,vup);
|
||||
|
|
@ -488,6 +483,10 @@ private:
|
|||
// else width in node is correct; it was set based on keyword().width()
|
||||
// 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) {
|
||||
nodep->iterateChildren(*this, vup);
|
||||
if (nodep->defp()) nodep->defp()->iterate(*this,vup);
|
||||
|
|
@ -759,55 +758,55 @@ private:
|
|||
}
|
||||
virtual void visit(AstDisplay* nodep, AstNUser*) {
|
||||
if (nodep->filep()) {
|
||||
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
|
||||
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64);
|
||||
nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
|
||||
widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
|
||||
}
|
||||
// Just let all arguments seek their natural sizes
|
||||
nodep->iterateChildren(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
}
|
||||
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->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*) {
|
||||
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
|
||||
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64);
|
||||
nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
|
||||
widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
|
||||
}
|
||||
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);
|
||||
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64);
|
||||
widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
|
||||
}
|
||||
virtual void visit(AstFFlush* nodep, AstNUser*) {
|
||||
if (nodep->filep()) {
|
||||
nodep->filep()->iterateAndNext(*this,WidthVP(64,64,BOTH).p());
|
||||
widthCheck(nodep,"file_descriptor (see docs)",nodep->filep(),64,64);
|
||||
nodep->filep()->iterateAndNext(*this,WidthVP(32,32,BOTH).p());
|
||||
widthCheck(nodep,"file_descriptor",nodep->filep(),32,32);
|
||||
}
|
||||
}
|
||||
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()) {
|
||||
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) {
|
||||
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());
|
||||
if (vup->c()->prelim()) {
|
||||
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) {
|
||||
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());
|
||||
if (vup->c()->prelim()) {
|
||||
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) {
|
||||
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
|
|
@ -825,9 +824,6 @@ private:
|
|||
nodep->lsbp()->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) {
|
||||
nodep->exprsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
|
||||
nodep->width(32,32);
|
||||
|
|
@ -939,7 +935,7 @@ private:
|
|||
m_funcp = NULL;
|
||||
}
|
||||
virtual void visit(AstReturn* nodep, AstNUser* vup) {
|
||||
if (!m_funcp) {
|
||||
if (!m_funcp) {
|
||||
if (nodep->lhsp()) { // Return w/o value ok other places
|
||||
nodep->v3error("Return with return value isn't underneath a function");
|
||||
}
|
||||
|
|
@ -1044,18 +1040,328 @@ private:
|
|||
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,
|
||||
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,
|
||||
AstNode* underp, int expWidth, int expWidthMin,
|
||||
bool ignoreWarn=false);
|
||||
void widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin);
|
||||
bool fixAutoExtend (AstNode*& nodepr, int expWidth);
|
||||
void fixWidthExtend (AstNode* nodep, int expWidth);
|
||||
void fixWidthReduce (AstNode* nodep, int expWidth);
|
||||
bool ignoreWarn=false) {
|
||||
// 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 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:
|
||||
// CONSTUCTORS
|
||||
|
|
@ -1072,356 +1378,6 @@ public:
|
|||
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
|
||||
|
||||
|
|
@ -1441,13 +1397,6 @@ AstNode* V3Width::widthParamsEdit(AstNode* nodep) {
|
|||
return nodep;
|
||||
}
|
||||
|
||||
AstNode* V3Width::widthParamsEditIfNeed(AstNode* nodep) {
|
||||
if (!nodep->width()) {
|
||||
nodep = V3Width::widthParamsEdit(nodep);
|
||||
}
|
||||
return nodep;
|
||||
}
|
||||
|
||||
void V3Width::widthCommit(AstNetlist* nodep) {
|
||||
UINFO(2,__FUNCTION__<<": "<<endl);
|
||||
WidthCommitVisitor visitor (nodep);
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@ public:
|
|||
static void width(AstNetlist* nodep);
|
||||
// Smaller step... Only do a single node for parameter propagation
|
||||
static AstNode* widthParamsEdit(AstNode* nodep);
|
||||
static AstNode* widthParamsEditIfNeed(AstNode* nodep);
|
||||
// Final step... Mark all widths as equal
|
||||
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
|
||||
|
|
@ -478,12 +478,12 @@ word [a-zA-Z0-9_]+
|
|||
<S05,S09>{
|
||||
/* Keywords */
|
||||
"assert" { FL; return yASSERT; }
|
||||
"const" { FL; return yCONST__LEX; }
|
||||
"cover" { FL; return yCOVER; }
|
||||
"property" { FL; return yPROPERTY; }
|
||||
/* Generic unsupported warnings */
|
||||
"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); }
|
||||
"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); }
|
||||
"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); }
|
||||
|
|
@ -964,7 +964,8 @@ int V3ParseImp::lexToken() {
|
|||
//yylval // Set by yylexThis()
|
||||
}
|
||||
// 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
|
||||
) {
|
||||
if (debugFlex()) { cout<<" lexToken: reading ahead to find possible strength"<<endl; }
|
||||
|
|
@ -975,7 +976,11 @@ int V3ParseImp::lexToken() {
|
|||
m_aheadVal = yylval;
|
||||
yylval = curValue;
|
||||
// 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;
|
||||
else { token = yaID__LEX; yylval.strp = PARSEP->newString("global"); } // Avoid 2009 "global" conflicting with old code when we can
|
||||
}
|
||||
|
|
|
|||
|
|
@ -274,6 +274,8 @@ class AstSenTree;
|
|||
%token<fl> yCASEZ "casez"
|
||||
%token<fl> yCHANDLE "chandle"
|
||||
%token<fl> yCLOCKING "clocking"
|
||||
%token<fl> yCONST__ETC "const"
|
||||
%token<fl> yCONST__LEX "const-in-lex"
|
||||
%token<fl> yCMOS "cmos"
|
||||
%token<fl> yCONTEXT "context"
|
||||
%token<fl> yCONTINUE "continue"
|
||||
|
|
@ -1269,23 +1271,24 @@ data_declarationVar<nodep>: // 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"
|
||||
constE yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($4); }
|
||||
| constE yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT)); }
|
||||
| constE yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4),$5,false)); }
|
||||
/**/ yVAR lifetimeE data_type { /*VARRESET-in-ddVar*/ VARDTYPE($3); }
|
||||
| /**/ yVAR lifetimeE { /*VARRESET-in-ddVar*/ VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT)); }
|
||||
| /**/ 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"
|
||||
| /**/ data_type { /*VARRESET-in-ddVar*/ VARDTYPE($1); }
|
||||
| /**/ 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
|
||||
;
|
||||
|
||||
constE: // IEEE: part of data_declaration
|
||||
/* empty */ { }
|
||||
//UNSUP yCONST__ETC { UNSUP }
|
||||
;
|
||||
|
||||
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
|
||||
// // Also expanded in data_declaration
|
||||
/* empty */ { $$ = NULL; }
|
||||
|
|
@ -2374,7 +2377,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
|
|||
//
|
||||
// // IEEE: unary_operator primary
|
||||
'+' ~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 prREDUCTION { $$ = new AstRedAnd ($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->{coverage_filename} ||= "$self->{obj_dir}/vlt_coverage.pl";
|
||||
$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/;
|
||||
if (!$self->{make_top_shell}) {
|
||||
$self->{top_shell_filename} = $self->{top_filename};
|
||||
|
|
@ -536,6 +537,11 @@ sub compile {
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (!$param{fails} && $param{verilator_make_gcc}
|
||||
&& $param{make_main}) {
|
||||
$self->_make_main();
|
||||
}
|
||||
|
||||
$self->_run(logfile=>"$self->{obj_dir}/vlt_compile.log",
|
||||
fails=>$param{fails},
|
||||
expect=>$param{expect},
|
||||
|
|
@ -543,9 +549,6 @@ sub compile {
|
|||
return 1 if $self->errors || $self->skips;
|
||||
|
||||
if (!$param{fails} && $param{verilator_make_gcc}) {
|
||||
if ($param{make_main}) {
|
||||
$self->_make_main();
|
||||
}
|
||||
if ($self->sp) {
|
||||
$self->_sp_preproc(%param);
|
||||
}
|
||||
|
|
@ -806,7 +809,7 @@ sub _make_main {
|
|||
|
||||
$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,";
|
||||
|
||||
print $fh "// Test defines\n";
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ module t (/*AUTOARG*/
|
|||
endcase
|
||||
end
|
||||
|
||||
`ifdef NOT_YET_verilator
|
||||
`ifdef NOT_YET_VERILATOR // Unsupported
|
||||
// ambit synthesis one_hot "a, b_oh"
|
||||
// cadence one_cold "a_l, b_oc_l"
|
||||
`endif
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ module t_case_huge_sub2 (/*AUTOARG*/
|
|||
|
||||
always @(/*AS*/index) begin
|
||||
case (index[7:0])
|
||||
`ifdef verilator
|
||||
`ifdef VERILATOR // Harder test
|
||||
8'h00: begin outa = $c("0"); end // Makes whole table non-optimizable
|
||||
`else
|
||||
8'h00: begin outa = 10'h0; end
|
||||
|
|
|
|||
|
|
@ -2497,11 +2497,7 @@ module t_case_write1_tasks ();
|
|||
endtask
|
||||
|
||||
task big_case;
|
||||
`ifdef verilator
|
||||
input [ 63:0] fd;
|
||||
`else
|
||||
input [ 31:0] fd;
|
||||
`endif
|
||||
input [ 31:0] foo;
|
||||
reg [STRLEN*8: 1] foobar;
|
||||
// verilator no_inline_task
|
||||
|
|
|
|||
|
|
@ -10,11 +10,7 @@ module t_case_write2_tasks ();
|
|||
// verilator lint_off WIDTH
|
||||
// verilator lint_off CASEINCOMPLETE
|
||||
|
||||
`ifdef verilator
|
||||
`define FD_BITS 63:0
|
||||
`else
|
||||
`define FD_BITS 31:0
|
||||
`endif
|
||||
|
||||
parameter STRLEN = 78;
|
||||
task ozonerab;
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ module Test (/*AUTOARG*/
|
|||
end
|
||||
|
||||
reg displayit;
|
||||
`ifdef verilator
|
||||
`ifdef VERILATOR // Harder test
|
||||
initial displayit = $c1("0"); // Something that won't optimize away
|
||||
`else
|
||||
initial displayit = '0;
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@
|
|||
`ifdef NC
|
||||
`define NO_SHORTREAL
|
||||
`endif
|
||||
`ifdef VERILATOR
|
||||
`ifdef VERILATOR // Unsupported
|
||||
`define NO_SHORTREAL
|
||||
`endif
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ module t (/*AUTOARG*/
|
|||
#error "`systemc_header didn't work"
|
||||
#endif
|
||||
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");
|
||||
return 1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,7 @@ module tpub (
|
|||
if (1'b1 != got_bool) $stop;
|
||||
$c("publicGetLong(got_long);");
|
||||
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;
|
||||
$c("{ WData gw[3]; publicGetWide(gw); VL_ASSIGN_W(72,got_wide,gw); }");
|
||||
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");
|
||||
|
||||
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 (
|
||||
check_finished=>1,
|
||||
);
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
file_grep ("$Self->{obj_dir}/t_sys_file_basic_test.log",
|
||||
qr/\[0\] hello v=12345667
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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+ 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<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_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+ 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<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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<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<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_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<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<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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -60,11 +60,11 @@ int sc_main(int argc, char* argv[]) {
|
|||
cout << "Defining Interconnect\n";
|
||||
sc_signal<bool> reset_l;
|
||||
sc_signal<bool> passed;
|
||||
sc_signal<uint32_t> in_small;
|
||||
sc_signal<uint64_t> in_quad;
|
||||
sc_signal<vluint32_t> in_small;
|
||||
sc_signal<vluint64_t> in_quad;
|
||||
sc_signal<sc_bv<70> > in_wide;
|
||||
sc_signal<uint32_t> out_small;
|
||||
sc_signal<uint64_t> out_quad;
|
||||
sc_signal<vluint32_t> out_small;
|
||||
sc_signal<vluint64_t> out_quad;
|
||||
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)', },
|
||||
'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)', },
|
||||
'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
|
||||
'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
|
||||
|
|
@ -143,7 +143,7 @@ my %ops2 =
|
|||
'VREDXOR'=> {pl=>'VREDXOR (%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);'},
|
||||
'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);'},
|
||||
'VONEHOT'=> {pl=>'VONEHOT (%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};
|
||||
if ($Opt_Sc) {
|
||||
(!$varref->{signed}) or die "%Error: No signed SystemC yet\n";
|
||||
my $type = (( ($varref->{val}->Size == 32) && "uint32_t")
|
||||
|| (($varref->{val}->Size == 64) && "uint64_t"));
|
||||
my $type = (( ($varref->{val}->Size == 32) && "sc_dt::uint32")
|
||||
|| (($varref->{val}->Size == 64) && "sc_dt::uint64"));
|
||||
$type or die "%Error: Unknown Size ".$varref->{val}->Size,",";
|
||||
return sprintf " %s<%s> %s; //=%s"
|
||||
, $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 VUNARYMIN { $_[0]{val} = my $o = newsized($_[1]); $o->Negate($_[1]); }
|
||||
sub VLOGNOT { $_[0]{val} = makebool(($_[1]->is_empty)?1:0); }
|
||||
sub VNEGATE { $_[0]{val} = my $o = newsized($_[1]); $o->Negate($_[1]); }
|
||||
sub VCOUNTONES { $_[0]{val} = Bit::Vector->new_Dec(32,countones($_[1])); }
|
||||
sub VONEHOT { $_[0]{val} = makebool((countones($_[1])==1)?1:0); }
|
||||
sub VONEHOT0 { $_[0]{val} = makebool((countones($_[1])<=1)?1:0); }
|
||||
|
|
|
|||
Loading…
Reference in New Issue