Fix nested structure parameter selects, bug1150.
This commit is contained in:
parent
be6a3d0f10
commit
d7a54b3632
2
Changes
2
Changes
|
|
@ -33,6 +33,8 @@ The contributors that suggested a given feature are shown in []. Thanks!
|
||||||
|
|
||||||
**** Fix wreal not handling continuous assign, bug1150. [J Briquet]
|
**** Fix wreal not handling continuous assign, bug1150. [J Briquet]
|
||||||
|
|
||||||
|
**** Fix nested structure parameter selects, bug1150. [J Briquet]
|
||||||
|
|
||||||
|
|
||||||
* Verilator 3.900 2017-01-15
|
* Verilator 3.900 2017-01-15
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -468,52 +468,53 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool handleAssignSel(AstNodeAssign* nodep, AstSel* selp, AstVarRef** outVarrefp, int depth) {
|
void handleAssignSel(AstNodeAssign* nodep, AstSel* selp) {
|
||||||
|
AstVarRef* varrefp = NULL;
|
||||||
|
V3Number lsb = V3Number(nodep->fileline());
|
||||||
|
nodep->rhsp()->iterateAndNext(*this); // Value to assign
|
||||||
|
handleAssignSelRecurse(nodep, selp, varrefp/*ref*/, lsb/*ref*/, 0);
|
||||||
|
if (!m_checkOnly && optimizable()) {
|
||||||
|
if (!varrefp) nodep->v3fatalSrc("Indicated optimizable, but no variable found on RHS of select");
|
||||||
|
AstNode* vscp = varOrScope(varrefp);
|
||||||
|
V3Number outnum = V3Number(nodep->fileline());
|
||||||
|
if (V3Number* vscpnump = fetchOutNumberNull(vscp)) {
|
||||||
|
outnum = *vscpnump;
|
||||||
|
} else if (V3Number* vscpnump = fetchNumberNull(vscp)) {
|
||||||
|
outnum = *vscpnump;
|
||||||
|
} else { // Assignment to unassigned variable, all bits are X or 0
|
||||||
|
outnum = V3Number(nodep->fileline(), varrefp->varp()->widthMin());
|
||||||
|
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
|
||||||
|
outnum.setAllBits0();
|
||||||
|
} else {
|
||||||
|
outnum.setAllBitsX();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outnum.opSelInto(*fetchNumber(nodep->rhsp()),
|
||||||
|
lsb,
|
||||||
|
selp->widthConst());
|
||||||
|
assignOutNumber(nodep, vscp, &outnum);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void handleAssignSelRecurse (AstNodeAssign* nodep, AstSel* selp,
|
||||||
|
AstVarRef*& outVarrefpRef, V3Number& lsbRef,
|
||||||
|
int depth) {
|
||||||
|
// Recurse down to find final variable being set (outVarrefp), with value to write on nodep->rhsp()
|
||||||
checkNodeInfo(selp);
|
checkNodeInfo(selp);
|
||||||
AstVarRef* varrefp = selp->fromp()->castVarRef();
|
selp->lsbp()->iterateAndNext(*this); // Bit index
|
||||||
if (!varrefp) {
|
if (AstVarRef* varrefp = selp->fromp()->castVarRef()) {
|
||||||
selp = selp->lhsp()->castSel();
|
outVarrefpRef = varrefp;
|
||||||
if (selp) {
|
lsbRef = *fetchNumber(selp->lsbp());
|
||||||
if (!handleAssignSel(nodep, selp, &varrefp, depth+1)) {
|
return; // And presumably still optimizable()
|
||||||
clearOptimizable(nodep, "Select LHS isn't simple variable");
|
} else if (AstSel* subselp = selp->lhsp()->castSel()) {
|
||||||
return false;
|
V3Number sublsb = V3Number(nodep->fileline());
|
||||||
}
|
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb/*ref*/, depth+1);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_checkOnly) {
|
|
||||||
nodep->iterateChildren(*this);
|
|
||||||
} else {
|
|
||||||
selp->lsbp()->iterateAndNext(*this);
|
|
||||||
nodep->rhsp()->iterateAndNext(*this);
|
|
||||||
|
|
||||||
if (optimizable()) {
|
if (optimizable()) {
|
||||||
if (varrefp) {
|
lsbRef = sublsb;
|
||||||
AstNode* vscp = varOrScope(varrefp);
|
lsbRef.opAdd(sublsb, *fetchNumber(selp->lsbp()));
|
||||||
V3Number outnum = V3Number(nodep->fileline());
|
|
||||||
if (V3Number* vscpnump = fetchOutNumberNull(vscp)) {
|
|
||||||
outnum = *vscpnump;
|
|
||||||
} else if (V3Number* vscpnump = fetchNumberNull(vscp)) {
|
|
||||||
outnum = *vscpnump;
|
|
||||||
} else { // Assignment to unassigned variable, all bits are X or 0
|
|
||||||
outnum = V3Number(nodep->fileline(), varrefp->varp()->widthMin());
|
|
||||||
if (varrefp->varp()->basicp() && varrefp->varp()->basicp()->isZeroInit()) {
|
|
||||||
outnum.setAllBits0();
|
|
||||||
} else {
|
|
||||||
outnum.setAllBitsX();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (depth == 0) {
|
|
||||||
outnum.opSelInto(*fetchNumber(nodep->rhsp()),
|
|
||||||
*fetchNumber(selp->lsbp()),
|
|
||||||
selp->widthConst());
|
|
||||||
assignOutNumber(nodep, vscp, &outnum);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
clearOptimizable(nodep, "Select LHS isn't simple variable");
|
||||||
}
|
}
|
||||||
if (outVarrefp) *outVarrefp = varrefp;
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void visit(AstNodeAssign* nodep) {
|
virtual void visit(AstNodeAssign* nodep) {
|
||||||
|
|
@ -530,7 +531,7 @@ private:
|
||||||
|
|
||||||
if (AstSel* selp = nodep->lhsp()->castSel()) {
|
if (AstSel* selp = nodep->lhsp()->castSel()) {
|
||||||
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
|
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
|
||||||
handleAssignSel(nodep, selp, NULL, 0);
|
handleAssignSel(nodep, selp);
|
||||||
}
|
}
|
||||||
else if (!nodep->lhsp()->castVarRef()) {
|
else if (!nodep->lhsp()->castVarRef()) {
|
||||||
clearOptimizable(nodep, "LHS isn't simple variable");
|
clearOptimizable(nodep, "LHS isn't simple variable");
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -0,0 +1,54 @@
|
||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed into the Public Domain, for any use,
|
||||||
|
// without warranty, 2017 by Matt Myers.
|
||||||
|
|
||||||
|
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
|
||||||
|
|
||||||
|
package config_pkg;
|
||||||
|
typedef struct packed {
|
||||||
|
int UPPER0;
|
||||||
|
struct packed {
|
||||||
|
int USE_QUAD0;
|
||||||
|
int USE_QUAD1;
|
||||||
|
int USE_QUAD2;
|
||||||
|
} mac;
|
||||||
|
int UPPER2;
|
||||||
|
} config_struct;
|
||||||
|
|
||||||
|
function automatic config_struct static_config(int selector);
|
||||||
|
config_struct return_config;
|
||||||
|
return_config = '0;
|
||||||
|
return_config.UPPER0 = 10;
|
||||||
|
return_config.UPPER2 = 20;
|
||||||
|
return_config.mac.USE_QUAD0 = 4;
|
||||||
|
return_config.mac.USE_QUAD2 = 6;
|
||||||
|
case (selector)
|
||||||
|
1: return_config.mac.USE_QUAD1 = 5;
|
||||||
|
endcase
|
||||||
|
return (return_config);
|
||||||
|
endfunction
|
||||||
|
endpackage : config_pkg
|
||||||
|
|
||||||
|
module t;
|
||||||
|
import config_pkg::*;
|
||||||
|
|
||||||
|
localparam config_struct MY_CONFIG = static_config(1);
|
||||||
|
|
||||||
|
struct_submodule #(.MY_CONFIG(MY_CONFIG)) a_submodule_I ();
|
||||||
|
endmodule : t
|
||||||
|
|
||||||
|
module struct_submodule
|
||||||
|
import config_pkg::*;
|
||||||
|
#(parameter config_struct MY_CONFIG = '0);
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
`checkd(MY_CONFIG.UPPER0, 10);
|
||||||
|
`checkd(MY_CONFIG.mac.USE_QUAD0, 4);
|
||||||
|
`checkd(MY_CONFIG.mac.USE_QUAD1, 5);
|
||||||
|
`checkd(MY_CONFIG.mac.USE_QUAD2, 6);
|
||||||
|
`checkd(MY_CONFIG.UPPER2, 20);
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
endmodule : struct_submodule
|
||||||
Loading…
Reference in New Issue