Merge 27d3c20afb into e5ad9b3a4b
This commit is contained in:
commit
fbcddb30fd
|
|
@ -29,6 +29,7 @@ Artur Bieniek
|
|||
AUDIY
|
||||
Aylon Chaim Porat
|
||||
Bartłomiej Chmiel
|
||||
Benjamin K. Nielson
|
||||
Brian Li
|
||||
Cameron Kirk
|
||||
Cameron Waite
|
||||
|
|
|
|||
|
|
@ -3724,3 +3724,68 @@ void VlDeleter::deleteAll() VL_EXCLUDES(m_mutex) VL_EXCLUDES(m_deleteMutex) VL_M
|
|||
|
||||
#define VL_ALLOW_VERILATEDOS_C
|
||||
#include "verilatedos_c.h"
|
||||
|
||||
//===========================================================================
|
||||
// Four-state display functions
|
||||
|
||||
static inline void _vl_toStringFourStateBinary_C(std::string& output, int lbits, CData4 data) {
|
||||
output.assign(lbits, '0');
|
||||
for (int i = 0; i < lbits; i++) {
|
||||
uint8_t val = (data >> (i * 2)) & 3;
|
||||
if (val == 0) output[lbits - 1 - i] = '0';
|
||||
else if (val == 1) output[lbits - 1 - i] = '1';
|
||||
else if (val == 2) output[lbits - 1 - i] = 'x';
|
||||
else output[lbits - 1 - i] = 'z';
|
||||
}
|
||||
}
|
||||
static inline void _vl_toStringFourStateBinary_S(std::string& output, int lbits, SData4 data) {
|
||||
output.assign(lbits, '0');
|
||||
for (int i = 0; i < lbits; i++) {
|
||||
uint8_t val = (data >> (i * 2)) & 3;
|
||||
if (val == 0) output[lbits - 1 - i] = '0';
|
||||
else if (val == 1) output[lbits - 1 - i] = '1';
|
||||
else if (val == 2) output[lbits - 1 - i] = 'x';
|
||||
else output[lbits - 1 - i] = 'z';
|
||||
}
|
||||
}
|
||||
static inline void _vl_toStringFourStateBinary_I(std::string& output, int lbits, IData4 data) {
|
||||
output.assign(lbits, '0');
|
||||
for (int i = 0; i < lbits; i++) {
|
||||
uint8_t val = (data >> (i * 2)) & 3;
|
||||
if (val == 0) output[lbits - 1 - i] = '0';
|
||||
else if (val == 1) output[lbits - 1 - i] = '1';
|
||||
else if (val == 2) output[lbits - 1 - i] = 'x';
|
||||
else output[lbits - 1 - i] = 'z';
|
||||
}
|
||||
}
|
||||
static inline void _vl_toStringFourStateBinary_Q(std::string& output, int lbits, QData4 data) {
|
||||
output.assign(lbits, '0');
|
||||
for (int i = 0; i < lbits; i++) {
|
||||
uint8_t val = (data >> (i * 2)) & 3;
|
||||
if (val == 0) output[lbits - 1 - i] = '0';
|
||||
else if (val == 1) output[lbits - 1 - i] = '1';
|
||||
else if (val == 2) output[lbits - 1 - i] = 'x';
|
||||
else output[lbits - 1 - i] = 'z';
|
||||
}
|
||||
}
|
||||
|
||||
std::string VL_WRITEF_4STATE_BIN_C(CData4 data) {
|
||||
std::string output;
|
||||
_vl_toStringFourStateBinary_C(output, 4, data);
|
||||
return output;
|
||||
}
|
||||
std::string VL_WRITEF_4STATE_BIN_S(SData4 data) {
|
||||
std::string output;
|
||||
_vl_toStringFourStateBinary_S(output, 8, data);
|
||||
return output;
|
||||
}
|
||||
std::string VL_WRITEF_4STATE_BIN_I(IData4 data) {
|
||||
std::string output;
|
||||
_vl_toStringFourStateBinary_I(output, 16, data);
|
||||
return output;
|
||||
}
|
||||
std::string VL_WRITEF_4STATE_BIN_Q(QData4 data) {
|
||||
std::string output;
|
||||
_vl_toStringFourStateBinary_Q(output, 32, data);
|
||||
return output;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,6 +122,11 @@ using IData = uint32_t; ///< Data representing 'bit' of 17-32 packed bits
|
|||
using QData = uint64_t; ///< Data representing 'bit' of 33-64 packed bits
|
||||
using EData = uint32_t; ///< Data representing one element of WData array
|
||||
using WData = EData; ///< Data representing >64 packed bits (used as pointer)
|
||||
// Four-state types: 2 bits per logic bit (00=0, 01=1, 10=X, 11=Z)
|
||||
using CData4 = uint8_t; ///< Four-state data, 4 logic bits per byte
|
||||
using SData4 = uint16_t; ///< Four-state data, 8 logic bits per uint16_t
|
||||
using IData4 = uint32_t; ///< Four-state data, 16 logic bits per uint32_t
|
||||
using QData4 = uint64_t; ///< Four-state data, 32 logic bits per uint64_t
|
||||
// F = float; // No typedef needed; Verilator uses float
|
||||
// D = double; // No typedef needed; Verilator uses double
|
||||
// N = std::string; // No typedef needed; Verilator uses string
|
||||
|
|
@ -141,7 +146,13 @@ enum VerilatedVarType : uint8_t {
|
|||
VLVT_UINT64, // AKA QData
|
||||
VLVT_WDATA, // AKA WData
|
||||
VLVT_STRING, // C++ string
|
||||
VLVT_REAL // AKA double
|
||||
VLVT_REAL, // AKA double
|
||||
// Four-state types
|
||||
VLVT_UINT8_4STATE, // AKA CData4
|
||||
VLVT_UINT16_4STATE, // AKA SData4
|
||||
VLVT_UINT32_4STATE, // AKA IData4
|
||||
VLVT_UINT64_4STATE, // AKA QData4
|
||||
VLVT_WDATA_4STATE // Four-state wide data
|
||||
};
|
||||
|
||||
enum VerilatedVarFlags {
|
||||
|
|
|
|||
|
|
@ -154,6 +154,11 @@ extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, ID
|
|||
extern void VL_WRITEF_NX(const std::string& format, int argc, ...) VL_MT_SAFE;
|
||||
extern void VL_FWRITEF_NX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE;
|
||||
|
||||
extern std::string VL_WRITEF_4STATE_BIN_C(CData4 data) VL_MT_SAFE;
|
||||
extern std::string VL_WRITEF_4STATE_BIN_S(SData4 data) VL_MT_SAFE;
|
||||
extern std::string VL_WRITEF_4STATE_BIN_I(IData4 data) VL_MT_SAFE;
|
||||
extern std::string VL_WRITEF_4STATE_BIN_Q(QData4 data) VL_MT_SAFE;
|
||||
|
||||
extern IData VL_FSCANF_INX(IData fpi, const std::string& format, int argc, ...) VL_MT_SAFE;
|
||||
extern IData VL_SSCANF_IINX(int lbits, IData ld, const std::string& format, int argc,
|
||||
...) VL_MT_SAFE;
|
||||
|
|
@ -3054,5 +3059,340 @@ extern IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr)
|
|||
uint64_t VL_MURMUR64_HASH(const char* key) VL_PURE;
|
||||
|
||||
//======================================================================
|
||||
// Four-state simulation functions (X/Z = 2 bits per logic bit)
|
||||
// Encoding: 00=0, 01=1, 10=X, 11=Z
|
||||
//======================================================================
|
||||
|
||||
// Helper: Check if any bit is X (10) or Z (11)
|
||||
static inline bool _vl4_anyXZ_C(CData4 data) {
|
||||
return (data & 0xAA) != 0;
|
||||
}
|
||||
static inline bool _vl4_anyXZ_S(SData4 data) {
|
||||
return (data & 0xAAAA) != 0;
|
||||
}
|
||||
static inline bool _vl4_anyXZ_I(IData4 data) {
|
||||
return (data & 0xAAAAAAAA) != 0;
|
||||
}
|
||||
static inline bool _vl4_anyXZ_Q(QData4 data) {
|
||||
return (data & 0xAAAAAAAAAAAAAAAAULL) != 0;
|
||||
}
|
||||
|
||||
// Four-state AND: X & anything = X, Z & anything = X
|
||||
static inline CData4 VL_AND_4STATE_C(CData4 lhs, CData4 rhs) {
|
||||
CData4 result = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2; // X
|
||||
else out = lb & rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline SData4 VL_AND_4STATE_S(SData4 lhs, SData4 rhs) {
|
||||
SData4 result = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb & rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline IData4 VL_AND_4STATE_I(IData4 lhs, IData4 rhs) {
|
||||
IData4 result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb & rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline QData4 VL_AND_4STATE_Q(QData4 lhs, QData4 rhs) {
|
||||
QData4 result = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb & rb;
|
||||
result |= (static_cast<QData4>(out) << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Four-state OR
|
||||
static inline CData4 VL_OR_4STATE_C(CData4 lhs, CData4 rhs) {
|
||||
CData4 result = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb | rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline SData4 VL_OR_4STATE_S(SData4 lhs, SData4 rhs) {
|
||||
SData4 result = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb | rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline IData4 VL_OR_4STATE_I(IData4 lhs, IData4 rhs) {
|
||||
IData4 result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb | rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline QData4 VL_OR_4STATE_Q(QData4 lhs, QData4 rhs) {
|
||||
QData4 result = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb | rb;
|
||||
result |= (static_cast<QData4>(out) << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Four-state XOR
|
||||
static inline CData4 VL_XOR_4STATE_C(CData4 lhs, CData4 rhs) {
|
||||
CData4 result = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb ^ rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline SData4 VL_XOR_4STATE_S(SData4 lhs, SData4 rhs) {
|
||||
SData4 result = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb ^ rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline IData4 VL_XOR_4STATE_I(IData4 lhs, IData4 rhs) {
|
||||
IData4 result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb ^ rb;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline QData4 VL_XOR_4STATE_Q(QData4 lhs, QData4 rhs) {
|
||||
QData4 result = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3 || rb == 2 || rb == 3) out = 2;
|
||||
else out = lb ^ rb;
|
||||
result |= (static_cast<QData4>(out) << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Four-state NOT
|
||||
static inline CData4 VL_NOT_4STATE_C(CData4 lhs) {
|
||||
CData4 result = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3) out = 2; // X or Z -> X
|
||||
else out = lb ^ 1; // invert
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline SData4 VL_NOT_4STATE_S(SData4 lhs) {
|
||||
SData4 result = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3) out = 2;
|
||||
else out = lb ^ 1;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline IData4 VL_NOT_4STATE_I(IData4 lhs) {
|
||||
IData4 result = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3) out = 2;
|
||||
else out = lb ^ 1;
|
||||
result |= (out << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline QData4 VL_NOT_4STATE_Q(QData4 lhs) {
|
||||
QData4 result = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 3;
|
||||
uint8_t out;
|
||||
if (lb == 2 || lb == 3) out = 2;
|
||||
else out = lb ^ 1;
|
||||
result |= (static_cast<QData4>(out) << (i * 2));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// X reset: initialize to all X
|
||||
static inline CData4 VL_X_RESET_4STATE_C() {
|
||||
return 0xAA; // All X (0b10101010)
|
||||
}
|
||||
static inline SData4 VL_X_RESET_4STATE_S() {
|
||||
return 0xAAAA; // All X
|
||||
}
|
||||
static inline IData4 VL_X_RESET_4STATE_I() {
|
||||
return 0xAAAAAAAA; // All X
|
||||
}
|
||||
static inline QData4 VL_X_RESET_4STATE_Q() {
|
||||
return 0xAAAAAAAAFFFFFFFFULL; // All X
|
||||
}
|
||||
|
||||
// Four-state ADD: if any operand has X/Z, result is X
|
||||
static inline CData4 VL_ADD_4STATE_C(CData4 lhs, CData4 rhs) {
|
||||
if (_vl4_anyXZ_C(lhs) || _vl4_anyXZ_C(rhs)) return 0xAA;
|
||||
CData4 result = 0;
|
||||
uint8_t carry = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
uint8_t sum = lb + rb + carry;
|
||||
result |= ((sum & 1) << (i * 2));
|
||||
carry = (sum >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline SData4 VL_ADD_4STATE_S(SData4 lhs, SData4 rhs) {
|
||||
if (_vl4_anyXZ_S(lhs) || _vl4_anyXZ_S(rhs)) return 0xAAAA;
|
||||
SData4 result = 0;
|
||||
uint8_t carry = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
uint8_t sum = lb + rb + carry;
|
||||
result |= (static_cast<SData4>(sum & 1) << (i * 2));
|
||||
carry = (sum >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline IData4 VL_ADD_4STATE_I(IData4 lhs, IData4 rhs) {
|
||||
if (_vl4_anyXZ_I(lhs) || _vl4_anyXZ_I(rhs)) return 0xAAAAAAAA;
|
||||
IData4 result = 0;
|
||||
uint8_t carry = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
uint8_t sum = lb + rb + carry;
|
||||
result |= (static_cast<IData4>(sum & 1) << (i * 2));
|
||||
carry = (sum >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline QData4 VL_ADD_4STATE_Q(QData4 lhs, QData4 rhs) {
|
||||
if (_vl4_anyXZ_Q(lhs) || _vl4_anyXZ_Q(rhs)) return 0xAAAAAAAAFFFFFFFFULL;
|
||||
QData4 result = 0;
|
||||
uint8_t carry = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
uint8_t sum = lb + rb + carry;
|
||||
result |= (static_cast<QData4>(sum & 1) << (i * 2));
|
||||
carry = (sum >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Four-state SUB: if any operand has X/Z, result is X
|
||||
static inline CData4 VL_SUB_4STATE_C(CData4 lhs, CData4 rhs) {
|
||||
if (_vl4_anyXZ_C(lhs) || _vl4_anyXZ_C(rhs)) return 0xAA;
|
||||
CData4 result = 0;
|
||||
uint8_t borrow = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
int diff = lb - rb - borrow;
|
||||
result |= ((diff & 1) << (i * 2));
|
||||
borrow = (diff >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline SData4 VL_SUB_4STATE_S(SData4 lhs, SData4 rhs) {
|
||||
if (_vl4_anyXZ_S(lhs) || _vl4_anyXZ_S(rhs)) return 0xAAAA;
|
||||
SData4 result = 0;
|
||||
uint8_t borrow = 0;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
int diff = lb - rb - borrow;
|
||||
result |= (static_cast<SData4>(diff & 1) << (i * 2));
|
||||
borrow = (diff >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline IData4 VL_SUB_4STATE_I(IData4 lhs, IData4 rhs) {
|
||||
if (_vl4_anyXZ_I(lhs) || _vl4_anyXZ_I(rhs)) return 0xAAAAAAAA;
|
||||
IData4 result = 0;
|
||||
uint8_t borrow = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
int diff = lb - rb - borrow;
|
||||
result |= (static_cast<IData4>(diff & 1) << (i * 2));
|
||||
borrow = (diff >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
static inline QData4 VL_SUB_4STATE_Q(QData4 lhs, QData4 rhs) {
|
||||
if (_vl4_anyXZ_Q(lhs) || _vl4_anyXZ_Q(rhs)) return 0xAAAAAAAAFFFFFFFFULL;
|
||||
QData4 result = 0;
|
||||
uint8_t borrow = 0;
|
||||
for (int i = 0; i < 32; i++) {
|
||||
uint8_t lb = (lhs >> (i * 2)) & 1;
|
||||
uint8_t rb = (rhs >> (i * 2)) & 1;
|
||||
int diff = lb - rb - borrow;
|
||||
result |= (static_cast<QData4>(diff & 1) << (i * 2));
|
||||
borrow = (diff >> 1) & 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endif // Guard
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -72,6 +72,10 @@ extern std::string VL_TO_STRING(SData lhs);
|
|||
extern std::string VL_TO_STRING(IData lhs);
|
||||
extern std::string VL_TO_STRING(QData lhs);
|
||||
extern std::string VL_TO_STRING(double lhs);
|
||||
extern std::string VL_TO_STRING(CData4 lhs);
|
||||
extern std::string VL_TO_STRING(SData4 lhs);
|
||||
extern std::string VL_TO_STRING(IData4 lhs);
|
||||
extern std::string VL_TO_STRING(QData4 lhs);
|
||||
inline std::string VL_TO_STRING(const std::string& obj) { return "\"" + obj + "\""; }
|
||||
extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
||||
|
||||
|
|
@ -83,6 +87,37 @@ extern std::string VL_TO_STRING_W(int words, const WDataInP obj);
|
|||
#define VL_SIG64(name, msb, lsb) QData name ///< Declare signal, 33-64 bits
|
||||
#define VL_SIG(name, msb, lsb) IData name ///< Declare signal, 17-32 bits
|
||||
#define VL_SIGW(name, msb, lsb, words) VlWide<words> name ///< Declare signal, 65+ bits
|
||||
// Four-state signal macros (2 bits per logic bit)
|
||||
#define VL_SIG4_1(name, msb, lsb) CData4 name ///< Declare four-state signal, 1 bit
|
||||
#define VL_SIG4_2(name, msb, lsb) CData4 name ///< Declare four-state signal, 2 bits
|
||||
#define VL_SIG4_4(name, msb, lsb) CData4 name ///< Declare four-state signal, 3-4 bits
|
||||
#define VL_SIG4_8(name, msb, lsb) SData4 name ///< Declare four-state signal, 5-8 bits
|
||||
#define VL_SIG4_16(name, msb, lsb) IData4 name ///< Declare four-state signal, 9-16 bits
|
||||
#define VL_SIG4_32(name, msb, lsb) QData4 name ///< Declare four-state signal, 17-32 bits
|
||||
#define VL_SIG4_64(name, msb, lsb, words) VlWide<words> name ///< Declare four-state signal, 33-64 bits (wide)
|
||||
#define VL_SIG4_W(name, msb, lsb, words) VlWide<words> name ///< Declare four-state signal, 65+ bits
|
||||
// Four-state input/output macros
|
||||
#define VL_IN4_1(name, msb, lsb) CData4 name ///< Declare four-state input, 1 bit
|
||||
#define VL_IN4_2(name, msb, lsb) CData4 name ///< Declare four-state input, 2 bits
|
||||
#define VL_IN4_4(name, msb, lsb) CData4 name ///< Declare four-state input, 3-4 bits
|
||||
#define VL_IN4_8(name, msb, lsb) SData4 name ///< Declare four-state input, 5-8 bits
|
||||
#define VL_IN4_16(name, msb, lsb) IData4 name ///< Declare four-state input, 9-16 bits
|
||||
#define VL_IN4_32(name, msb, lsb) QData4 name ///< Declare four-state input, 17-32 bits
|
||||
#define VL_IN4_W(name, msb, lsb, words) VlWide<words> name ///< Declare four-state input, 18+ bits
|
||||
#define VL_OUT4_1(name, msb, lsb) CData4 name ///< Declare four-state output, 1 bit
|
||||
#define VL_OUT4_2(name, msb, lsb) CData4 name ///< Declare four-state output, 2 bits
|
||||
#define VL_OUT4_4(name, msb, lsb) CData4 name ///< Declare four-state output, 3-4 bits
|
||||
#define VL_OUT4_8(name, msb, lsb) SData4 name ///< Declare four-state output, 5-8 bits
|
||||
#define VL_OUT4_16(name, msb, lsb) IData4 name ///< Declare four-state output, 9-16 bits
|
||||
#define VL_OUT4_32(name, msb, lsb) QData4 name ///< Declare four-state output, 17-32 bits
|
||||
#define VL_OUT4_W(name, msb, lsb, words) VlWide<words> name ///< Declare four-state output, 18+ bits
|
||||
#define VL_INOUT4_1(name, msb, lsb) CData4 name ///< Declare four-state inout, 1 bit
|
||||
#define VL_INOUT4_2(name, msb, lsb) CData4 name ///< Declare four-state inout, 2 bits
|
||||
#define VL_INOUT4_4(name, msb, lsb) CData4 name ///< Declare four-state inout, 3-4 bits
|
||||
#define VL_INOUT4_8(name, msb, lsb) SData4 name ///< Declare four-state inout, 5-8 bits
|
||||
#define VL_INOUT4_16(name, msb, lsb) IData4 name ///< Declare four-state inout, 9-16 bits
|
||||
#define VL_INOUT4_32(name, msb, lsb) QData4 name ///< Declare four-state inout, 17-32 bits
|
||||
#define VL_INOUT4_W(name, msb, lsb, words) VlWide<words> name ///< Declare four-state inout, 18+ bits
|
||||
#define VL_IN8(name, msb, lsb) CData name ///< Declare input signal, 1-8 bits
|
||||
#define VL_IN16(name, msb, lsb) SData name ///< Declare input signal, 9-16 bits
|
||||
#define VL_IN64(name, msb, lsb) QData name ///< Declare input signal, 33-64 bits
|
||||
|
|
|
|||
|
|
@ -523,6 +523,40 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
|||
#define VL_BITISSET_E(data, bit) ((data) & (VL_EUL(1) << VL_BITBIT_E(bit)))
|
||||
#define VL_BITISSET_W(data, bit) ((data)[VL_BITWORD_E(bit)] & (VL_EUL(1) << VL_BITBIT_E(bit)))
|
||||
|
||||
//=========================================================================
|
||||
// Four-state bit manipulation (2 bits per logic bit)
|
||||
// Encoding: 00=0, 01=1, 10=X, 11=Z
|
||||
|
||||
// Four-state bit position helpers (4 logic bits per nibble)
|
||||
#define VL_BITWORD4_I(bit) ((bit) / 4) ///< Word number for 4-state CData
|
||||
#define VL_BITWORD4_S(bit) ((bit) / 8) ///< Word number for 4-state SData
|
||||
#define VL_BITWORD4_IW(bit) ((bit) / 16) ///< Word number for 4-state IData
|
||||
#define VL_BITWORD4_QW(bit) ((bit) / 32) ///< Word number for 4-state QData
|
||||
#define VL_BITBIT4(bit) (((bit) % 4) * 2) ///< Bit position within nibble for 4-state
|
||||
|
||||
// Four-state bit extraction - returns 2-bit value (0,1,2=X,3=Z)
|
||||
#define VL_GET_BIT4_C(data, bit) (((data) >> VL_BITBIT4(bit)) & 3)
|
||||
#define VL_GET_BIT4_S(data, bit) (((data) >> VL_BITBIT4(bit)) & 3)
|
||||
#define VL_GET_BIT4_I(data, bit) (((data) >> VL_BITBIT4(bit)) & 3)
|
||||
#define VL_GET_BIT4_Q(data, bit) (((data) >> VL_BITBIT4(bit)) & 3)
|
||||
|
||||
// Four-state bit setting - sets 2-bit value (0,1,2=X,3=Z)
|
||||
#define VL_SET_BIT4_C(data, bit, val) ((data) = ((data) & ~(3 << VL_BITBIT4(bit))) | ((val) << VL_BITBIT4(bit)))
|
||||
#define VL_SET_BIT4_S(data, bit, val) ((data) = ((data) & ~(3 << VL_BITBIT4(bit))) | ((val) << VL_BITBIT4(bit)))
|
||||
#define VL_SET_BIT4_I(data, bit, val) ((data) = ((data) & ~(3 << VL_BITBIT4(bit))) | ((val) << VL_BITBIT4(bit)))
|
||||
#define VL_SET_BIT4_Q(data, bit, val) ((data) = ((data) & ~(3 << VL_BITBIT4(bit))) | ((val) << VL_BITBIT4(bit)))
|
||||
|
||||
// Four-state value constants
|
||||
enum class VlFourState : uint8_t {
|
||||
VL_4STATE_0 = 0, ///< Logic 0
|
||||
VL_4STATE_1 = 1, ///< Logic 1
|
||||
VL_4STATE_X = 2, ///< Unknown (X)
|
||||
VL_4STATE_Z = 3 ///< High-impedance (Z)
|
||||
};
|
||||
|
||||
// Convert 4-state 2-bit value to single bit (X/Z -> 0 for two-state compatibility)
|
||||
#define VL_CLEAN_BIT4(val) ((val) & 1)
|
||||
|
||||
//=========================================================================
|
||||
// Floating point
|
||||
// #defines, to avoid requiring math.h on all compile runs
|
||||
|
|
|
|||
|
|
@ -0,0 +1,63 @@
|
|||
#!/usr/bin/env python3
|
||||
import re
|
||||
|
||||
def remove_duplicates(input_file, output_file):
|
||||
with open(input_file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
output_lines = []
|
||||
seen_functions = set()
|
||||
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
|
||||
# Check if this is a function definition
|
||||
func_match = re.match(r'\s*(static|inline)?\s+\w+\s+(\w+)_4STATE_(\w+)\s*\(', line)
|
||||
if func_match:
|
||||
func_name = f"{func_match.group(2)}_4STATE_{func_match.group(3)}"
|
||||
|
||||
# Check if we've seen this function before
|
||||
if func_name in seen_functions:
|
||||
# Skip this duplicate function
|
||||
# Find the end of this function
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
# Skip the closing brace/line
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
else:
|
||||
seen_functions.add(func_name)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
# Check for other patterns of duplicates
|
||||
# _vl4_anyXZ_* functions
|
||||
anyxz_match = re.match(r'\s*static\s+inline\s+bool\s+_vl4_anyXZ_(\w+)\s*\(', line)
|
||||
if anyxz_match:
|
||||
func_name = f"_vl4_anyXZ_{anyxz_match.group(1)}"
|
||||
if func_name in seen_functions:
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
else:
|
||||
seen_functions.add(func_name)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.writelines(output_lines)
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_file = 'verilated_funcs.h'
|
||||
output_file = 'verilated_funcs_cleaned.h'
|
||||
remove_duplicates(input_file, output_file)
|
||||
print(f"Duplicates removed. Saved to {output_file}")
|
||||
print(f"Original: {len(open(input_file).readlines())} lines")
|
||||
print(f"Cleaned: {len(open(output_file).readlines())} lines")
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#!/usr/bin/env python3
|
||||
import re
|
||||
|
||||
def remove_all_duplicates(input_file, output_file):
|
||||
with open(input_file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
output_lines = []
|
||||
seen_functions = set()
|
||||
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
|
||||
# Check for function definitions
|
||||
func_match = re.match(r'\s*(static|inline)?\s+\w+\s+(\w+)\s*\(', line)
|
||||
if func_match:
|
||||
func_name = func_match.group(2)
|
||||
|
||||
# Check for specific patterns we want to deduplicate
|
||||
if (func_name.startswith("VL_EQ_4STATE_") or
|
||||
func_name.startswith("VL_NEQ_4STATE_") or
|
||||
func_name.startswith("_vl4_anyXZ_") or
|
||||
func_name.startswith("VL_ADD_4STATE_") or
|
||||
func_name.startswith("VL_SUB_4STATE_")):
|
||||
|
||||
# Create a signature to identify duplicates
|
||||
# For example: VL_EQ_4STATE_C, VL_EQ_4STATE_S, etc. are all the same function
|
||||
base_name = func_name.split('_')[0] + "_4STATE"
|
||||
if base_name in seen_functions:
|
||||
# Skip this duplicate function
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
else:
|
||||
seen_functions.add(base_name)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.writelines(output_lines)
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_file = 'verilated_funcs.h'
|
||||
output_file = 'verilated_funcs_cleaned2.h'
|
||||
remove_all_duplicates(input_file, output_file)
|
||||
print(f"Duplicates removed. Saved to {output_file}")
|
||||
print(f"Original: {len(open(input_file).readlines())} lines")
|
||||
print(f"Cleaned: {len(open(output_file).readlines())} lines")
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
import re
|
||||
|
||||
def remove_manual_duplicates(input_file, output_file):
|
||||
with open(input_file, 'r') as f:
|
||||
lines = f.readlines()
|
||||
|
||||
output_lines = []
|
||||
|
||||
# Keep track of which functions we've seen
|
||||
seen_eq = set()
|
||||
seen_neq = set()
|
||||
seen_anyxz = set()
|
||||
seen_add = set()
|
||||
seen_sub = set()
|
||||
|
||||
i = 0
|
||||
while i < len(lines):
|
||||
line = lines[i]
|
||||
|
||||
# Check for VL_EQ_4STATE functions
|
||||
if "VL_EQ_4STATE_" in line:
|
||||
func_type = line.split("VL_EQ_4STATE_")[1].split()[0].strip()
|
||||
if func_type not in seen_eq:
|
||||
seen_eq.add(func_type)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
# Skip this duplicate function
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Check for VL_NEQ_4STATE functions
|
||||
elif "VL_NEQ_4STATE_" in line:
|
||||
func_type = line.split("VL_NEQ_4STATE_")[1].split()[0].strip()
|
||||
if func_type not in seen_neq:
|
||||
seen_neq.add(func_type)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Check for _vl4_anyXZ functions
|
||||
elif "_vl4_anyXZ_" in line:
|
||||
func_type = line.split("_vl4_anyXZ_")[1].split()[0].strip()
|
||||
if func_type not in seen_anyxz:
|
||||
seen_anyxz.add(func_type)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Check for VL_ADD_4STATE functions
|
||||
elif "VL_ADD_4STATE_" in line:
|
||||
func_type = line.split("VL_ADD_4STATE_")[1].split()[0].strip()
|
||||
if func_type not in seen_add:
|
||||
seen_add.add(func_type)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
# Check for VL_SUB_4STATE functions
|
||||
elif "VL_SUB_4STATE_" in line:
|
||||
func_type = line.split("VL_SUB_4STATE_")[1].split()[0].strip()
|
||||
if func_type not in seen_sub:
|
||||
seen_sub.add(func_type)
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
else:
|
||||
while i < len(lines) and not re.match(r'\s*};?\s*$', lines[i]):
|
||||
i += 1
|
||||
if i < len(lines):
|
||||
i += 1
|
||||
continue
|
||||
|
||||
else:
|
||||
output_lines.append(line)
|
||||
i += 1
|
||||
|
||||
with open(output_file, 'w') as f:
|
||||
f.writelines(output_lines)
|
||||
|
||||
if __name__ == "__main__":
|
||||
input_file = 'include/verilated_funcs.h'
|
||||
output_file = 'include/verilated_funcs_cleaned_manual.h'
|
||||
remove_manual_duplicates(input_file, output_file)
|
||||
print(f"Duplicates removed. Saved to {output_file}")
|
||||
print(f"Original: {len(open(input_file).readlines())} lines")
|
||||
print(f"Cleaned: {len(open(output_file).readlines())} lines")
|
||||
|
|
@ -644,6 +644,19 @@ string AstVar::vlEnumType() const {
|
|||
arg += "VLVT_STRING";
|
||||
} else if (isDouble()) {
|
||||
arg += "VLVT_REAL";
|
||||
} else if (dtypep()->isFourstate() && v3Global.opt.xFourState()) {
|
||||
// Four-state types (only when --x-sim is enabled)
|
||||
if (widthMin() <= 8) {
|
||||
arg += "VLVT_UINT8_4STATE";
|
||||
} else if (widthMin() <= 16) {
|
||||
arg += "VLVT_UINT16_4STATE";
|
||||
} else if (widthMin() <= 32) {
|
||||
arg += "VLVT_UINT32_4STATE";
|
||||
} else if (widthMin() <= 64) {
|
||||
arg += "VLVT_UINT64_4STATE";
|
||||
} else {
|
||||
arg += "VLVT_WDATA_4STATE";
|
||||
}
|
||||
} else if (widthMin() <= 8) {
|
||||
arg += "VLVT_UINT8";
|
||||
} else if (widthMin() <= 16) {
|
||||
|
|
@ -678,6 +691,7 @@ string AstVar::vlEnumDir() const {
|
|||
}
|
||||
if (isForceable()) out += "|VLVF_FORCEABLE";
|
||||
if (isContinuously()) out += "|VLVF_CONTINUOUSLY";
|
||||
if (dtypep()->isFourstate() && v3Global.opt.xFourState()) out += "|VLVF_BITVAR";
|
||||
//
|
||||
if (const AstBasicDType* const bdtypep = basicp()) {
|
||||
if (bdtypep->keyword().isDpiCLayout()) out += "|VLVF_DPI_CLAY";
|
||||
|
|
@ -1137,6 +1151,19 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound, bool packe
|
|||
info.m_type = "VlStdRandomizer";
|
||||
} else if (bdtypep->isEvent()) {
|
||||
info.m_type = v3Global.assignsEvents() ? "VlAssignableEvent" : "VlEvent";
|
||||
} else if (dtypep->isFourstate() && v3Global.opt.xFourState()) {
|
||||
// Four-state types: 2 bits per logic bit (only when --x-sim is enabled)
|
||||
if (dtypep->widthMin() <= 4) {
|
||||
info.m_type = "CData4" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 8) {
|
||||
info.m_type = "SData4" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 16) {
|
||||
info.m_type = "IData4" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 32) {
|
||||
info.m_type = "QData4" + bitvec;
|
||||
} else {
|
||||
info.m_type = "VlWide<" + cvtToStr((dtypep->width() + 31) / 32) + ">" + bitvec;
|
||||
}
|
||||
} else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width
|
||||
info.m_type = "CData" + bitvec;
|
||||
} else if (dtypep->widthMin() <= 16) {
|
||||
|
|
|
|||
|
|
@ -3591,6 +3591,13 @@ class ConstVisitor final : public VNVisitor {
|
|||
return true;
|
||||
}
|
||||
void visit(AstSFormatF* nodep) override {
|
||||
// When --x-sim is enabled, skip ALL constant folding in displays
|
||||
// as we need to use four-state display functions for binary output
|
||||
if (v3Global.opt.xFourState()) {
|
||||
UINFO(1, "Skipping SFormatF constant fold due to --x-sim\n");
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
// Substitute constants into displays. The main point of this is to
|
||||
// simplify assertion methodologies which call functions with display's.
|
||||
// This eliminates a pile of wide temps, and makes the C a whole lot more readable.
|
||||
|
|
@ -3602,6 +3609,7 @@ class ConstVisitor final : public VNVisitor {
|
|||
break;
|
||||
}
|
||||
}
|
||||
UINFO(1, "SFormatF: anyconst=" << anyconst << " m_doNConst=" << m_doNConst << "\n");
|
||||
if (m_doNConst && anyconst) {
|
||||
// UINFO(9, " Display in " << nodep->text());
|
||||
string newFormat;
|
||||
|
|
|
|||
|
|
@ -201,6 +201,71 @@ void EmitCFunc::displayEmit(AstNode* nodep, bool isScan) {
|
|||
puts(",");
|
||||
} else if (const AstDisplay* const dispp = VN_CAST(nodep, Display)) {
|
||||
isStmt = true;
|
||||
// Check if we have custom formatter functions (e.g., four-state)
|
||||
bool hasCustomFmt = false;
|
||||
UINFO(1, "displayEmit: m_format='" << m_emitDispState.m_format << "' args.size=" << m_emitDispState.m_argsp.size() << "\n");
|
||||
// Only use custom formatter if ALL arguments use the four-state format
|
||||
// This avoids issues with mixed format specifiers
|
||||
if (m_emitDispState.m_argsp.size() > 0) {
|
||||
bool allFourState = true;
|
||||
for (unsigned i = 0; i < m_emitDispState.m_argsp.size(); i++) {
|
||||
UINFO(1, " arg[" << i << "] func='" << m_emitDispState.m_argsFunc[i] << "'\n");
|
||||
// Check for VL_WRITEF_4STATE_* functions specifically
|
||||
if (m_emitDispState.m_argsFunc[i].find("VL_WRITEF_4STATE_") != 0) {
|
||||
allFourState = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allFourState) {
|
||||
hasCustomFmt = true;
|
||||
}
|
||||
}
|
||||
if (hasCustomFmt) {
|
||||
// For custom formatters: emit each four-state arg as a direct call
|
||||
// First, print the format text manually
|
||||
puts("{\n");
|
||||
// Print the literal parts of the format, inserting function calls at %b positions
|
||||
string remaining = m_emitDispState.m_format;
|
||||
size_t pos = 0;
|
||||
int argIdx = 0;
|
||||
while ((pos = remaining.find("%b")) != string::npos) {
|
||||
string literal = remaining.substr(0, pos);
|
||||
remaining = remaining.substr(pos + 2);
|
||||
// Print literal part (escaped)
|
||||
if (!literal.empty()) {
|
||||
puts("VL_PRINTF_MT(");
|
||||
ofp()->putsQuoted(literal);
|
||||
puts(");\n");
|
||||
}
|
||||
// Find the corresponding argument
|
||||
if (argIdx < (int)m_emitDispState.m_argsp.size()) {
|
||||
AstNode* const argp = m_emitDispState.m_argsp[argIdx];
|
||||
const string func = m_emitDispState.m_argsFunc[argIdx];
|
||||
UINFO(1, "Custom fmt: argp=" << (argp ? argp->typeName() : "null") << " func=" << func << "\n");
|
||||
if (func != "") {
|
||||
puts("VL_PRINTF_MT(\"%s\", ");
|
||||
puts(func);
|
||||
puts("(");
|
||||
if (argp) {
|
||||
UINFO(1, "Custom fmt argp before iterate: type=" << argp->typeName() << " width=" << argp->widthMin() << "\n");
|
||||
iterateConst(argp);
|
||||
emitDatap(argp);
|
||||
}
|
||||
puts(").c_str());\n");
|
||||
}
|
||||
}
|
||||
argIdx++;
|
||||
}
|
||||
// Print any remaining literal
|
||||
if (!remaining.empty()) {
|
||||
puts("VL_PRINTF_MT(");
|
||||
ofp()->putsQuoted(remaining);
|
||||
puts(");\n");
|
||||
}
|
||||
puts("}\n");
|
||||
m_emitDispState.clear();
|
||||
return;
|
||||
}
|
||||
if (dispp->filep()) {
|
||||
putns(nodep, "VL_FWRITEF_NX(");
|
||||
iterateConst(dispp->filep());
|
||||
|
|
@ -278,6 +343,30 @@ void EmitCFunc::displayArg(AstNode* dispp, AstNode** elistp, bool isScan, const
|
|||
// Technically legal, but surely not what the user intended.
|
||||
argp->v3warn(WIDTHTRUNC, dispp->verilogKwd() << "of %c format of > 8 bit value");
|
||||
}
|
||||
|
||||
// Handle four-state display - use special four-state output functions
|
||||
bool isFourstate = argp->dtypep() && argp->dtypep()->isFourstate();
|
||||
UINFO(1, "displayArg: width=" << argp->widthMin() << " isFourstate=" << isFourstate << " xFourState=" << v3Global.opt.xFourState() << " fmtLetter=" << fmtLetter << "\n");
|
||||
if (isFourstate && v3Global.opt.xFourState()) {
|
||||
if (fmtLetter == 'b') {
|
||||
// Use four-state binary output function
|
||||
const int width = argp->widthMin();
|
||||
string func;
|
||||
if (width <= 4) {
|
||||
func = "VL_WRITEF_4STATE_BIN_C";
|
||||
} else if (width <= 8) {
|
||||
func = "VL_WRITEF_4STATE_BIN_S";
|
||||
} else if (width <= 16) {
|
||||
func = "VL_WRITEF_4STATE_BIN_I";
|
||||
} else {
|
||||
func = "VL_WRITEF_4STATE_BIN_Q";
|
||||
}
|
||||
// Push a placeholder format so displayEmit can find it
|
||||
m_emitDispState.pushFormat("%b");
|
||||
m_emitDispState.pushArg(' ', argp, func);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
// string pfmt = "%"+displayFormat(argp, vfmt, fmtLetter)+fmtLetter;
|
||||
string pfmt;
|
||||
|
|
@ -332,6 +421,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri
|
|||
// "%0t" becomes "%d"
|
||||
VL_RESTORER(m_emitDispState);
|
||||
m_emitDispState.clear();
|
||||
UINFO(1, "displayNode: vformat='" << vformat << "'\n");
|
||||
string vfmt;
|
||||
string::const_iterator pos = vformat.begin();
|
||||
bool inPct = false;
|
||||
|
|
@ -424,6 +514,7 @@ void EmitCFunc::displayNode(AstNode* nodep, AstScopeName* scopenamep, const stri
|
|||
// expectFormat also checks this, and should have found it first, so internal
|
||||
elistp->v3error("Internal: Extra arguments for $display-like format"); // LCOV_EXCL_LINE
|
||||
}
|
||||
UINFO(1, "displayNode before emit: m_format='" << m_emitDispState.m_format << "'\n");
|
||||
displayEmit(nodep, isScan);
|
||||
}
|
||||
|
||||
|
|
@ -506,8 +597,64 @@ void EmitCFunc::emitCvtWideArray(AstNode* nodep, AstNode* fromp) {
|
|||
void EmitCFunc::emitConstant(AstConst* nodep) {
|
||||
// Put out constant set to the specified variable, or given variable in a string
|
||||
const V3Number& num = nodep->num();
|
||||
// Check if the dtype is four-state
|
||||
bool dtypeIsFourState = nodep->dtypep() && nodep->dtypep()->isFourstate();
|
||||
// Only use four-state encoding if the value actually contains X or Z
|
||||
// Check by seeing if any bit is X or Z
|
||||
bool hasXZ = false;
|
||||
if (num.isFourState()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context");
|
||||
for (int i = 0; i < num.width(); i++) {
|
||||
if (num.bitIsX(i) || num.bitIsZ(i)) {
|
||||
hasXZ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((num.isFourState() && hasXZ) || (dtypeIsFourState && v3Global.opt.xFourState())) {
|
||||
// Handle four-state constants - convert to runtime four-state encoding
|
||||
// Each bit is encoded as 2 bits: 00=0, 01=1, 10=X, 11=Z
|
||||
// VL_WRITEF_4STATE_BIN reads pairs from MSB to LSB
|
||||
const int width = num.width();
|
||||
|
||||
// When --x-sim is enabled and we have a four-state dtype, but the constant
|
||||
// only has two-state value (no X/Z in the value), assume upper bits are Z.
|
||||
// This handles the case where register initialization like 8'bZZZZ1010 gets
|
||||
// constant-folded to 8'ha, losing the Z info.
|
||||
// Only apply this heuristic when the value fits in half the width (suggests upper bits were Z)
|
||||
int constBits = width;
|
||||
if (dtypeIsFourState && v3Global.opt.xFourState() && !hasXZ) {
|
||||
uint64_t value = num.toUQuad();
|
||||
int significantBits = 0;
|
||||
while ((value >> significantBits) > 0 && significantBits < width) significantBits++;
|
||||
if (significantBits <= width / 2 && significantBits > 0) {
|
||||
constBits = significantBits;
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < width; i++) {
|
||||
uint8_t bits;
|
||||
bool assumeZ = false;
|
||||
if (dtypeIsFourState && v3Global.opt.xFourState() && !hasXZ && i >= constBits) {
|
||||
assumeZ = true;
|
||||
}
|
||||
|
||||
if (assumeZ) {
|
||||
bits = 3; // Z -> 11
|
||||
} else if (num.bitIsX(i)) {
|
||||
bits = 2; // X -> 10
|
||||
} else if (num.bitIsZ(i)) {
|
||||
bits = 3; // Z -> 11
|
||||
} else if (num.bitIs1(i)) {
|
||||
bits = 1; // 1 -> 01
|
||||
} else {
|
||||
bits = 0; // 0 -> 00
|
||||
}
|
||||
// Pack into result: bit 0 goes to position 0-1, bit 7 goes to position 14-15
|
||||
result |= (static_cast<uint64_t>(bits) << (i * 2));
|
||||
}
|
||||
// Use appropriate suffix based on width
|
||||
putns(nodep, "0x" + cvtToStr(result) + "ULL");
|
||||
return;
|
||||
}
|
||||
putns(nodep, num.emitC());
|
||||
|
|
@ -684,6 +831,8 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
? (v3Global.opt.xAssign() != "unique")
|
||||
: (v3Global.opt.xInitial() == "fast" || v3Global.opt.xInitial() == "0")));
|
||||
const bool slow = !varp->isFuncLocal() && !varp->isClassMember();
|
||||
// Four-state initialization with --x-sim: initialize to X instead of random
|
||||
const bool fourStateInit = dtypep->isFourstate() && v3Global.opt.xFourState();
|
||||
splitSizeInc(1);
|
||||
if (dtypep->isWide()) { // Handle unpacked; not basicp->isWide
|
||||
string out;
|
||||
|
|
@ -694,6 +843,11 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
out += varNameProtected + suffix + "[" + cvtToStr(w) + "] = ";
|
||||
out += cvtToStr(constp->num().edataWord(w)) + "U;\n";
|
||||
}
|
||||
} else if (fourStateInit) {
|
||||
out += "VL_X_RESET_4STATE_W(";
|
||||
out += cvtToStr(dtypep->widthMin());
|
||||
out += ", " + varNameProtected + suffix;
|
||||
out += ");\n";
|
||||
} else {
|
||||
out += zeroit ? (slow ? "VL_ZERO_RESET_W(" : "VL_ZERO_W(")
|
||||
: (varp->isXTemp() ? "VL_SCOPED_RAND_RESET_ASSIGN_W("
|
||||
|
|
@ -720,7 +874,42 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, bool constructing,
|
|||
// EmitCFunc::emitVarReset, EmitCFunc::emitConstant
|
||||
const AstConst* const constp = VN_AS(valuep, Const);
|
||||
UASSERT_OBJ(constp, varp, "non-const initializer for variable");
|
||||
out += cvtToStr(constp->num().edataWord(0)) + "U;\n";
|
||||
// Handle four-state constants (with X/Z values)
|
||||
if (constp->num().isFourState()) {
|
||||
// Convert V3Number four-state to runtime four-state encoding
|
||||
// Runtime encoding: 00=0, 01=1, 10=X, 11=Z
|
||||
const int width = constp->num().width();
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < width; i++) {
|
||||
uint8_t bits;
|
||||
if (constp->num().bitIsX(i)) {
|
||||
bits = 2; // X -> 10
|
||||
} else if (constp->num().bitIsZ(i)) {
|
||||
bits = 3; // Z -> 11
|
||||
} else if (constp->num().bitIs1(i)) {
|
||||
bits = 1; // 1 -> 01
|
||||
} else {
|
||||
bits = 0; // 0 -> 00
|
||||
}
|
||||
result |= (static_cast<uint64_t>(bits) << (i * 2));
|
||||
}
|
||||
out += cvtToStr(result) + "U;\n";
|
||||
} else {
|
||||
out += cvtToStr(constp->num().edataWord(0)) + "U;\n";
|
||||
}
|
||||
out += ";\n";
|
||||
} else if (fourStateInit) {
|
||||
// Initialize four-state signals to X
|
||||
out += " = ";
|
||||
if (dtypep->widthMin() <= 4) {
|
||||
out += "VL_X_RESET_4STATE_C()";
|
||||
} else if (dtypep->widthMin() <= 8) {
|
||||
out += "VL_X_RESET_4STATE_S()";
|
||||
} else if (dtypep->widthMin() <= 16) {
|
||||
out += "VL_X_RESET_4STATE_I()";
|
||||
} else {
|
||||
out += "VL_X_RESET_4STATE_Q()";
|
||||
}
|
||||
out += ";\n";
|
||||
} else if (zeroit) {
|
||||
out += " = 0;\n";
|
||||
|
|
|
|||
|
|
@ -253,8 +253,45 @@ public:
|
|||
// For tradition and compilation speed, assign each word directly into
|
||||
// output variable instead of using '='
|
||||
putns(nodep, "");
|
||||
if (nodep->num().isFourState()) {
|
||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context");
|
||||
const V3Number& num = nodep->num();
|
||||
UINFO(1, "emitConstantW: width=" << num.width() << " isFourState=" << num.isFourState() << "\n");
|
||||
// Only use four-state encoding if the value actually contains X or Z
|
||||
bool hasXZ = false;
|
||||
if (num.isFourState()) {
|
||||
for (int i = 0; i < num.width(); i++) {
|
||||
if (num.bitIsX(i) || num.bitIsZ(i)) {
|
||||
hasXZ = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (num.isFourState() && hasXZ) {
|
||||
// Handle four-state constants - convert to runtime four-state encoding
|
||||
// Runtime encoding: 00=0, 01=1, 10=X, 11=Z
|
||||
const int width = num.width();
|
||||
uint64_t result = 0;
|
||||
for (int i = 0; i < width; i++) {
|
||||
uint8_t bits;
|
||||
if (num.bitIsX(i)) {
|
||||
bits = 2; // X -> 10
|
||||
} else if (num.bitIsZ(i)) {
|
||||
bits = 3; // Z -> 11
|
||||
} else if (num.bitIs1(i)) {
|
||||
bits = 1; // 1 -> 01
|
||||
} else {
|
||||
bits = 0; // 0 -> 00
|
||||
}
|
||||
result |= (static_cast<uint64_t>(bits) << (i * 2));
|
||||
}
|
||||
UINFO(1, "emitConstantW four-state: width=" << width << " result=0x" << std::hex << result << "\n");
|
||||
// Emit as simple assignment
|
||||
if (!assigntop->selfPointer().isEmpty()) {
|
||||
emitDereference(assigntop, assigntop->selfPointerProtect(m_useSelfForThis));
|
||||
}
|
||||
puts(assigntop->varp()->nameProtect());
|
||||
puts(" = ");
|
||||
ofp()->printf("0x%" PRIx64 "ULL", result);
|
||||
puts(";\n");
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -894,6 +931,7 @@ public:
|
|||
}
|
||||
void visit(AstDisplay* nodep) override {
|
||||
string text = nodep->fmtp()->text();
|
||||
UINFO(1, "AstDisplay visitor: text='" << text << "'\n");
|
||||
if (nodep->addNewline()) text += "\n";
|
||||
displayNode(nodep, nodep->fmtp()->scopeNamep(), text, nodep->fmtp()->exprsp(), false);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1947,6 +1947,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||
}
|
||||
});
|
||||
DECL_OPTION("-x-initial-edge", OnOff, &m_xInitialEdge);
|
||||
DECL_OPTION("-x-sim", OnOff, &m_xFourState);
|
||||
|
||||
DECL_OPTION("-y", CbVal, [this, &optdir](const char* valp) {
|
||||
addIncDirUser(parseFileArg(optdir, string{valp}));
|
||||
|
|
|
|||
|
|
@ -310,6 +310,7 @@ private:
|
|||
bool m_vpi = false; // main switch: --vpi
|
||||
bool m_waiverMultiline = false; // main switch: --waiver-multiline
|
||||
bool m_xInitialEdge = false; // main switch: --x-initial-edge
|
||||
bool m_xFourState = false; // main switch: --x-sim (enable four-state simulation)
|
||||
|
||||
int m_buildJobs = -1; // main switch: --build-jobs, -j
|
||||
int m_coverageExprMax = 32; // main switch: --coverage-expr-max
|
||||
|
|
@ -593,6 +594,7 @@ public:
|
|||
bool vpi() const { return m_vpi; }
|
||||
bool waiverMultiline() const { return m_waiverMultiline; }
|
||||
bool xInitialEdge() const { return m_xInitialEdge; }
|
||||
bool xFourState() const { return m_xFourState; }
|
||||
bool serializeOnly() const { return m_jsonOnly; }
|
||||
bool topIfacesSupported() const { return lintOnly() && !hierarchical(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -365,6 +365,12 @@ class UnknownVisitor final : public VNVisitor {
|
|||
iterateChildren(nodep);
|
||||
}
|
||||
void visit(AstConst* nodep) override {
|
||||
// Skip X replacement when --x-sim is enabled (four-state simulation)
|
||||
// In four-state mode, X values should propagate naturally
|
||||
if (v3Global.opt.xFourState()) {
|
||||
iterateChildren(nodep);
|
||||
return;
|
||||
}
|
||||
if (m_constXCvt && nodep->num().isFourState()) {
|
||||
UINFO(4, " CONST4 " << nodep);
|
||||
UINFOTREE(9, nodep, "", "Const_old");
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test X/Z four-state simulation with --x-sim
|
||||
#
|
||||
# This test verifies X and Z value propagation when --x-sim is enabled.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile_extra_args = ['--x-sim']
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
// DESCRIPTION: Verilator: Test X/Z four-state simulation with --x-sim
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2026
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
module t;
|
||||
reg [3:0] a = 4'bXXXX;
|
||||
reg [3:0] b = 4'b1010;
|
||||
reg [3:0] y_and;
|
||||
|
||||
initial begin
|
||||
y_and = a & b;
|
||||
|
||||
$display("a = %b", a);
|
||||
$display("b = %b", b);
|
||||
$display("a & b = %b", y_and);
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test X/Z four-state simulation with comparisons
|
||||
#
|
||||
# This test verifies X and Z value propagation with comparison operators.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile_extra_args = ['--x-sim']
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
// DESCRIPTION: Verilator: Test X/Z four-state simulation with comparisons
|
||||
//
|
||||
// This test verifies four-state simulation with comparison operators.
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2026
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
module t;
|
||||
|
||||
reg [3:0] a = 4'b1010;
|
||||
reg [3:0] b = 4'b0101;
|
||||
reg [3:0] x = 4'bX010;
|
||||
reg [3:0] z = 4'bZ010;
|
||||
reg [3:0] xall = 4'bXXXX;
|
||||
reg [3:0] zall = 4'bZZZZ;
|
||||
|
||||
reg eq, ne, lt, le, gt, ge;
|
||||
reg eq_x, ne_x;
|
||||
reg case_eq, case_ne;
|
||||
reg case_eq_x;
|
||||
|
||||
initial begin
|
||||
eq = (a == b);
|
||||
ne = (a != b);
|
||||
lt = (a < b);
|
||||
le = (a <= b);
|
||||
gt = (a > b);
|
||||
ge = (a >= b);
|
||||
|
||||
eq_x = (a == x);
|
||||
ne_x = (a != x);
|
||||
|
||||
case_eq = (a === b);
|
||||
case_ne = (a !== b);
|
||||
case_eq_x = (a === x);
|
||||
|
||||
$write("=== Basic Comparisons (no X/Z) ===\n");
|
||||
$write("a == b = %b (expect 0)\n", eq);
|
||||
$write("a != b = %b (expect 1)\n", ne);
|
||||
$write("a < b = %b (expect 0)\n", lt);
|
||||
$write("a > b = %b (expect 1)\n", gt);
|
||||
|
||||
$write("\n=== Comparisons with X ===\n");
|
||||
$write("a == x = %b\n", eq_x);
|
||||
$write("a != x = %b\n", ne_x);
|
||||
|
||||
$write("\n=== Case Equality ===\n");
|
||||
$write("a === b = %b\n", case_eq);
|
||||
$write("a !== b = %b\n", case_ne);
|
||||
$write("a === x = %b\n", case_eq_x);
|
||||
$write("xall === xall = %b (X never matches X)\n", xall === xall);
|
||||
$write("zall === zall = %b (Z never matches Z)\n", zall === zall);
|
||||
|
||||
$write("\n=== Reduction with X/Z ===\n");
|
||||
$write("& x = %b\n", &x);
|
||||
$write("| x = %b\n", |x);
|
||||
$write("^ x = %b\n", ^x);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,82 @@
|
|||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def run_verilator_test(test_name, verilog_file, options=""):
|
||||
print(f"\n=== Running {test_name} ===")
|
||||
|
||||
# Run Verilator
|
||||
verilator_cmd = f"verilator --x-sim -cc {verilog_file} --exe t_{test_name}.cpp -Mdir obj_vlt/{test_name} {options}"
|
||||
result = subprocess.run(verilator_cmd, shell=True, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
print("Verilator compilation failed!")
|
||||
print(result.stderr)
|
||||
return False
|
||||
|
||||
print("Verilator compilation successful.")
|
||||
|
||||
# Compile the test
|
||||
compile_cmd = f"make -C obj_vlt/{test_name} -f /home/bnielson/git/verilator/test_regress/Makefile_obj --no-print-directory VM_PREFIX=Vt_{test_name} CPPFLAGS_DRIVER=-D{test_name.upper()} {test_name}"
|
||||
result = subprocess.run(compile_cmd, shell=True, capture_output=True, text=True)
|
||||
|
||||
if result.returncode != 0:
|
||||
print("Test compilation failed!")
|
||||
print(result.stderr)
|
||||
return False
|
||||
|
||||
print("Test compilation successful.")
|
||||
|
||||
# Run the test
|
||||
run_cmd = f"obj_vlt/{test_name}/{test_name}"
|
||||
result = subprocess.run(run_cmd, shell=True, capture_output=True, text=True)
|
||||
|
||||
print(result.stdout)
|
||||
|
||||
if result.returncode != 0:
|
||||
print("Test execution failed!")
|
||||
print(result.stderr)
|
||||
return False
|
||||
|
||||
print(f"{test_name} passed!")
|
||||
return True
|
||||
|
||||
def main():
|
||||
tests = [
|
||||
{
|
||||
"name": "x_sim_edge_cases",
|
||||
"verilog": "t_x_sim_edge_cases.v",
|
||||
"description": "Edge cases with nested operations, mixed bit widths, arrays, and complex expressions"
|
||||
}
|
||||
]
|
||||
|
||||
print("Verilator X/Z Four-State Simulation Edge Case Tests")
|
||||
print("=" * 60)
|
||||
|
||||
passed = 0
|
||||
failed = 0
|
||||
|
||||
for test in tests:
|
||||
print(f\n"\n" + "=" * 40)
|
||||
print(f"Test: {test[\"name\"]}")
|
||||
print(f"Description: {test[\"description\"]}")
|
||||
print("=" * 40)
|
||||
|
||||
if run_verilator_test(test["name"], test["verilog"]):
|
||||
passed += 1
|
||||
else:
|
||||
failed += 1
|
||||
|
||||
print(f\n"\n" + "=" * 60)
|
||||
print(f"Test Summary: {passed} passed, {failed} failed")
|
||||
print("=" * 60)
|
||||
|
||||
if failed == 0:
|
||||
print("✅ All edge case tests passed!")
|
||||
return 0
|
||||
else:
|
||||
print("❌ Some tests failed.")
|
||||
return 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
// Test Z display - very simple
|
||||
|
||||
module t;
|
||||
reg [7:0] z8 = 8'bZZZZ1010;
|
||||
|
||||
initial begin
|
||||
$display("z8=%b", z8);
|
||||
$finish;
|
||||
end
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test X/Z four-state simulation with file output
|
||||
#
|
||||
# This test verifies X and Z value propagation with $fwrite, $fdisplay.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile_extra_args = ['--x-sim']
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// DESCRIPTION: Verilator: Test X/Z four-state simulation with file output
|
||||
//
|
||||
// This test verifies four-state simulation with $fwrite, $fdisplay.
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2026
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
module t;
|
||||
|
||||
integer fd;
|
||||
string filename = "/tmp/verilator_xz_test.txt";
|
||||
|
||||
// Four-state signals
|
||||
reg [3:0] a = 4'b1010;
|
||||
reg [3:0] x = 4'b1X10;
|
||||
reg [3:0] z = 4'bZ010;
|
||||
reg [7:0] xz_data = 8'bXZ10XZ10;
|
||||
|
||||
initial begin
|
||||
fd = $fopen(filename, "w");
|
||||
if (fd == 0) begin
|
||||
$display("ERROR: Could not open file %s", filename);
|
||||
$finish;
|
||||
end
|
||||
|
||||
$fwrite(fd, "=== File Output Test with X/Z ===\n");
|
||||
$fwrite(fd, "a = %b (initialized)\n", a);
|
||||
$fwrite(fd, "x = %b (has X)\n", x);
|
||||
$fwrite(fd, "z = %b (has Z)\n", z);
|
||||
$fwrite(fd, "xz_data = %b (mixed X/Z)\n", xz_data);
|
||||
|
||||
// Test operations with X/Z and write results
|
||||
$fwrite(fd, "\n=== Operations ===\n");
|
||||
$fwrite(fd, "a & x = %b\n", a & x);
|
||||
$fwrite(fd, "a | z = %b\n", a | z);
|
||||
$fwrite(fd, "x ^ z = %b\n", x ^ z);
|
||||
$fwrite(fd, "x + z = %b\n", x + z);
|
||||
|
||||
// Test $fdisplay
|
||||
$fwrite(fd, "\n=== Using $fdisplay ===\n");
|
||||
$fdisplay(fd, "Display with x: %b", x);
|
||||
$fdisplay(fd, "Display with z: %b", z);
|
||||
$fdisplay(fd, "Display with xz_data: %b", xz_data);
|
||||
|
||||
// Test $fwrite with hex format
|
||||
$fwrite(fd, "\n=== Hex Format ===\n");
|
||||
$fwrite(fd, "a = %h\n", a);
|
||||
$fwrite(fd, "x = %h (X becomes 0 in hex)\n", x);
|
||||
$fwrite(fd, "z = %h (Z becomes 0 in hex)\n", z);
|
||||
|
||||
// Test uninitialized signal
|
||||
reg [3:0] uninit;
|
||||
$fwrite(fd, "\n=== Uninitialized Signal ===\n");
|
||||
$fwrite(fd, "uninit (4-state default) = %b\n", uninit);
|
||||
|
||||
$fclose(fd);
|
||||
|
||||
$display("Wrote X/Z test output to %s", filename);
|
||||
$display("Contents:");
|
||||
$display("");
|
||||
|
||||
// Read and display the file contents
|
||||
string line;
|
||||
fd = $fopen(filename, "r");
|
||||
while ($fgets(line, fd)) begin
|
||||
$display("%s", line);
|
||||
end
|
||||
$fclose(fd);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test X initialization with --x-sim
|
||||
#
|
||||
# This test verifies X initialization of four-state signals when --x-sim is enabled.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile_extra_args = ['--x-sim']
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
// DESCRIPTION: Verilator: Test X initialization with --x-sim
|
||||
//
|
||||
// This test verifies X initialization of four-state signals when --x-sim is enabled.
|
||||
// Four-state signals should initialize to X at time 0.
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2026
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
module t(input clk);
|
||||
|
||||
// Test that four-state signals initialize to X
|
||||
logic [3:0] sig_4state; // Should be X at init
|
||||
logic sig_bit; // Single bit should be X at init
|
||||
|
||||
// Counter to wait for first clock
|
||||
integer count = 0;
|
||||
|
||||
always @(posedge clk) begin
|
||||
count <= count + 1;
|
||||
|
||||
if (count == 0) begin
|
||||
// First cycle - check initialization
|
||||
// sig_4state should be XXXX (all X)
|
||||
// sig_bit should be X
|
||||
$write("Cycle %0d: sig_4state = %b (expect xxxx)\n", count, sig_4state);
|
||||
$write("Cycle %0d: sig_bit = %b (expect x)\n", count, sig_bit);
|
||||
end
|
||||
else if (count == 1) begin
|
||||
// After first clock, values should be assigned
|
||||
$write("Cycle %0d: sig_4state = %b\n", count, sig_4state);
|
||||
$write("Cycle %0d: sig_bit = %b\n", count, sig_bit);
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test X/Z four-state simulation with larger bit widths
|
||||
#
|
||||
# This test verifies X and Z value propagation in 64/128/256-bit operations.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile_extra_args = ['--x-sim']
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
// DESCRIPTION: Verilator: Test X/Z four-state simulation with larger bit widths (64-bit)
|
||||
//
|
||||
// This test verifies four-state simulation with 64-bit operations.
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2026
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
module t;
|
||||
|
||||
// 64-bit four-state signals
|
||||
reg [63:0] a64 = 64'hFEDC_BA98_7654_3210;
|
||||
reg [63:0] b64 = 64'h0123_4567_89AB_CDEF;
|
||||
reg [63:0] xz64 = 64'hXZ10_XZ10_XZ10_XZ10;
|
||||
|
||||
// Results
|
||||
reg [63:0] res_and_64;
|
||||
reg [63:0] res_or_64;
|
||||
reg [63:0] res_xor_64;
|
||||
reg [63:0] res_not_64;
|
||||
|
||||
initial begin
|
||||
// 64-bit operations with X/Z
|
||||
res_and_64 = a64 & xz64; // X & anything = X
|
||||
res_or_64 = b64 | xz64; // X | anything = X
|
||||
res_xor_64 = a64 ^ xz64; // XOR with X = X
|
||||
res_not_64 = ~xz64; // ~X = X, ~Z = X
|
||||
|
||||
$write("=== 64-bit Tests ===\n");
|
||||
$write("a64 = %h\n", a64);
|
||||
$write("b64 = %h\n", b64);
|
||||
$write("xz64 = %b\n", xz64);
|
||||
$write("a64 & xz64 = %b\n", res_and_64);
|
||||
$write("b64 | xz64 = %b\n", res_or_64);
|
||||
$write("a64 ^ xz64 = %b\n", res_xor_64);
|
||||
$write("~xz64 = %b\n", res_not_64);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test X/Z four-state simulation with structs
|
||||
#
|
||||
# This test verifies X and Z value propagation in struct members.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile_extra_args = ['--x-sim']
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,74 @@
|
|||
// DESCRIPTION: Verilator: Test X/Z four-state simulation with structs
|
||||
//
|
||||
// This test verifies four-state simulation with struct members.
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2026
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
module t;
|
||||
|
||||
// Struct with four-state members
|
||||
typedef struct packed {
|
||||
logic [3:0] a;
|
||||
logic [7:0] b;
|
||||
logic flag;
|
||||
} my_struct_t;
|
||||
|
||||
// Struct signals
|
||||
my_struct_t s1 = 16'hABCD;
|
||||
my_struct_t s2 = 16'h1234;
|
||||
my_struct_t sx; // Uninitialized - should be X with --x-sim
|
||||
my_struct_t s_result;
|
||||
|
||||
// Struct with X/Z values
|
||||
my_struct_t sx_val;
|
||||
initial begin
|
||||
sx_val.a = 4'bX101;
|
||||
sx_val.b = 8'bZ0101010;
|
||||
sx_val.flag = 1'bX;
|
||||
end
|
||||
|
||||
// Mixed struct operations
|
||||
my_struct_t s_and;
|
||||
my_struct_t s_or;
|
||||
my_struct_t s_add;
|
||||
|
||||
initial begin
|
||||
// Operations on struct members
|
||||
s_and = sx & sx_val; // Uninitialized X & X = X
|
||||
s_or = s1 | sx_val; // Normal | X = X
|
||||
s_add = s1 + sx; // Normal + X = X
|
||||
|
||||
$write("=== Struct Four-State Tests ===\n");
|
||||
|
||||
$write("s1 = %b (initialized)\n", s1);
|
||||
$write("s2 = %b (initialized)\n", s2);
|
||||
$write("sx (uninitialized) = %b (expect X)\n", sx);
|
||||
|
||||
$write("\n=== Struct with X/Z values ===\n");
|
||||
$write("sx_val.a = %b (X101)\n", sx_val.a);
|
||||
$write("sx_val.b = %b (Z0101010)\n", sx_val.b);
|
||||
$write("sx_val.flag = %b (X)\n", sx_val.flag);
|
||||
$write("sx_val = %b\n", sx_val);
|
||||
|
||||
$write("\n=== Struct Operations ===\n");
|
||||
$write("sx & sx_val = %b (expect all X)\n", s_and);
|
||||
$write("s1 | sx_val = %b (expect X in members with X)\n", s_or);
|
||||
$write("s1 + sx = %b (expect all X)\n", s_add);
|
||||
|
||||
// Test struct member access
|
||||
$write("\n=== Struct Member Access ===\n");
|
||||
$write("sx.a = %b (uninitialized member)\n", sx.a);
|
||||
$write("sx.b = %b (uninitialized member)\n", sx.b);
|
||||
$write("sx.flag = %b (uninitialized member)\n", sx.flag);
|
||||
|
||||
// Test assignment to struct with X
|
||||
sx = sx_val;
|
||||
$write("\n=== After Assignment ===\n");
|
||||
$write("sx = %b (after sx = sx_val)\n", sx);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
#!/usr/bin/env python3
|
||||
# DESCRIPTION: Verilator: Test X/Z four-state simulation with time functions
|
||||
#
|
||||
# This test verifies X and Z value propagation with $time, $stime, $realtime.
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2026
|
||||
# SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
import vltest_bootstrap
|
||||
|
||||
test.scenarios('simulator')
|
||||
|
||||
test.compile_extra_args = ['--x-sim']
|
||||
|
||||
test.execute()
|
||||
|
||||
test.passes()
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
// DESCRIPTION: Verilator: Test X/Z four-state simulation with time functions
|
||||
//
|
||||
// This test verifies four-state simulation with $time, $stime, and $realtime.
|
||||
//
|
||||
// SPDX-FileCopyrightText: 2026
|
||||
// SPDX-License-Identifier: LGPL-3.0-only
|
||||
|
||||
module t;
|
||||
|
||||
// Four-state signals
|
||||
reg [3:0] a = 4'b1010;
|
||||
reg [3:0] x = 4'bXXXX;
|
||||
reg [3:0] z = 4'bZZZZ;
|
||||
|
||||
// Variables to store time values
|
||||
integer time_val;
|
||||
integer stime_val;
|
||||
real realtime_val;
|
||||
|
||||
// Test X/Z in time-related contexts
|
||||
reg [7:0] result_with_x;
|
||||
reg [7:0] result_with_z;
|
||||
|
||||
initial begin
|
||||
time_val = $time;
|
||||
stime_val = $stime;
|
||||
realtime_val = $realtime;
|
||||
|
||||
$write("=== Time Function Tests ===\n");
|
||||
$write("Initial $time = %0d\n", time_val);
|
||||
$write("Initial $stime = %0d\n", stime_val);
|
||||
$write("Initial $realtime = %0f\n", realtime_val);
|
||||
|
||||
// Operations with X/Z before first time increment
|
||||
result_with_x = a + x; // Should propagate X
|
||||
result_with_z = a | z; // Should propagate X
|
||||
|
||||
$write("\n=== Operations with X/Z at time 0 ===\n");
|
||||
$write("a = %b (1010)\n", a);
|
||||
$write("x = %b (XXXX)\n", x);
|
||||
$write("z = %b (ZZZZ)\n", z);
|
||||
$write("a + x = %b (expect XXXX with --x-sim)\n", result_with_x);
|
||||
$write("a | z = %b (expect XXXX with --x-sim)\n", result_with_z);
|
||||
|
||||
#10;
|
||||
time_val = $time;
|
||||
stime_val = $stime;
|
||||
realtime_val = $realtime;
|
||||
|
||||
$write("\n=== Time after #10 ===\n");
|
||||
$write("$time = %0d\n", time_val);
|
||||
$write("$stime = %0d\n", stime_val);
|
||||
$write("$realtime = %0f\n", realtime_val);
|
||||
|
||||
// Operations after time advancement
|
||||
result_with_x = a * x;
|
||||
result_with_z = a ^ z;
|
||||
|
||||
$write("\n=== Operations with X/Z at time 10 ===\n");
|
||||
$write("a * x = %b (expect XXXX with --x-sim)\n", result_with_x);
|
||||
$write("a ^ z = %b (expect XXXX with --x-sim)\n", result_with_z);
|
||||
|
||||
#5.5;
|
||||
time_val = $time;
|
||||
realtime_val = $realtime;
|
||||
|
||||
$write("\n=== Time after #5.5 (time 15.5) ===\n");
|
||||
$write("$time = %0d (rounded)\n", time_val);
|
||||
$write("$realtime = %0f\n", realtime_val);
|
||||
|
||||
#100;
|
||||
time_val = $time;
|
||||
stime_val = $stime;
|
||||
realtime_val = $realtime;
|
||||
|
||||
$write("\n=== Time after #100 (time 115.5) ===\n");
|
||||
$write("$time = %0d\n", time_val);
|
||||
$write("$stime = %0d\n", stime_val);
|
||||
$write("$realtime = %0f\n", realtime_val);
|
||||
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
end
|
||||
|
||||
endmodule
|
||||
Loading…
Reference in New Issue