Fix nested structure parameter selects, bug1150.

This commit is contained in:
Wilson Snyder 2017-03-30 19:05:55 -04:00
parent be6a3d0f10
commit d7a54b3632
4 changed files with 118 additions and 43 deletions

View File

@ -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 nested structure parameter selects, bug1150. [J Briquet]
* Verilator 3.900 2017-01-15

View File

@ -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);
AstVarRef* varrefp = selp->fromp()->castVarRef();
if (!varrefp) {
selp = selp->lhsp()->castSel();
if (selp) {
if (!handleAssignSel(nodep, selp, &varrefp, depth+1)) {
clearOptimizable(nodep, "Select LHS isn't simple variable");
return false;
}
}
}
if (m_checkOnly) {
nodep->iterateChildren(*this);
} else {
selp->lsbp()->iterateAndNext(*this);
nodep->rhsp()->iterateAndNext(*this);
selp->lsbp()->iterateAndNext(*this); // Bit index
if (AstVarRef* varrefp = selp->fromp()->castVarRef()) {
outVarrefpRef = varrefp;
lsbRef = *fetchNumber(selp->lsbp());
return; // And presumably still optimizable()
} else if (AstSel* subselp = selp->lhsp()->castSel()) {
V3Number sublsb = V3Number(nodep->fileline());
handleAssignSelRecurse(nodep, subselp, outVarrefpRef, sublsb/*ref*/, depth+1);
if (optimizable()) {
if (varrefp) {
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();
}
}
if (depth == 0) {
outnum.opSelInto(*fetchNumber(nodep->rhsp()),
*fetchNumber(selp->lsbp()),
selp->widthConst());
assignOutNumber(nodep, vscp, &outnum);
}
}
lsbRef = sublsb;
lsbRef.opAdd(sublsb, *fetchNumber(selp->lsbp()));
}
} else {
clearOptimizable(nodep, "Select LHS isn't simple variable");
}
if (outVarrefp) *outVarrefp = varrefp;
return true;
}
virtual void visit(AstNodeAssign* nodep) {
@ -530,7 +531,7 @@ private:
if (AstSel* selp = nodep->lhsp()->castSel()) {
if (!m_params) { clearOptimizable(nodep, "LHS has select"); return; }
handleAssignSel(nodep, selp, NULL, 0);
handleAssignSel(nodep, selp);
}
else if (!nodep->lhsp()->castVarRef()) {
clearOptimizable(nodep, "LHS isn't simple variable");

View 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;

View File

@ -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