mirror of
https://github.com/verilator/verilator.git
synced 2025-01-10 08:37:35 +00:00
333 lines
16 KiB
C++
333 lines
16 KiB
C++
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||
//*************************************************************************
|
||
// DESCRIPTION: Verilator: Large 4-state numbers
|
||
//
|
||
// Code available from: http://www.veripool.org/verilator
|
||
//
|
||
//*************************************************************************
|
||
//
|
||
// Copyright 2003-2016 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 _V3NUMBER_H_
|
||
#define _V3NUMBER_H_ 1
|
||
#include "config_build.h"
|
||
#include "verilatedos.h"
|
||
#include <vector>
|
||
|
||
#include "V3Error.h"
|
||
#include "V3FileLine.h"
|
||
|
||
//============================================================================
|
||
|
||
class V3Number {
|
||
// Large 4-state number handling
|
||
int m_width; // Width as specified/calculated.
|
||
bool m_sized:1; // True if the user specified the width, else we track it.
|
||
bool m_signed:1; // True if signed value
|
||
bool m_double:1; // True if double real value
|
||
bool m_isString:1; // True if string
|
||
bool m_fromString:1; // True if from string literal
|
||
bool m_autoExtend:1; // True if SystemVerilog extend-to-any-width
|
||
FileLine* m_fileline;
|
||
vector<uint32_t> m_value; // The Value, with bit 0 being in bit 0 of this vector (unless X/Z)
|
||
vector<uint32_t> m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x
|
||
string m_stringVal; // If isString, the value of the string
|
||
// METHODS
|
||
V3Number& setSingleBits(char value);
|
||
V3Number& setString(const string& str) { m_isString=true; m_stringVal=str; return *this; }
|
||
void opCleanThis();
|
||
public:
|
||
FileLine* fileline() const { return m_fileline; }
|
||
void fileline(FileLine* fl) { m_fileline=fl; }
|
||
V3Number& setZero();
|
||
V3Number& setQuad(vluint64_t value);
|
||
V3Number& setLong(uint32_t value);
|
||
V3Number& setLongS(vlsint32_t value);
|
||
V3Number& setDouble(double value);
|
||
void setBit (int bit, char value) { // Note must be pre-zeroed!
|
||
if (bit>=m_width) return;
|
||
uint32_t mask = (1UL<<(bit&31));
|
||
if (value=='0' || value==0) {
|
||
m_value [bit/32] &= ~mask;
|
||
m_valueX[bit/32] &= ~mask;
|
||
} else if (value=='1'|| value==1) {
|
||
m_value [bit/32] |= mask;
|
||
m_valueX[bit/32] &= ~mask;
|
||
} else if (value=='z'|| value==2) {
|
||
m_value [bit/32] &= ~mask;
|
||
m_valueX[bit/32] |= mask;
|
||
} else { // X
|
||
m_value [bit/32] |= mask;
|
||
m_valueX[bit/32] |= mask;
|
||
}
|
||
}
|
||
private:
|
||
char bitIs (int bit) const {
|
||
if (bit>=m_width || bit<0) {
|
||
// We never sign extend
|
||
return '0';
|
||
}
|
||
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
|
||
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
|
||
char bitIsExtend (int bit, int lbits) const {
|
||
// lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less
|
||
if (bit<0) return '0';
|
||
UASSERT(lbits<=m_width, "Extend of wrong size");
|
||
if (bit>=lbits) {
|
||
bit = lbits ? lbits-1 : 0;
|
||
// We do sign extend
|
||
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
|
||
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] );
|
||
}
|
||
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
|
||
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
|
||
bool bitIs0 (int bit) const {
|
||
if (bit<0) return false;
|
||
if (bit>=m_width) return !bitIsXZ(m_width-1);
|
||
return ( (m_value[bit/32] & (1UL<<(bit&31)))==0 && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||
bool bitIs1 (int bit) const {
|
||
if (bit<0) return false;
|
||
if (bit>=m_width) return false;
|
||
return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||
bool bitIs1Extend (int bit) const {
|
||
if (bit<0) return false;
|
||
if (bit>=m_width) return bitIs1Extend(m_width-1);
|
||
return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||
bool bitIsX (int bit) const {
|
||
if (bit<0) return false;
|
||
if (bit>=m_width) return bitIsZ(m_width-1);
|
||
return ( (m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||
bool bitIsXZ(int bit) const {
|
||
if (bit<0) return false;
|
||
if (bit>=m_width) return bitIsXZ(m_width-1);
|
||
return ( (m_valueX[bit/32] & (1UL<<(bit&31))));
|
||
}
|
||
bool bitIsZ (int bit) const {
|
||
if (bit<0) return false;
|
||
if (bit>=m_width) return bitIsZ(m_width-1);
|
||
return ( (~m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
|
||
uint32_t bitsValue(int lsb, int nbits) const {
|
||
uint32_t v=0;
|
||
for (int bitn=0; bitn<nbits; bitn++) { v |= (bitIs1(lsb+bitn)<<bitn); }
|
||
return v;
|
||
}
|
||
|
||
int words() const { return ((width()+31)/32); }
|
||
uint32_t hiWordMask() const { return VL_MASK_I(width()); }
|
||
|
||
V3Number& opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus);
|
||
|
||
public:
|
||
// CONSTRUCTORS
|
||
explicit V3Number(FileLine* fileline) { init(fileline, 1); }
|
||
V3Number(FileLine* fileline, int width) { init(fileline, width); } // 0=unsized
|
||
V3Number(FileLine* fileline, int width, uint32_t value) { init(fileline, width); m_value[0]=value; opCleanThis(); }
|
||
V3Number(FileLine* fileline, const char* source); // Create from a verilog 32'hxxxx number.
|
||
class VerilogStringLiteral {}; // for creator type-overload selection
|
||
V3Number(VerilogStringLiteral, FileLine* fileline, const string& vvalue);
|
||
class String {};
|
||
V3Number(String, FileLine* fileline, const string& value) { init(fileline, 0); setString(value); }
|
||
|
||
private:
|
||
void init(FileLine* fileline, int swidth) {
|
||
m_fileline = fileline;
|
||
m_signed = false;
|
||
m_double = false;
|
||
m_isString = false;
|
||
m_autoExtend = false;
|
||
m_fromString = false;
|
||
width(swidth);
|
||
for (int i=0; i<words(); i++) m_value[i]=m_valueX[i] = 0;
|
||
}
|
||
public:
|
||
void width(int width, bool sized=true) {
|
||
// Set width. Only set m_width here, as we need to tweak vector size
|
||
if (width) { m_sized = sized; m_width=width; }
|
||
else { m_sized = false; m_width=1; }
|
||
if (VL_UNLIKELY(m_value.size() < (unsigned)(words()+1))) {
|
||
m_value.resize(words()+1);
|
||
m_valueX.resize(words()+1);
|
||
}
|
||
}
|
||
|
||
// SETTERS
|
||
V3Number& setAllBitsXRemoved();
|
||
V3Number& setAllBitsX();
|
||
V3Number& setAllBitsZ();
|
||
V3Number& setAllBits0();
|
||
V3Number& setAllBits1();
|
||
V3Number& setMask(int nbits); // IE if nbits=1, then 0b1, if 2->0b11, if 3->0b111 etc
|
||
|
||
// ACCESSORS
|
||
string ascii(bool prefixed=true, bool cleanVerilog=false) const;
|
||
static string quoteNameControls(const string& namein); // Add backslash quotes to strings
|
||
string displayed(FileLine* fl, const string& format) const;
|
||
static bool displayedFmtLegal(char format); // Is this a valid format letter?
|
||
int width() const { return m_width; }
|
||
int widthMin() const; // Minimum width that can represent this number (~== log2(num)+1)
|
||
bool sized() const { return m_sized; }
|
||
bool autoExtend() const { return m_autoExtend; }
|
||
bool isFromString() const { return m_fromString; }
|
||
bool isSigned() const { return m_signed; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
|
||
bool isDouble() const { return m_double; } // Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
|
||
void isDouble(bool flag) { m_double=flag; } // Only if have 64 bit value loaded, and want to indicate it's real
|
||
bool isString() const { return m_isString; }
|
||
void isString(bool flag) { m_isString=flag; }
|
||
bool isNegative() const { return bitIs1(width()-1); }
|
||
bool isFourState() const { for (int i=0;i<words();i++) {if (m_valueX[i]) return true;} return false; }
|
||
bool hasZ() const { for(int i=0;i<words();i++) {if((~m_value[i]) & m_valueX[i]) return true;} return false;}
|
||
bool isAllZ() const { for(int i=0;i<width();i++) { if(!bitIsZ(i)){return false;} } return true; }
|
||
bool isEqZero() const;
|
||
bool isNeqZero() const;
|
||
bool isBitsZero(int msb, int lsb) const;
|
||
bool isEqOne() const;
|
||
bool isEqAllOnes(int optwidth=0) const;
|
||
bool isCaseEq(const V3Number& rhsp) const; // operator==
|
||
bool isLt(const V3Number& rhsp) const; // operator<
|
||
bool isLtXZ(const V3Number& rhsp) const; // operator< with XZ compared
|
||
void isSigned(bool ssigned) { m_signed=ssigned; }
|
||
bool isUnknown() const;
|
||
uint32_t toUInt() const;
|
||
vlsint32_t toSInt() const;
|
||
vluint64_t toUQuad() const;
|
||
vlsint64_t toSQuad() const;
|
||
string toString() const;
|
||
double toDouble() const;
|
||
uint32_t toHash() const;
|
||
uint32_t dataWord(int word) const;
|
||
uint8_t dataByte(int byte) const { return (dataWord(byte/4) >> (8*(byte&3))) & 0xff; }
|
||
uint32_t countOnes() const;
|
||
uint32_t mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
|
||
|
||
// Operators
|
||
bool operator<(const V3Number& rhs) const { return isLtXZ(rhs); }
|
||
|
||
// STATICS
|
||
static int log2b(uint32_t num);
|
||
|
||
typedef V3Number& (*UniopFuncp)(V3Number&);
|
||
typedef V3Number& (*BiopFuncp) (V3Number&, V3Number&);
|
||
|
||
// MATH
|
||
// "this" is the output, as we need the output width before some computations
|
||
V3Number& isTrue (const V3Number& lhs);
|
||
V3Number& opBitsNonX(const V3Number& lhs); // 0/1->1, X/Z->0
|
||
V3Number& opBitsOne (const V3Number& lhs); // 1->1, 0/X/Z->0
|
||
V3Number& opBitsXZ (const V3Number& lhs); // 0/1->0, X/Z->1
|
||
V3Number& opBitsZ (const V3Number& lhs); // Z->1, 0/1/X->0
|
||
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
|
||
//
|
||
V3Number& opAssign (const V3Number& lhs);
|
||
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
|
||
V3Number& opRedOr (const V3Number& lhs);
|
||
V3Number& opRedAnd (const V3Number& lhs);
|
||
V3Number& opRedXor (const V3Number& lhs);
|
||
V3Number& opRedXnor (const V3Number& lhs);
|
||
V3Number& opCountOnes(const V3Number& lhs);
|
||
V3Number& opIsUnknown(const V3Number& lhs);
|
||
V3Number& opOneHot (const V3Number& lhs);
|
||
V3Number& opOneHot0 (const V3Number& lhs);
|
||
V3Number& opCLog2 (const V3Number& lhs);
|
||
V3Number& opClean (const V3Number& lhs, uint32_t bits);
|
||
V3Number& opConcat (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opRepl (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opRepl (const V3Number& lhs, uint32_t rhs);
|
||
V3Number& opStreamL (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opSel (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
|
||
V3Number& opSel (const V3Number& lhs, uint32_t rhs, uint32_t ths);
|
||
V3Number& opSelInto (const V3Number& lhs, const V3Number& lsb, int width);
|
||
V3Number& opSelInto (const V3Number& lhs, int lsb, int width);
|
||
V3Number& opCond (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
|
||
V3Number& opCaseEq (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opWildEq (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opWildNeq (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opBufIf1 (const V3Number& lhs, const V3Number& rhs);
|
||
// "standard" math
|
||
V3Number& opNot (const V3Number& lhs);
|
||
V3Number& opLogNot (const V3Number& lhs);
|
||
V3Number& opLogAnd (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLogOr (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLogIf (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLogIff (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opAbsS (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);
|
||
V3Number& opMulS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||
V3Number& opDiv (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opDivS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||
V3Number& opModDiv (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opModDivS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||
V3Number& opPow (const V3Number& lhs, const V3Number& rhs, bool lsign=false, bool rsign=false);
|
||
V3Number& opPowSU (const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs
|
||
V3Number& opPowSS (const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs
|
||
V3Number& opPowUS (const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs
|
||
V3Number& opAnd (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opChangeXor(const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opXor (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opXnor (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opOr (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opRotR (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opRotL (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits); // Arithmetic w/carry
|
||
V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs);
|
||
// Comparisons
|
||
V3Number& opEq (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opNeq (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opGt (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opGtS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||
V3Number& opGte (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opGteS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||
V3Number& opLt (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLtS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||
V3Number& opLte (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLteS (const V3Number& lhs, const V3Number& rhs); // Signed
|
||
|
||
// "D" - double (aka real) math
|
||
V3Number& opIToRD (const V3Number& lhs);
|
||
V3Number& opRToIS (const V3Number& lhs);
|
||
V3Number& opRToIRoundS (const V3Number& lhs);
|
||
V3Number& opRealToBits (const V3Number& lhs);
|
||
V3Number& opBitsToRealD(const V3Number& lhs);
|
||
V3Number& opNegateD (const V3Number& lhs);
|
||
V3Number& opAddD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opSubD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opMulD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opDivD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opPowD (const V3Number& lhs, const V3Number& rhs);
|
||
// Comparisons
|
||
V3Number& opEqD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opNeqD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opGtD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opGteD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLtD (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLteD (const V3Number& lhs, const V3Number& rhs);
|
||
|
||
// "N" - string operations
|
||
V3Number& opConcatN (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opReplN (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opReplN (const V3Number& lhs, uint32_t rhs);
|
||
V3Number& opEqN (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opNeqN (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opGtN (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opGteN (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLtN (const V3Number& lhs, const V3Number& rhs);
|
||
V3Number& opLteN (const V3Number& lhs, const V3Number& rhs);
|
||
};
|
||
inline ostream& operator<<(ostream& os, V3Number rhs) { return os<<rhs.ascii(); }
|
||
|
||
#endif // Guard
|