forked from github/verilator
Fix sign extension in large localparams, bug910.
This commit is contained in:
parent
1d6bcda014
commit
7312de6bc2
2
Changes
2
Changes
@ -9,6 +9,8 @@ indicates the contributor was also the author of the fix; Thanks!
|
||||
|
||||
**** Fix installing missing manpages, bug908. [Ahmed El-Mahmoudy]
|
||||
|
||||
**** Fix sign extension in large localparams, bug910. [Mike Thyer]
|
||||
|
||||
**** Fix core dump in sync-async warnings, bug911. [Sebastian Dressler]
|
||||
|
||||
**** Fix truncation warning with -pins-bv, bug912. [Alfonso Martinez]
|
||||
|
@ -1079,6 +1079,7 @@ public:
|
||||
//TODO stomp these width functions out, and call via dtypep() instead
|
||||
int width() const;
|
||||
int widthMin() const;
|
||||
int widthMinV() const { return v3Global.widthMinUsage()==VWidthMinUsage::VERILOG_WIDTH ? widthMin() : width(); }
|
||||
int widthWords() const { return VL_WORDS_I(width()); }
|
||||
bool isQuad() const { return (width()>VL_WORDSIZE && width()<=VL_QUADSIZE); }
|
||||
bool isWide() const { return (width()>VL_QUADSIZE); }
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
return num().isCaseEq(samep->castConst()->num()); }
|
||||
virtual int instrCount() const { return widthInstrs(); }
|
||||
bool isEqAllOnes() const { return num().isEqAllOnes(width()); }
|
||||
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMin()); }
|
||||
bool isEqAllOnesV() const { return num().isEqAllOnes(widthMinV()); }
|
||||
};
|
||||
|
||||
class AstRange : public AstNode {
|
||||
@ -3310,7 +3310,8 @@ public:
|
||||
dtypeSetLogicSized(width,width,AstNumeric::UNSIGNED); }
|
||||
ASTNODE_NODE_FUNCS(ExtendS, EXTENDS)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs) {
|
||||
out.opExtendS(lhs, lhsp()->widthMin()); }
|
||||
out.opExtendS(lhs, lhsp()->widthMinV());
|
||||
}
|
||||
virtual string emitVerilog() { return "%l"; }
|
||||
virtual string emitC() { return "VL_EXTENDS_%nq%lq(%nw,%lw, %P, %li)"; }
|
||||
virtual bool cleanOut() {return false;} virtual bool cleanLhs() {return true;}
|
||||
@ -4150,7 +4151,7 @@ public:
|
||||
}
|
||||
ASTNODE_NODE_FUNCS(ShiftRS, SHIFTRS)
|
||||
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) {
|
||||
out.opShiftRS(lhs,rhs,lhsp()->widthMin()); }
|
||||
out.opShiftRS(lhs,rhs,lhsp()->widthMinV()); }
|
||||
virtual string emitVerilog() { return "%k(%l %f>>> %r)"; }
|
||||
virtual string emitC() { return "VL_SHIFTRS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
|
||||
virtual string emitSimpleOperator() { return ""; }
|
||||
|
@ -204,6 +204,12 @@ public:
|
||||
|
||||
class BrokenCheckVisitor : public AstNVisitor {
|
||||
private:
|
||||
void checkWidthMin(AstNode* nodep) {
|
||||
if (nodep->width() != nodep->widthMin()
|
||||
&& v3Global.widthMinUsage()==VWidthMinUsage::MATCHES_WIDTH) {
|
||||
nodep->v3fatalSrc("Width != WidthMin");
|
||||
}
|
||||
}
|
||||
virtual void visit(AstNode* nodep, AstNUser*) {
|
||||
BrokenTable::setUnder(nodep,true);
|
||||
if (const char* whyp=nodep->broken()) {
|
||||
@ -220,18 +226,9 @@ private:
|
||||
if (nodep->dtypep()) nodep->v3fatalSrc("DType on node without hasDType(): "<<nodep->prettyTypeName());
|
||||
}
|
||||
if (nodep->getChildDTypep()) nodep->v3fatalSrc("childDTypep() non-null on node after should have removed");
|
||||
if (AstNodeDType* dnodep = nodep->castNodeDType()) {
|
||||
if (dnodep->width() != dnodep->widthMin()
|
||||
&& v3Global.assertWidthsMatch()) {
|
||||
dnodep->v3fatalSrc("Width != WidthMin");
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v3Global.assertWidthsMatch()) {
|
||||
if (nodep->width() != nodep->widthMin()) {
|
||||
nodep->v3fatalSrc("Width != WidthMin");
|
||||
}
|
||||
if (AstNodeDType* dnodep = nodep->castNodeDType()) checkWidthMin(dnodep);
|
||||
}
|
||||
checkWidthMin(nodep);
|
||||
nodep->iterateChildrenConst(*this);
|
||||
BrokenTable::setUnder(nodep,false);
|
||||
}
|
||||
|
@ -36,15 +36,35 @@ class AstNetlist;
|
||||
|
||||
|
||||
//######################################################################
|
||||
// V3 - The top level class for the entire program
|
||||
|
||||
class VWidthMinUsage {
|
||||
public:
|
||||
enum en {
|
||||
LINT_WIDTH,
|
||||
MATCHES_WIDTH,
|
||||
VERILOG_WIDTH
|
||||
};
|
||||
enum en m_e;
|
||||
inline VWidthMinUsage () : m_e(LINT_WIDTH) {}
|
||||
inline VWidthMinUsage (en _e) : m_e(_e) {}
|
||||
explicit inline VWidthMinUsage (int _e) : m_e(static_cast<en>(_e)) {}
|
||||
operator en () const { return m_e; }
|
||||
};
|
||||
inline bool operator== (VWidthMinUsage lhs, VWidthMinUsage rhs) { return (lhs.m_e == rhs.m_e); }
|
||||
inline bool operator== (VWidthMinUsage lhs, VWidthMinUsage::en rhs) { return (lhs.m_e == rhs); }
|
||||
inline bool operator== (VWidthMinUsage::en lhs, VWidthMinUsage rhs) { return (lhs == rhs.m_e); }
|
||||
|
||||
//######################################################################
|
||||
// V3Global - The top level class for the entire program
|
||||
|
||||
class V3Global {
|
||||
// Globals
|
||||
AstNetlist* m_rootp; // Root of entire netlist
|
||||
VWidthMinUsage m_widthMinUsage; // What AstNode::widthMin() is used for
|
||||
|
||||
int m_debugFileNumber; // Number to append to debug files created
|
||||
int m_assertWidthsMatch; // Tree should have width()==widthMin()
|
||||
bool m_assertDTypesResolved; // Tree should have dtypep()'s
|
||||
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_needHeavy; // Need verilated_heavy.h include
|
||||
@ -58,8 +78,8 @@ public:
|
||||
// CREATORS
|
||||
V3Global() {
|
||||
m_debugFileNumber = 0;
|
||||
m_widthMinUsage = VWidthMinUsage::LINT_WIDTH;
|
||||
m_assertDTypesResolved = false;
|
||||
m_assertWidthsMatch = false;
|
||||
m_constRemoveXs = false;
|
||||
m_needHInlines = false;
|
||||
m_needHeavy = false;
|
||||
@ -71,15 +91,15 @@ public:
|
||||
void clear();
|
||||
// ACCESSORS (general)
|
||||
AstNetlist* rootp() const { return m_rootp; }
|
||||
VWidthMinUsage widthMinUsage() const { return m_widthMinUsage; }
|
||||
bool assertDTypesResolved() const { return m_assertDTypesResolved; }
|
||||
bool assertWidthsMatch() const { return m_assertWidthsMatch; }
|
||||
|
||||
// METHODS
|
||||
void readFiles();
|
||||
void checkTree();
|
||||
static void dumpCheckGlobalTree(const string& filename, int newNumber=0, bool doDump=true);
|
||||
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
|
||||
void assertWidthsMatch(bool flag) { m_assertWidthsMatch = flag; }
|
||||
void widthMinUsage(const VWidthMinUsage& flag) { m_widthMinUsage = flag; }
|
||||
bool constRemoveXs() const { return m_constRemoveXs; }
|
||||
void constRemoveXs(bool flag) { m_constRemoveXs = flag; }
|
||||
string debugFilename(const string& nameComment, int newNumber=0) {
|
||||
|
@ -187,7 +187,7 @@ void process () {
|
||||
// Commit to the widths we've chosen; Make widthMin==width
|
||||
V3Width::widthCommit(v3Global.rootp());
|
||||
v3Global.assertDTypesResolved(true);
|
||||
v3Global.assertWidthsMatch(true);
|
||||
v3Global.widthMinUsage(VWidthMinUsage::MATCHES_WIDTH);
|
||||
|
||||
// Coverage insertion
|
||||
// Before we do dead code elimination and inlining, or we'll lose it.
|
||||
@ -448,7 +448,7 @@ void process () {
|
||||
|
||||
// Here down, widthMin() is the Verilog width, and width() is the C++ width
|
||||
// Bits between widthMin() and width() are irrelevant, but may be non zero.
|
||||
v3Global.assertWidthsMatch(false);
|
||||
v3Global.widthMinUsage(VWidthMinUsage::VERILOG_WIDTH);
|
||||
|
||||
// Make all math operations either 8, 16, 32 or 64 bits
|
||||
V3Clean::cleanAll(v3Global.rootp());
|
||||
|
18
test_regress/t/t_math_sign_extend.pl
Executable file
18
test_regress/t/t_math_sign_extend.pl
Executable file
@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
132
test_regress/t/t_math_sign_extend.v
Normal file
132
test_regress/t/t_math_sign_extend.v
Normal file
@ -0,0 +1,132 @@
|
||||
// DESCRIPTION: Verilator: Verilog Test module
|
||||
//
|
||||
// This test demonstrates an issue with sign extension.
|
||||
// Assigning to localparms larger than 32 bits broke in 3.862
|
||||
//
|
||||
// This file ONLY is placed into the Public Domain, for any use,
|
||||
// without warranty, 2015 by Mike Thyer.
|
||||
|
||||
module t (/*AUTOARG*/
|
||||
// Inputs
|
||||
clk
|
||||
);
|
||||
input clk;
|
||||
|
||||
|
||||
localparam [ 0:0] one1_lp = 1;
|
||||
localparam [ 1:0] one2_lp = 1;
|
||||
localparam [ 2:0] one3_lp = 1;
|
||||
localparam [ 3:0] one4_lp = 1;
|
||||
localparam [ 4:0] one5_lp = 1;
|
||||
localparam [ 5:0] one6_lp = 1;
|
||||
localparam [ 6:0] one7_lp = 1;
|
||||
localparam [ 7:0] one8_lp = 1;
|
||||
localparam [ 8:0] one9_lp = 1;
|
||||
localparam [ 9:0] one10_lp = 1;
|
||||
localparam [19:0] one20_lp = 1;
|
||||
localparam [29:0] one30_lp = 1;
|
||||
localparam [30:0] one31_lp = 1;
|
||||
localparam [31:0] one32_lp = 1;
|
||||
localparam [32:0] one33_lp = 1;
|
||||
localparam [33:0] one34_lp = 1;
|
||||
localparam [34:0] one35_lp = 1;
|
||||
localparam [35:0] one36_lp = 1;
|
||||
localparam [36:0] one37_lp = 1;
|
||||
localparam [37:0] one38_lp = 1;
|
||||
localparam [38:0] one39_lp = 1;
|
||||
localparam [39:0] one40_lp = 1;
|
||||
localparam [49:0] one50_lp = 1;
|
||||
localparam [59:0] one60_lp = 1;
|
||||
localparam [60:0] one61_lp = 1;
|
||||
localparam [61:0] one62_lp = 1;
|
||||
localparam [62:0] one63_lp = 1;
|
||||
localparam [63:0] one64_lp = 1;
|
||||
localparam [64:0] one65_lp = 1;
|
||||
localparam [65:0] one66_lp = 1;
|
||||
localparam [66:0] one67_lp = 1;
|
||||
localparam [67:0] one68_lp = 1;
|
||||
localparam [68:0] one69_lp = 1;
|
||||
localparam [69:0] one70_lp = 1;
|
||||
|
||||
bit all_ok = 1;
|
||||
|
||||
initial begin
|
||||
`ifdef TEST_VERBOSE
|
||||
$display("one1_lp : %x %d", one1_lp, one1_lp==1);
|
||||
$display("one2_lp : %x %d", one2_lp, one2_lp==1);
|
||||
$display("one3_lp : %x %d", one3_lp, one3_lp==1);
|
||||
$display("one4_lp : %x %d", one4_lp, one4_lp==1);
|
||||
$display("one5_lp : %x %d", one5_lp, one5_lp==1);
|
||||
$display("one6_lp : %x %d", one6_lp, one6_lp==1);
|
||||
$display("one7_lp : %x %d", one7_lp, one7_lp==1);
|
||||
$display("one8_lp : %x %d", one8_lp, one8_lp==1);
|
||||
$display("one9_lp : %x %d", one9_lp, one9_lp==1);
|
||||
$display("one10_lp: %x %d", one10_lp, one10_lp==1);
|
||||
$display("one20_lp: %x %d", one20_lp, one20_lp==1);
|
||||
$display("one30_lp: %x %d", one30_lp, one30_lp==1);
|
||||
$display("one31_lp: %x %d", one31_lp, one31_lp==1);
|
||||
$display("one32_lp: %x %d", one32_lp, one32_lp==1);
|
||||
$display("one33_lp: %x %d", one33_lp, one33_lp==1);
|
||||
$display("one34_lp: %x %d", one34_lp, one34_lp==1);
|
||||
$display("one35_lp: %x %d", one35_lp, one35_lp==1);
|
||||
$display("one36_lp: %x %d", one36_lp, one36_lp==1);
|
||||
$display("one37_lp: %x %d", one37_lp, one37_lp==1);
|
||||
$display("one38_lp: %x %d", one38_lp, one38_lp==1);
|
||||
$display("one39_lp: %x %d", one39_lp, one39_lp==1);
|
||||
$display("one40_lp: %x %d", one40_lp, one40_lp==1);
|
||||
$display("one50_lp: %x %d", one50_lp, one50_lp==1);
|
||||
$display("one60_lp: %x %d", one60_lp, one60_lp==1);
|
||||
$display("one61_lp: %x %d", one61_lp, one61_lp==1);
|
||||
$display("one62_lp: %x %d", one62_lp, one62_lp==1);
|
||||
$display("one63_lp: %x %d", one63_lp, one63_lp==1);
|
||||
$display("one64_lp: %x %d", one64_lp, one64_lp==1);
|
||||
$display("one65_lp: %x %d", one65_lp, one65_lp==1);
|
||||
$display("one66_lp: %x %d", one66_lp, one66_lp==1);
|
||||
$display("one67_lp: %x %d", one67_lp, one67_lp==1);
|
||||
$display("one68_lp: %x %d", one68_lp, one68_lp==1);
|
||||
$display("one69_lp: %x %d", one69_lp, one69_lp==1);
|
||||
$display("one70_lp: %x %d", one70_lp, one70_lp==1);
|
||||
`endif
|
||||
|
||||
all_ok &= one1_lp == 1;
|
||||
all_ok &= one2_lp == 1;
|
||||
all_ok &= one3_lp == 1;
|
||||
all_ok &= one4_lp == 1;
|
||||
all_ok &= one5_lp == 1;
|
||||
all_ok &= one6_lp == 1;
|
||||
all_ok &= one7_lp == 1;
|
||||
all_ok &= one8_lp == 1;
|
||||
all_ok &= one9_lp == 1;
|
||||
all_ok &= one10_lp == 1;
|
||||
all_ok &= one20_lp == 1;
|
||||
all_ok &= one30_lp == 1;
|
||||
all_ok &= one31_lp == 1;
|
||||
all_ok &= one32_lp == 1;
|
||||
all_ok &= one33_lp == 1;
|
||||
all_ok &= one34_lp == 1;
|
||||
all_ok &= one35_lp == 1;
|
||||
all_ok &= one36_lp == 1;
|
||||
all_ok &= one37_lp == 1;
|
||||
all_ok &= one38_lp == 1;
|
||||
all_ok &= one39_lp == 1;
|
||||
all_ok &= one40_lp == 1;
|
||||
all_ok &= one50_lp == 1;
|
||||
all_ok &= one60_lp == 1;
|
||||
all_ok &= one61_lp == 1;
|
||||
all_ok &= one62_lp == 1;
|
||||
all_ok &= one63_lp == 1;
|
||||
all_ok &= one64_lp == 1;
|
||||
all_ok &= one65_lp == 1;
|
||||
all_ok &= one66_lp == 1;
|
||||
all_ok &= one67_lp == 1;
|
||||
all_ok &= one68_lp == 1;
|
||||
all_ok &= one69_lp == 1;
|
||||
all_ok &= one70_lp == 1;
|
||||
|
||||
if (!all_ok) $stop;
|
||||
$write("*-* All Finished *-*\n");
|
||||
$finish;
|
||||
|
||||
end
|
||||
endmodule
|
||||
|
Loading…
Reference in New Issue
Block a user