Internals: Four state pre-pull (types) (#7520)

This commit is contained in:
Igor Zaworski 2026-04-30 22:56:15 +02:00 committed by GitHub
parent ec03edcddd
commit 25d4827bd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
18 changed files with 196 additions and 80 deletions

View File

@ -416,6 +416,8 @@ detailed descriptions of these arguments.
-f <file> Parse arguments from a file
-FI <file> Force include of a file
--flatten Force inlining of all modules, tasks and functions
--fourstate Enable fourstate logic
--no-fourstate Disable fourstate logic
--func-recursion-depth <value> Maximum recursive constant function depth
--future0 <option> Ignore an option for compatibility
--future1 <option> Ignore an option with argument for compatibility

View File

@ -758,6 +758,14 @@ Summary:
automatically. Variables explicitly annotated with
:option:`/*verilator&32;split_var*/` are still split.
.. option:: --fourstate
Enables four-state logic support. Experimental, for developer use only.
.. option:: --no-fourstate
Disables four-state logic support which is the default. Exists for forward compatibility.
.. option:: --fslice-element-limit
Rarely needed. Set the maximum array size (number of elements) for slice

View File

@ -1592,7 +1592,7 @@ void AstNode::dtypeChgWidthSigned(int width, int widthMin, VSigning numeric) {
&& !VN_IS(dtypep()->skipRefToEnump(), EnumDType))
return; // Correct already
if (AstBasicDType* const basicp = VN_CAST(dtypep(), BasicDType)) {
if (basicp->keyword() == VBasicDTypeKwd::BIT) {
if (!basicp->keyword().isFourstate()) {
dtypeSetBitUnsized(width, widthMin, numeric);
return;
}

View File

@ -756,9 +756,13 @@ public:
dtypep(findLogicDType(width, width, numeric)); // Since sized, widthMin is width
}
void dtypeSetBit() { dtypep(findBitDType()); }
void dtypeSetLogic() { dtypep(findLogicDType()); }
void dtypeSetDouble() { dtypep(findDoubleDType()); }
void dtypeSetInt() { dtypep(findIntDType()); }
void dtypeSetInteger() { dtypep(findIntegerDType()); }
// TODO: add a type to handle 4-state integers with 2-state domain
void dtypeSetInteger2State() { dtypep(findIntegerDType()); }
void dtypeSetString() { dtypep(findStringDType()); }
void dtypeSetSigned32() { dtypep(findSigned32DType()); }
void dtypeSetUInt32() { dtypep(findUInt32DType()); } // Twostate
void dtypeSetUInt64() { dtypep(findUInt64DType()); } // Twostate
void dtypeSetEmptyQueue() { dtypep(findEmptyQueueDType()); }
@ -767,11 +771,12 @@ public:
// Data type locators
AstNodeDType* findBitDType() const { return findBasicDType(VBasicDTypeKwd::BIT); }
AstNodeDType* findLogicDType() const { return findBasicDType(VBasicDTypeKwd::LOGIC); }
AstNodeDType* findDoubleDType() const { return findBasicDType(VBasicDTypeKwd::DOUBLE); }
AstNodeDType* findIntDType() const { return findBasicDType(VBasicDTypeKwd::INT); }
AstNodeDType* findIntegerDType() const { return findBasicDType(VBasicDTypeKwd::INTEGER); }
AstNodeDType* findStringDType() const { return findBasicDType(VBasicDTypeKwd::STRING); }
AstNodeDType* findSigned8DType() const { return findBasicDType(VBasicDTypeKwd::BYTE); }
AstNodeDType* findSigned32DType() const { return findBasicDType(VBasicDTypeKwd::INTEGER); }
AstNodeDType* findUInt32DType() const { return findBasicDType(VBasicDTypeKwd::UINT32); }
AstNodeDType* findUInt64DType() const { return findBasicDType(VBasicDTypeKwd::UINT64); }
AstNodeDType* findCHandleDType() const { return findBasicDType(VBasicDTypeKwd::CHANDLE); }

View File

@ -130,7 +130,7 @@ class AstNodeDistBiop VL_NOT_FINAL : public AstNodeBiop {
public:
AstNodeDistBiop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: AstNodeBiop{t, fl, lhsp, rhsp} {
dtypeSetSigned32();
dtypeSetInteger();
}
ASTGEN_MEMBERS_AstNodeDistBiop;
bool cleanOut() const override { return false; }
@ -403,7 +403,7 @@ public:
AstNodeDistTriop(VNType t, FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp,
AstNodeExpr* thsp)
: AstNodeTriop{t, fl, lhsp, rhsp, thsp} {
dtypeSetSigned32();
dtypeSetInteger();
}
ASTGEN_MEMBERS_AstNodeDistTriop;
bool cleanOut() const override { return false; }
@ -1671,7 +1671,7 @@ class AstGetInitialRandomSeed final : public AstNodeExpr {
public:
explicit AstGetInitialRandomSeed(FileLine* fl)
: ASTGEN_SUPER_GetInitialRandomSeed(fl) {
dtypeSetSigned32();
dtypeSetInt();
}
ASTGEN_MEMBERS_AstGetInitialRandomSeed;
string emitVerilog() override { return "$get_initial_random_seed()"; }
@ -2721,7 +2721,7 @@ class AstTimePrecision final : public AstNodeExpr {
public:
explicit AstTimePrecision(FileLine* fl)
: ASTGEN_SUPER_TimePrecision(fl) {
dtypeSetSigned32();
dtypeSetInteger2State();
}
ASTGEN_MEMBERS_AstTimePrecision;
string emitVerilog() override { return "$timeprecision"; }
@ -2738,7 +2738,7 @@ class AstTimeUnit final : public AstNodeExpr {
public:
explicit AstTimeUnit(FileLine* fl)
: ASTGEN_SUPER_TimeUnit(fl) {
dtypeSetSigned32();
dtypeSetInteger2State();
}
ASTGEN_MEMBERS_AstTimeUnit;
string emitVerilog() override { return "$timeunit"; }
@ -2753,11 +2753,11 @@ public:
};
class AstUnbounded final : public AstNodeExpr {
// A $ in the parser, used for unbounded and queues
// Due to where is used, treated as Signed32
// Due to where is used, treated as int
public:
explicit AstUnbounded(FileLine* fl)
: ASTGEN_SUPER_Unbounded(fl) {
dtypeSetSigned32();
dtypeSetInt();
}
ASTGEN_MEMBERS_AstUnbounded;
string emitVerilog() override { return "$"; }
@ -2917,7 +2917,7 @@ public:
AstCompareNN(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, bool ignoreCase)
: ASTGEN_SUPER_CompareNN(fl, lhsp, rhsp)
, m_ignoreCase{ignoreCase} {
dtypeSetUInt32();
dtypeSetInt();
}
ASTGEN_MEMBERS_AstCompareNN;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
@ -3060,7 +3060,12 @@ class AstEqWild final : public AstNodeBiop {
public:
AstEqWild(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_EqWild(fl, lhsp, rhsp) {
dtypeSetBit();
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
&& !rhsp->dtypep()->isFourstate()) {
dtypeSetBit();
} else {
dtypeSetLogic();
}
}
ASTGEN_MEMBERS_AstEqWild;
// Return AstEqWild/AstEqD
@ -3069,9 +3074,21 @@ public:
out.opWildEq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f==? %r)"; }
string emitC() override { return "VL_EQ_%lq(%lW, %P, %li, %ri)"; }
string emitC() override {
if (v3Global.opt.fourstate()) {
V3ERROR_NA_RETURN("");
} else {
return "VL_EQ_%lq(%lW, %P, %li, %ri)";
}
}
string emitSMT() const override { return "(__Vbv (= %l %r))"; }
string emitSimpleOperator() override { return "=="; }
string emitSimpleOperator() override {
if (v3Global.opt.fourstate()) {
V3ERROR_NA_RETURN("");
} else {
return "==";
}
}
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
@ -3618,15 +3635,32 @@ class AstNeqWild final : public AstNodeBiop {
public:
AstNeqWild(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_NeqWild(fl, lhsp, rhsp) {
dtypeSetBit();
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
&& !rhsp->dtypep()->isFourstate()) {
dtypeSetBit();
} else {
dtypeSetLogic();
}
}
ASTGEN_MEMBERS_AstNeqWild;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
out.opWildNeq(lhs, rhs);
}
string emitVerilog() override { return "%k(%l %f!=? %r)"; }
string emitC() override { return "VL_NEQ_%lq(%lW, %P, %li, %ri)"; }
string emitSimpleOperator() override { return "!="; }
string emitC() override {
if (v3Global.opt.fourstate()) {
V3ERROR_NA_RETURN("");
} else {
return "VL_NEQ_%lq(%lW, %P, %li, %ri)";
}
}
string emitSimpleOperator() override {
if (v3Global.opt.fourstate()) {
V3ERROR_NA_RETURN("");
} else {
return "!=";
}
}
bool cleanOut() const override { return true; }
bool cleanLhs() const override { return true; }
bool cleanRhs() const override { return true; }
@ -3976,7 +4010,18 @@ class AstShiftL final : public AstNodeBiop {
public:
AstShiftL(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftL(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
&& !rhsp->dtypep()->isFourstate()) {
dtypeSetBitUnsized(setwidth ? setwidth : lhsp->width(),
setwidth ? 0 : lhsp->dtypep()->widthMin(),
lhsp->dtypep()->numeric());
} else if (lhsp->dtypep()) {
dtypeSetLogicUnsized(setwidth ? setwidth : lhsp->width(),
setwidth ? 0 : lhsp->dtypep()->widthMin(),
lhsp->dtypep()->numeric());
} else {
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
}
ASTGEN_MEMBERS_AstShiftL;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
@ -4020,7 +4065,18 @@ class AstShiftR final : public AstNodeBiop {
public:
AstShiftR(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp, int setwidth = 0)
: ASTGEN_SUPER_ShiftR(fl, lhsp, rhsp) {
if (setwidth) dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
&& !rhsp->dtypep()->isFourstate()) {
dtypeSetBitUnsized(setwidth ? setwidth : lhsp->width(),
setwidth ? 0 : lhsp->dtypep()->widthMin(),
lhsp->dtypep()->numeric());
} else if (lhsp->dtypep()) {
dtypeSetLogicUnsized(setwidth ? setwidth : lhsp->width(),
setwidth ? 0 : lhsp->dtypep()->widthMin(),
lhsp->dtypep()->numeric());
} else {
dtypeSetLogicSized(setwidth, VSigning::UNSIGNED);
}
}
ASTGEN_MEMBERS_AstShiftR;
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
@ -4181,7 +4237,12 @@ class AstEq final : public AstNodeBiCom {
public:
AstEq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Eq(fl, lhsp, rhsp) {
dtypeSetBit();
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
&& !rhsp->dtypep()->isFourstate()) {
dtypeSetBit();
} else {
dtypeSetLogic();
}
}
ASTGEN_MEMBERS_AstEq;
// Return AstEq/AstEqD
@ -4307,7 +4368,12 @@ class AstNeq final : public AstNodeBiCom {
public:
AstNeq(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp)
: ASTGEN_SUPER_Neq(fl, lhsp, rhsp) {
dtypeSetBit();
if (lhsp->dtypep() && rhsp->dtypep() && !lhsp->dtypep()->isFourstate()
&& !rhsp->dtypep()->isFourstate()) {
dtypeSetBit();
} else {
dtypeSetLogic();
}
}
ASTGEN_MEMBERS_AstNeq;
static AstNodeBiop* newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp);
@ -5275,7 +5341,7 @@ public:
AstAtoN(FileLine* fl, AstNodeExpr* lhsp, FmtType fmt)
: ASTGEN_SUPER_AtoN(fl, lhsp)
, m_fmt{fmt} {
fmt == ATOREAL ? dtypeSetDouble() : dtypeSetSigned32();
fmt == ATOREAL ? dtypeSetDouble() : dtypeSetInteger();
}
ASTGEN_MEMBERS_AstAtoN;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opAtoN(lhs, m_fmt); }
@ -5360,7 +5426,7 @@ class AstCLog2 final : public AstNodeUniop {
public:
AstCLog2(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_CLog2(fl, lhsp) {
dtypeSetSigned32();
dtypeSetInteger2State();
}
ASTGEN_MEMBERS_AstCLog2;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opCLog2(lhs); }
@ -5581,7 +5647,7 @@ class AstLenN final : public AstNodeUniop {
public:
AstLenN(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_LenN(fl, lhsp) {
dtypeSetSigned32();
dtypeSetInt();
}
ASTGEN_MEMBERS_AstLenN;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLenN(lhs); }
@ -5732,7 +5798,7 @@ class AstRToIRoundS final : public AstNodeUniop {
public:
AstRToIRoundS(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RToIRoundS(fl, lhsp) {
dtypeSetSigned32();
dtypeSetInteger();
}
ASTGEN_MEMBERS_AstRToIRoundS;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIRoundS(lhs); }
@ -5751,7 +5817,7 @@ class AstRToIS final : public AstNodeUniop {
public:
AstRToIS(FileLine* fl, AstNodeExpr* lhsp)
: ASTGEN_SUPER_RToIS(fl, lhsp) {
dtypeSetSigned32();
dtypeSetInteger2State();
}
ASTGEN_MEMBERS_AstRToIS;
void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRToIS(lhs); }

View File

@ -584,11 +584,11 @@ static AstNode* createForeachAssoc(FileLine* fl, AstVar* varp, AstNodeExpr* subf
AstNodeExpr* const firstp
= new AstCMethodHard{fl, subfromp->cloneTreePure(false), VCMethod::ASSOC_FIRST,
new AstVarRef{fl, next_varp, VAccess::READWRITE}};
firstp->dtypeSetSigned32();
firstp->dtypeSetInteger();
AstNodeExpr* const nextp
= new AstCMethodHard{fl, subfromp->cloneTreePure(false), VCMethod::ASSOC_NEXT,
new AstVarRef{fl, next_varp, VAccess::READWRITE}};
nextp->dtypeSetSigned32();
nextp->dtypeSetInteger();
// _Vmore = array.first(__Vnext)
loopp->addNext(new AstAssign{fl, new AstVarRef{fl, more_varp, VAccess::WRITE},
@ -693,7 +693,7 @@ AstNode* V3Begin::convertToWhile(AstForeach* nodep) {
: subfromp->cloneTreePure(false),
VCMethod::DYN_SIZE};
AstVarRef* varRefp = new AstVarRef{fl, varp, VAccess::READ};
rightp->dtypeSetSigned32();
rightp->dtypeSetInt();
rightp->protect(false);
loopp = createForeachLoop(nodep, bodyPointp, arrayMayResize, subfromp, varp, leftp,
rightp, VNType::Lt);

View File

@ -695,6 +695,8 @@ class EmitCTrace final : public EmitCFunc {
// Type
puts(", VerilatedTraceSigType::");
UASSERT_OBJ(nodep->dtypep()->basicp()->keyword() != VBasicDTypeKwd::UNKNOWN, nodep,
"DType is unknown");
puts(nodep->dtypep()->basicp()->keyword().traceSigType());
// Array range

View File

@ -401,7 +401,7 @@ class LinkJumpVisitor final : public VNVisitor {
AstBegin* const beginp = new AstBegin{nodep->fileline(), "", nullptr, true};
// Spec says value is integral, if negative is ignored
AstVar* const varp
= new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findSigned32DType()};
= new AstVar{nodep->fileline(), VVarType::BLOCKTEMP, name, nodep->findIntDType()};
varp->lifetime(VLifetime::AUTOMATIC_EXPLICIT);
varp->usedLoopIdx(true);
beginp->addStmtsp(varp);

View File

@ -1848,11 +1848,14 @@ V3Number& V3Number::opWildEq(const V3Number& lhs, const V3Number& rhs) {
char outc = 1;
for (int bit = 0; bit < std::max(lhs.width(), rhs.width()); ++bit) {
if (!rhs.bitIsXZ(bit)) {
if (lhs.bitIsXZ(bit)) {
outc = 'x';
goto last;
}
if (lhs.bitIs(bit) != rhs.bitIs(bit)) {
outc = 0;
goto last;
}
if (lhs.bitIsXZ(bit)) outc = 'x';
}
}
last:
@ -1865,11 +1868,14 @@ V3Number& V3Number::opWildNeq(const V3Number& lhs, const V3Number& rhs) {
char outc = 0;
for (int bit = 0; bit < std::max(lhs.width(), rhs.width()); ++bit) {
if (!rhs.bitIsXZ(bit)) {
if (lhs.bitIsXZ(bit)) {
outc = 'x';
goto last;
}
if (lhs.bitIs(bit) != rhs.bitIs(bit)) {
outc = 1;
goto last;
}
if (lhs.bitIsXZ(bit)) outc = 'x';
}
}
last:

View File

@ -1050,6 +1050,10 @@ void V3Options::notify() VL_MT_DISABLED {
if (fourstate()) {
cmdfl->v3warn(FUTURE, "--fourstate is not supported as is under development");
if (hierarchical()) {
cmdfl->v3warn(E_UNSUPPORTED,
"--fourstate is not supported with hierarchical Verilation");
}
}
if (coverage() && savable()) {

View File

@ -2331,7 +2331,7 @@ class ConstraintExprVisitor final : public VNVisitor {
const bool randArr = nodep->fromp()->user1();
AstVar* const newVarp
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vinside", nodep->findSigned32DType()};
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vinside", nodep->findIntDType()};
AstNodeExpr* const idxRefp = new AstVarRef{nodep->fileline(), newVarp, VAccess::READ};
AstForeachHeader* const headerp
= new AstForeachHeader{fl, nodep->fromp()->cloneTreePure(false), newVarp};
@ -2397,7 +2397,7 @@ class ConstraintExprVisitor final : public VNVisitor {
// Create loop variable and header
AstVar* const loopVarp
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vreduce", nodep->findSigned32DType()};
= new AstVar{fl, VVarType::BLOCKTEMP, "__Vreduce", nodep->findIntDType()};
AstForeachHeader* const headerp
= new AstForeachHeader{fl, nodep->fromp()->cloneTreePure(false), loopVarp};
@ -5263,8 +5263,8 @@ class RandomizeVisitor final : public VNVisitor {
if (!arrVarp->rand().isRandomizable()) continue;
FileLine* const fl = methodp->fileline();
bool wasCreated = false;
AstVar* const sizeVarp = createOrGetSizeVar(
classp, arrVarp, fl, methodp->findSigned32DType(), wasCreated);
AstVar* const sizeVarp
= createOrGetSizeVar(classp, arrVarp, fl, methodp->findIntDType(), wasCreated);
if (wasCreated) {
// Generate resize for dynamic arrays/queues (not assoc arrays)
if (!VN_IS(arrVarp->dtypep()->skipRefp(), AssocArrayDType)) {
@ -5352,8 +5352,8 @@ class RandomizeVisitor final : public VNVisitor {
}
AstVar* const queueVarp = queueVarRefp->varp();
bool wasCreated = false;
AstVar* const sizeVarp = createOrGetSizeVar(classp, queueVarp, fl,
nodep->findSigned32DType(), wasCreated);
AstVar* const sizeVarp
= createOrGetSizeVar(classp, queueVarp, fl, nodep->findIntDType(), wasCreated);
if (wasCreated) {
// Associative arrays have no resize(); only generate resize
// for dynamic arrays and queues

View File

@ -430,7 +430,7 @@ class WidthVisitor final : public VNVisitor {
if (m_vup->prelim()) {
// See similar handling in visit_cmp_eq_gt where created
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
nodep->dtypeSetSigned32();
nodep->dtypeSetInt();
}
}
void visit(AstPutcN* nodep) override {
@ -485,7 +485,7 @@ class WidthVisitor final : public VNVisitor {
// See similar handling in visit_cmp_eq_gt where created
iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH);
iterateCheckString(nodep, "RHS", nodep->rhsp(), BOTH);
nodep->dtypeSetSigned32();
nodep->dtypeSetInt();
}
}
void visit(AstAtoN* nodep) override {
@ -498,7 +498,7 @@ class WidthVisitor final : public VNVisitor {
if (nodep->format() == AstAtoN::ATOREAL) {
nodep->dtypeSetDouble();
} else {
nodep->dtypeSetSigned32();
nodep->dtypeSetInteger();
}
}
}
@ -514,8 +514,8 @@ class WidthVisitor final : public VNVisitor {
// Widths: Constant, terminal
void visit(AstTime* nodep) override { nodep->dtypeSetUInt64(); }
void visit(AstTimeD* nodep) override { nodep->dtypeSetDouble(); }
void visit(AstTimePrecision* nodep) override { nodep->dtypeSetSigned32(); }
void visit(AstGetInitialRandomSeed* nodep) override { nodep->dtypeSetSigned32(); }
void visit(AstTimePrecision* nodep) override { nodep->dtypeSetInteger2State(); }
void visit(AstGetInitialRandomSeed* nodep) override { nodep->dtypeSetInt(); }
void visit(AstTimeUnit* nodep) override {
nodep->replaceWith(
new AstConst{nodep->fileline(), AstConst::Signed32{}, nodep->timeunit().powerOfTen()});
@ -950,7 +950,7 @@ class WidthVisitor final : public VNVisitor {
if (m_vup->prelim()) { // First stage evaluation
iterateCheckSigned32(nodep, "seed", nodep->lhsp(), BOTH);
iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
nodep->dtypeSetSigned32();
nodep->dtypeSetInteger();
}
}
void visit(AstNodeDistTriop* nodep) override {
@ -958,7 +958,7 @@ class WidthVisitor final : public VNVisitor {
iterateCheckSigned32(nodep, "seed", nodep->lhsp(), BOTH);
iterateCheckSigned32(nodep, "RHS", nodep->rhsp(), BOTH);
iterateCheckSigned32(nodep, "THS", nodep->thsp(), BOTH);
nodep->dtypeSetSigned32();
nodep->dtypeSetInteger();
}
}
void visit(AstNodeStream* nodep) override {
@ -1723,7 +1723,7 @@ class WidthVisitor final : public VNVisitor {
if (nodep->urandom()) {
nodep->dtypeSetUInt32(); // Says the spec
} else {
nodep->dtypeSetSigned32(); // Says the spec
nodep->dtypeSetInt(); // Says the spec
}
if (nodep->seedp()) iterateCheckSigned32(nodep, "seed", nodep->seedp(), BOTH);
}
@ -1783,7 +1783,7 @@ class WidthVisitor final : public VNVisitor {
}
}
void visit(AstUnbounded* nodep) override {
nodep->dtypeSetSigned32(); // Used in int context
nodep->dtypeSetInt(); // Used in int context
if (VN_IS(nodep->backp(), IsUnbounded)) return; // Ok, leave
if (VN_IS(nodep->backp(), BracketArrayDType)) return; // Ok, leave
if (VN_IS(nodep->backp(), InsideRange)) return; // Ok, leave
@ -2043,7 +2043,7 @@ class WidthVisitor final : public VNVisitor {
AstNodeExpr* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeExpr);
AstNode* const newp
= new AstCMethodHard{nodep->fileline(), fromp, VCMethod::DYN_SIZE};
newp->dtypeSetSigned32();
newp->dtypeSetInt();
newp->didWidth(true);
newp->protect(false);
nodep->replaceWith(newp);
@ -2062,7 +2062,7 @@ class WidthVisitor final : public VNVisitor {
AstNodeExpr* const fromp = VN_AS(nodep->fromp()->unlinkFrBack(), NodeExpr);
AstNodeExpr* const sizep
= new AstCMethodHard{nodep->fileline(), fromp, VCMethod::DYN_SIZE};
sizep->dtypeSetSigned32();
sizep->dtypeSetInt();
sizep->didWidth(true);
sizep->protect(false);
AstNode* const newp
@ -2906,7 +2906,7 @@ class WidthVisitor final : public VNVisitor {
// UINFO below will print variable nodep
} else {
// Or, if nothing assigned, they're integral
nodep->dtypeSetSigned32();
nodep->dtypeSetInteger();
VL_DANGLING(bdtypep);
}
} else if (bdtypep && bdtypep->implicit()) { // Implicits get converted to size 1
@ -3016,7 +3016,7 @@ class WidthVisitor final : public VNVisitor {
<< badDtp->warnOther() << "... Location of failing data type "
<< badDtp->prettyDTypeNameQ() << '\n'
<< badDtp->warnContextSecondary());
basicp = nodep->findSigned32DType()->basicp();
basicp = nodep->findIntDType()->basicp();
nodep->refDTypep(basicp);
}
nodep->widthFromSub(nodep->subDTypep());
@ -4127,7 +4127,7 @@ class WidthVisitor final : public VNVisitor {
methodOkArguments(nodep, 0, 0);
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
VCMethod::ASSOC_SIZE}; // So don't need num()
newp->dtypeSetSigned32();
newp->dtypeSetInt();
} else if (nodep->name() == "first" // function int first(ref index)
|| nodep->name() == "last" //
|| nodep->name() == "next" //
@ -4224,7 +4224,7 @@ class WidthVisitor final : public VNVisitor {
methodOkArguments(nodep, 0, 0);
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
VCMethod::ASSOC_SIZE}; // So don't need num()
newp->dtypeSetSigned32();
newp->dtypeSetInt();
} else if (nodep->name() == "first" // function int first(ref index)
|| nodep->name() == "last" //
|| nodep->name() == "next" //
@ -4237,7 +4237,7 @@ class WidthVisitor final : public VNVisitor {
= new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
VCMethod::arrayMethod(nodep->name()), // first/last/next/prev
index_exprp->unlinkFrBack()};
newp->dtypeSetSigned32();
newp->dtypeSetInteger();
if (!nodep->firstAbovep()) newp->dtypeSetVoid();
} else if (nodep->name() == "exists") { // function int exists(input index)
// IEEE really should have made this a "bit" return
@ -4490,7 +4490,7 @@ class WidthVisitor final : public VNVisitor {
methodOkArguments(nodep, 0, 0);
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
VCMethod::DYN_SIZE};
newp->dtypeSetSigned32();
newp->dtypeSetInt();
} else if (nodep->name() == "delete") { // function void delete()
methodOkArguments(nodep, 0, 0);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
@ -4544,7 +4544,7 @@ class WidthVisitor final : public VNVisitor {
methodOkArguments(nodep, 0, 0);
newp = new AstCMethodHard{nodep->fileline(), nodep->fromp()->unlinkFrBack(),
VCMethod::DYN_SIZE};
newp->dtypeSetSigned32();
newp->dtypeSetInt();
} else if (nodep->name() == "delete") { // function void delete([input integer index])
methodOkArguments(nodep, 0, 1);
methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE);
@ -4870,7 +4870,7 @@ class WidthVisitor final : public VNVisitor {
<< "\n"
<< (suggest.empty() ? "" : nodep->fileline()->warnMore() + suggest));
}
nodep->dtypeSetSigned32(); // Guess on error
nodep->dtypeSetInteger(); // Guess on error
}
void methodCallConstraint(AstMethodCall* nodep, AstConstraintRefDType*) {
if (nodep->name() == "constraint_mode") {
@ -6474,7 +6474,7 @@ class WidthVisitor final : public VNVisitor {
void visit(AstFGetS* nodep) override {
assertAtExpr(nodep);
if (m_vup->prelim()) {
nodep->dtypeSetSigned32(); // Spec says integer return
nodep->dtypeSetInteger2State(); // Spec says integer return
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
userIterateAndNext(nodep->strgp(), WidthVP{SELF, BOTH}.p());
}
@ -6490,7 +6490,7 @@ class WidthVisitor final : public VNVisitor {
void visit(AstFRead* nodep) override {
assertAtExpr(nodep);
if (m_vup->prelim()) {
nodep->dtypeSetSigned32(); // Spec says integer return
nodep->dtypeSetInteger2State(); // Spec says integer return
userIterateAndNext(nodep->memp(), WidthVP{SELF, BOTH}.p());
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
if (nodep->startp()) {
@ -6504,7 +6504,7 @@ class WidthVisitor final : public VNVisitor {
void visit(AstFScanF* nodep) override {
assertAtExpr(nodep);
if (m_vup->prelim()) {
nodep->dtypeSetSigned32(); // Spec says integer return
nodep->dtypeSetInteger2State(); // Spec says integer return
iterateCheckFileDesc(nodep, nodep->filep(), BOTH);
userIterateAndNext(nodep->exprsp(), WidthVP{SELF, BOTH}.p());
}
@ -6512,7 +6512,7 @@ class WidthVisitor final : public VNVisitor {
void visit(AstSScanF* nodep) override {
assertAtExpr(nodep);
if (m_vup->prelim()) {
nodep->dtypeSetSigned32(); // Spec says integer return
nodep->dtypeSetInteger2State(); // Spec says integer return
userIterateAndNext(nodep->fromp(), WidthVP{SELF, BOTH}.p());
userIterateAndNext(nodep->exprsp(), WidthVP{SELF, BOTH}.p());
}
@ -6525,7 +6525,7 @@ class WidthVisitor final : public VNVisitor {
assertAtExpr(nodep);
if (m_vup->prelim()) {
userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p());
nodep->dtypeSetSigned32(); // Spec says integer return
nodep->dtypeSetInteger2State(); // Spec says integer return
}
}
void visit(AstSystemT* nodep) override {
@ -7632,7 +7632,7 @@ class WidthVisitor final : public VNVisitor {
assertAtExpr(nodep);
if (m_vup->prelim()) { // First stage evaluation
iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH);
nodep->dtypeSetSigned32();
nodep->dtypeSetInteger();
}
}
void visit_Ou64_Lr(AstNodeUniop* nodep) {
@ -8629,7 +8629,7 @@ class WidthVisitor final : public VNVisitor {
}
void iterateCheckSigned32(AstNode* parentp, const char* side, AstNode* underp, Stage stage) {
// Coerce child to signed32 if not already. Child is self-determined
iterateCheckTypedSelfPrelim(parentp, side, underp, parentp->findSigned32DType(), stage);
iterateCheckTypedSelfPrelim(parentp, side, underp, parentp->findIntDType(), stage);
}
void iterateCheckUInt32(AstNode* parentp, const char* side, AstNode* underp, Stage stage) {
// Coerce child to unsigned32 if not already. Child is self-determined
@ -9398,7 +9398,7 @@ class WidthVisitor final : public VNVisitor {
std::forward_as_tuple(nullptr));
if (pair.second) {
AstNodeArrayDType* const vardtypep
= new AstUnpackArrayDType{nodep->fileline(), nodep->findSigned32DType(),
= new AstUnpackArrayDType{nodep->fileline(), nodep->findIntDType(),
new AstRange(nodep->fileline(), msbdim, 0)};
AstInitArray* const initp = new AstInitArray{nodep->fileline(), vardtypep, nullptr};
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);

View File

@ -351,7 +351,7 @@ module Vt_debug_emitv_t;
end
force sum = 'sha;
begin : unnamedblk1_1
integer signed __Vrepeat0;
int signed __Vrepeat0;
__Vrepeat0 = 'sh2;
while ((__Vrepeat0 > 32'h0)) begin
if ((sum != 'sha)) begin
@ -778,7 +778,7 @@ package Vt_debug_emitv_std;
???? // CLASSREFDTYPE 'process'
;
begin : unnamedblk1_1
integer signed __Vrepeat0;
int signed __Vrepeat0;
__Vrepeat0 = processQueue.size();
while ((__Vrepeat0 > 32'h0)) begin
begin

View File

@ -1,21 +1,18 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed under the Creative Commons Public Domain
// SPDX-FileCopyrightText: 2024 Antmicro
// This file ONLY is placed under the Creative Commons Public Domain.
// SPDX-FileCopyrightText: 2026 Antmicro
// SPDX-License-Identifier: CC0-1.0
function bit get_1_or_0(bit get_1);
return get_1 ? 1'b1 : 1'b0;
endfunction
module t;
initial begin
if (get_1_or_0(0) ==? get_1_or_0(1)) $stop;
if (!(get_1_or_0(0) !=? get_1_or_0(1))) $stop;
if (('bxz10 ==? 'bxxx0) !== 1) $stop;
if (('bxz10 ==? 'bxxx1) !== 0) $stop;
if (('bxz10 ==? 'bx1xx) !== 'x) $stop;
if (('bxz10 !=? 'bxxx1) !== 1) $stop;
if (('bxz10 !=? 'bxxx0) !== 0) $stop;
if (('bxz10 !=? 'b1xx0) !== 'x) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

View File

@ -0,0 +1,6 @@
%Warning-FUTURE: --fourstate is not supported as is under development
... For warning description see https://verilator.org/warn/FUTURE?v=latest
... Use "/* verilator lint_off FUTURE */" and lint_on around source to disable this message.
%Error-UNSUPPORTED: --fourstate is not supported with hierarchical Verilation
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
%Error: Exiting due to

View File

@ -0,0 +1,20 @@
#!/usr/bin/env python3
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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.
# SPDX-FileCopyrightText: 2026 Wilson Snyder
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
import vltest_bootstrap
test.scenarios('simulator')
test.top_filename = "t_fourstate_fourstate_unsup.v"
test.lint(verilator_flags2=['--fourstate', '--hierarchical'],
fails=True,
expect_filename=test.golden_filename)
test.passes()

View File

@ -333,11 +333,11 @@
"typesp": [
{"type":"BASICDTYPE","name":"bit","addr":"(BD)","loc":"d,18:18,18:19","dtypep":"(BD)","keyword":"bit","generic":true,"rangep": []},
{"type":"BASICDTYPE","name":"bit","addr":"(ID)","loc":"d,19:34,19:39","dtypep":"(ID)","keyword":"bit","range":"1:0","generic":true,"rangep": []},
{"type":"BASICDTYPE","name":"logic","addr":"(FD)","loc":"d,19:31,19:33","dtypep":"(FD)","keyword":"logic","generic":true,"rangep": []},
{"type":"BASICDTYPE","name":"logic","addr":"(H)","loc":"d,9:11,9:16","dtypep":"(H)","keyword":"logic","range":"15:0","generic":true,"rangep": []},
{"type":"BASICDTYPE","name":"logic","addr":"(K)","loc":"d,11:12,11:17","dtypep":"(K)","keyword":"logic","range":"6:0","generic":true,"rangep": []},
{"type":"BASICDTYPE","name":"integer","addr":"(WB)","loc":"d,17:5,17:12","dtypep":"(WB)","keyword":"integer","range":"31:0","generic":true,"signed":true,"rangep": []},
{"type":"BASICDTYPE","name":"logic","addr":"(PD)","loc":"d,18:18,18:19","dtypep":"(PD)","keyword":"logic","range":"31:0","generic":true,"signed":true,"rangep": []},
{"type":"BASICDTYPE","name":"logic","addr":"(FD)","loc":"d,19:10,19:11","dtypep":"(FD)","keyword":"logic","generic":true,"rangep": []},
{"type":"BASICDTYPE","name":"logic","addr":"(XD)","loc":"d,19:10,19:11","dtypep":"(XD)","keyword":"logic","range":"2:0","generic":true,"signed":true,"rangep": []},
{"type":"BASICDTYPE","name":"bit","addr":"(TD)","loc":"d,19:11,19:12","dtypep":"(TD)","keyword":"bit","range":"31:0","generic":true,"rangep": []},
{"type":"BASICDTYPE","name":"logic","addr":"(KD)","loc":"d,19:20,19:21","dtypep":"(KD)","keyword":"logic","range":"1:0","generic":true,"rangep": []},

View File

@ -10,7 +10,7 @@
// verilog_format: on
interface intf ();
integer index;
int index;
endinterface
module t (