From d7a54b363241effad39b3bb2f743ed1bbd9a2bf5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 30 Mar 2017 19:05:55 -0400 Subject: [PATCH] Fix nested structure parameter selects, bug1150. --- Changes | 2 + src/V3Simulate.h | 87 ++++++++++++++++---------------- test_regress/t/t_struct_param.pl | 18 +++++++ test_regress/t/t_struct_param.v | 54 ++++++++++++++++++++ 4 files changed, 118 insertions(+), 43 deletions(-) create mode 100755 test_regress/t/t_struct_param.pl create mode 100644 test_regress/t/t_struct_param.v diff --git a/Changes b/Changes index d8c85fdab..6969191b0 100644 --- a/Changes +++ b/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 diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 9d4d59ac3..4ed8e2693 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -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"); diff --git a/test_regress/t/t_struct_param.pl b/test_regress/t/t_struct_param.pl new file mode 100755 index 000000000..f91289753 --- /dev/null +++ b/test_regress/t/t_struct_param.pl @@ -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; diff --git a/test_regress/t/t_struct_param.v b/test_regress/t/t_struct_param.v new file mode 100644 index 000000000..604b2ee4f --- /dev/null +++ b/test_regress/t/t_struct_param.v @@ -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