Fix late constant division by zero giving X error, bug775.
This commit is contained in:
parent
71b2eed32c
commit
475e4207cc
2
Changes
2
Changes
|
|
@ -25,6 +25,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||||
|
|
||||||
**** Fix C compiler interpreting signing, bug773. [Clifford Wolf]
|
**** Fix C compiler interpreting signing, bug773. [Clifford Wolf]
|
||||||
|
|
||||||
|
**** Fix late constant division by zero giving X error, bug775. [Clifford Wolf]
|
||||||
|
|
||||||
**** Fix gate primitives with arrays and non-arrayed pins.
|
**** Fix gate primitives with arrays and non-arrayed pins.
|
||||||
|
|
||||||
**** Fix DETECTARRAY error on packed arrays, bug770. [Jie Xu]
|
**** Fix DETECTARRAY error on packed arrays, bug770. [Jie Xu]
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,7 @@ class V3Global {
|
||||||
int m_debugFileNumber; // Number to append to debug files created
|
int m_debugFileNumber; // Number to append to debug files created
|
||||||
bool m_assertDTypesResolved; // Tree should have dtypep()'s
|
bool m_assertDTypesResolved; // Tree should have dtypep()'s
|
||||||
bool m_assertWidthsMatch; // Tree should have width()==widthMin()
|
bool m_assertWidthsMatch; // Tree should have width()==widthMin()
|
||||||
|
bool m_constRemoveXs; // Const needs to strip any Xs
|
||||||
bool m_needHInlines; // Need __Inlines file
|
bool m_needHInlines; // Need __Inlines file
|
||||||
bool m_needHeavy; // Need verilated_heavy.h include
|
bool m_needHeavy; // Need verilated_heavy.h include
|
||||||
bool m_dpi; // Need __Dpi include files
|
bool m_dpi; // Need __Dpi include files
|
||||||
|
|
@ -58,6 +59,7 @@ public:
|
||||||
m_debugFileNumber = 0;
|
m_debugFileNumber = 0;
|
||||||
m_assertDTypesResolved = false;
|
m_assertDTypesResolved = false;
|
||||||
m_assertWidthsMatch = false;
|
m_assertWidthsMatch = false;
|
||||||
|
m_constRemoveXs = false;
|
||||||
m_needHInlines = false;
|
m_needHInlines = false;
|
||||||
m_needHeavy = false;
|
m_needHeavy = false;
|
||||||
m_dpi = false;
|
m_dpi = false;
|
||||||
|
|
@ -77,6 +79,8 @@ public:
|
||||||
static void dumpCheckGlobalTree(const string& filename, int newNumber=0, bool doDump=true);
|
static void dumpCheckGlobalTree(const string& filename, int newNumber=0, bool doDump=true);
|
||||||
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
|
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
|
||||||
void assertWidthsMatch(bool flag) { m_assertWidthsMatch = flag; }
|
void assertWidthsMatch(bool flag) { m_assertWidthsMatch = flag; }
|
||||||
|
bool constRemoveXs() const { return m_constRemoveXs; }
|
||||||
|
void constRemoveXs(bool flag) { m_constRemoveXs = flag; }
|
||||||
string debugFilename(const string& nameComment, int newNumber=0) {
|
string debugFilename(const string& nameComment, int newNumber=0) {
|
||||||
++m_debugFileNumber;
|
++m_debugFileNumber;
|
||||||
if (newNumber) m_debugFileNumber = newNumber;
|
if (newNumber) m_debugFileNumber = newNumber;
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include <cstdarg>
|
#include <cstdarg>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include "V3Global.h"
|
||||||
#include "V3Number.h"
|
#include "V3Number.h"
|
||||||
|
|
||||||
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
|
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
|
||||||
|
|
@ -323,6 +324,7 @@ V3Number& V3Number::setAllBits1() {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
V3Number& V3Number::setAllBitsX() {
|
V3Number& V3Number::setAllBitsX() {
|
||||||
|
// Use setAllBitsXRemoved if calling this based on a non-X/Z input value such as divide by zero
|
||||||
for (int i=0; i<words(); i++) { m_value[i]=m_valueX[i] = ~0; }
|
for (int i=0; i<words(); i++) { m_value[i]=m_valueX[i] = ~0; }
|
||||||
opCleanThis();
|
opCleanThis();
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -332,6 +334,20 @@ V3Number& V3Number::setAllBitsZ() {
|
||||||
opCleanThis();
|
opCleanThis();
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
V3Number& V3Number::setAllBitsXRemoved() {
|
||||||
|
if (!v3Global.constRemoveXs()) {
|
||||||
|
return setAllBitsX();
|
||||||
|
} else {
|
||||||
|
// If we get a divide by zero we get Xs.
|
||||||
|
// But after V3Unknown we have removed Xs, so use --x-assign to direct-insert 0/1
|
||||||
|
if (v3Global.opt.xAssign() == "1") {
|
||||||
|
return setAllBits1();
|
||||||
|
} else {
|
||||||
|
return setAllBits0();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
V3Number& V3Number::setMask(int nbits) {
|
V3Number& V3Number::setMask(int nbits) {
|
||||||
setZero();
|
setZero();
|
||||||
for (int bit=0; bit<nbits; bit++) { setBit(bit,1); }
|
for (int bit=0; bit<nbits; bit++) { setBit(bit,1); }
|
||||||
|
|
@ -1248,7 +1264,7 @@ V3Number& V3Number::opDiv (const V3Number& lhs, const V3Number& rhs) {
|
||||||
UINFO(9, "opdiv "<<lhs<<" "<<rhs<<endl);
|
UINFO(9, "opdiv "<<lhs<<" "<<rhs<<endl);
|
||||||
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
|
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
|
||||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||||
if (rhs.isEqZero()) return setAllBitsX();
|
if (rhs.isEqZero()) return setAllBitsXRemoved();
|
||||||
if (lhs.width()<=64) {
|
if (lhs.width()<=64) {
|
||||||
setQuad(lhs.toUQuad() / rhs.toUQuad());
|
setQuad(lhs.toUQuad() / rhs.toUQuad());
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -1261,7 +1277,7 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
|
||||||
// Signed divide
|
// Signed divide
|
||||||
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
|
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
|
||||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||||
if (rhs.isEqZero()) return setAllBitsX();
|
if (rhs.isEqZero()) return setAllBitsXRemoved();
|
||||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||||
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
|
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
|
||||||
|
|
@ -1278,7 +1294,7 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
|
||||||
V3Number& V3Number::opModDiv (const V3Number& lhs, const V3Number& rhs) {
|
V3Number& V3Number::opModDiv (const V3Number& lhs, const V3Number& rhs) {
|
||||||
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
|
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
|
||||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||||
if (rhs.isEqZero()) return setAllBitsX();
|
if (rhs.isEqZero()) return setAllBitsXRemoved();
|
||||||
if (lhs.width()<=64) {
|
if (lhs.width()<=64) {
|
||||||
setQuad(lhs.toUQuad() % rhs.toUQuad());
|
setQuad(lhs.toUQuad() % rhs.toUQuad());
|
||||||
return *this;
|
return *this;
|
||||||
|
|
@ -1290,7 +1306,7 @@ V3Number& V3Number::opModDiv (const V3Number& lhs, const V3Number& rhs) {
|
||||||
V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
|
V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
|
||||||
// Signed moddiv
|
// Signed moddiv
|
||||||
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
|
||||||
if (rhs.isEqZero()) return setAllBitsX();
|
if (rhs.isEqZero()) return setAllBitsXRemoved();
|
||||||
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
|
||||||
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
|
||||||
V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign);
|
V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign);
|
||||||
|
|
@ -1428,7 +1444,7 @@ V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs, bool lsign,
|
||||||
if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
|
if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
|
||||||
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
|
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
|
||||||
if (rsign && rhs.isNegative()) {
|
if (rsign && rhs.isNegative()) {
|
||||||
if (lhs.isEqZero()) return setAllBitsX();
|
if (lhs.isEqZero()) return setAllBitsXRemoved();
|
||||||
else if (lhs.isEqOne()) return setQuad(1);
|
else if (lhs.isEqOne()) return setQuad(1);
|
||||||
else if (lsign && lhs.isEqAllOnes()) {
|
else if (lsign && lhs.isEqAllOnes()) {
|
||||||
if (rhs.bitIs1(0)) return setAllBits1(); // -1^odd=-1
|
if (rhs.bitIs1(0)) return setAllBits1(); // -1^odd=-1
|
||||||
|
|
|
||||||
|
|
@ -145,6 +145,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
// SETTERS
|
// SETTERS
|
||||||
|
V3Number& setAllBitsXRemoved();
|
||||||
V3Number& setAllBitsX();
|
V3Number& setAllBitsX();
|
||||||
V3Number& setAllBitsZ();
|
V3Number& setAllBitsZ();
|
||||||
V3Number& setAllBits0();
|
V3Number& setAllBits0();
|
||||||
|
|
|
||||||
|
|
@ -256,6 +256,7 @@ void process () {
|
||||||
// Move assignments from X into MODULE temps.
|
// Move assignments from X into MODULE temps.
|
||||||
// (Before flattening, so each new X variable is shared between all scopes of that module.)
|
// (Before flattening, so each new X variable is shared between all scopes of that module.)
|
||||||
V3Unknown::unknownAll(v3Global.rootp());
|
V3Unknown::unknownAll(v3Global.rootp());
|
||||||
|
v3Global.constRemoveXs(true);
|
||||||
V3Global::dumpCheckGlobalTree("unknown.tree");
|
V3Global::dumpCheckGlobalTree("unknown.tree");
|
||||||
|
|
||||||
// Module inlining
|
// Module inlining
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/perl
|
||||||
|
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||||
|
# redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
|
||||||
|
compile (
|
||||||
|
verilator_flags2 => ['--x-assign 0'],
|
||||||
|
);
|
||||||
|
|
||||||
|
execute (
|
||||||
|
);
|
||||||
|
|
||||||
|
ok(1);
|
||||||
|
1;
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
module t(y);
|
||||||
|
output [3:0] y;
|
||||||
|
// bug775
|
||||||
|
// verilator lint_off WIDTH
|
||||||
|
assign y = ((0/0) ? 1 : 2) % 0;
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule
|
||||||
|
|
@ -11,7 +11,10 @@
|
||||||
`define c(v,vs) (v)
|
`define c(v,vs) (v)
|
||||||
`endif
|
`endif
|
||||||
|
|
||||||
module t (/*AUTOARG*/);
|
module t (/*AUTOARG*/
|
||||||
|
// Outputs
|
||||||
|
ow4_u
|
||||||
|
);
|
||||||
|
|
||||||
bit fail;
|
bit fail;
|
||||||
|
|
||||||
|
|
@ -157,4 +160,9 @@
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|
||||||
|
// bug775
|
||||||
|
output [3:0] ow4_u; // Must be consumed
|
||||||
|
assign ow4_u = ((0/0) ? 1 : 2) % 0;
|
||||||
|
|
||||||
endmodule
|
endmodule
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue