forked from github/verilator
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 nested structure parameter selects, bug1150. [J Briquet]
|
||||
|
||||
|
||||
* 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);
|
||||
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");
|
||||
|
18
test_regress/t/t_struct_param.pl
Executable file
18
test_regress/t/t_struct_param.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;
|
54
test_regress/t/t_struct_param.v
Normal file
54
test_regress/t/t_struct_param.v
Normal 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
|
Loading…
Reference in New Issue
Block a user