diff --git a/Makefile.in b/Makefile.in index 7bd62d4f1..57500f88e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -106,7 +106,8 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ elab_expr.o elaborate_analog.o elab_lval.o elab_net.o \ elab_scope.o elab_sig.o elab_sig_analog.o emit.o eval.o eval_attrib.o \ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ - load_module.o netlist.o netmisc.o net_analog.o net_assign.o net_design.o \ + load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \ + net_design.o \ netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \ net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \ diff --git a/design_dump.cc b/design_dump.cc index 2ded152a2..f42676183 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -187,9 +187,9 @@ void NetDelaySrc::dump(ostream&o, unsigned ind) const dump_node_pins(o, ind+4); } -ostream&operator<<(ostream&out, const list&rlist) +ostream&operator<<(ostream&out, const list&rlist) { - for (list::const_iterator cur = rlist.begin() + for (list::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { out << "[" << cur->msb << ":" << cur->lsb << "]"; } diff --git a/elab_expr.cc b/elab_expr.cc index 213a580db..f0b6a2896 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -1442,24 +1442,59 @@ static const netstruct_t::member_t*get_struct_member(const LineInfo*li, return type->packed_member(method_name, off); } - +/* + * Test if the tail name (method_name argument) is a member name and + * the net is a struct. If that turns out to be the case, and the + * struct is packed, then return a NetExpr that selects the member out + * of the variable. + */ static NetExpr* check_for_struct_members(const LineInfo*li, - Design*des, NetScope*, - NetNet*net, perm_string method_name) + Design*des, NetScope*scope, + NetNet*net, const name_component_t&comp) { unsigned long off; const netstruct_t::member_t*mem = get_struct_member(li, des, 0, net, - method_name, off); + comp.name, off); if (mem == 0) return 0; if (debug_elaborate) { - cerr << li->get_fileline() << ": debug: Found struct member " <name + cerr << li->get_fileline() << ": debug: Found struct member " << mem->name << " At offset " << off << endl; } + unsigned use_width = mem->width(); + + if ( ! comp.index.empty() ) { + // Evaluate all but the last index expression, into prefix_indices. + listprefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, comp.index); + ivl_assert(*li, rc); + + // Evaluate the last index expression into a constant long. + NetExpr*texpr = elab_and_eval(des, scope, comp.index.back().msb, -1, true); + long tmp; + if (texpr == 0 || !eval_as_long(tmp, texpr)) { + cerr << li->get_fileline() << ": error: " + "Array index expressions must be constant here." << endl; + des->errors += 1; + return false; + } + + delete texpr; + + // Now use the prefix_to_slice function to calculate the + // offset and width of the addressed slice of the member. + long loff; + unsigned long lwid; + prefix_to_slice(mem->packed_dims, prefix_indices, tmp, loff, lwid); + + off += loff; + use_width = lwid; + } + NetESignal*sig = new NetESignal(net); NetEConst*base = make_const_val(off); - NetESelect*sel = new NetESelect(sig, base, mem->width()); + NetESelect*sel = new NetESelect(sig, base, use_width); return sel; } @@ -2350,7 +2385,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, // really a method attached to an object. if (gn_system_verilog() && found_in==0 && path_.size() >= 2) { pform_name_t use_path = path_; - perm_string method_name = peek_tail_name(use_path); + name_component_t member_comp = use_path.back(); use_path.pop_back(); found_in = symbol_search(this, des, scope, use_path, @@ -2372,7 +2407,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, return check_for_enum_methods(this, des, scope, netenum, - use_path, method_name, + use_path, member_comp.name, expr, expr_wid, NULL, 0); } @@ -2382,7 +2417,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, ivl_assert(*this, use_path.back().index.empty()); return check_for_struct_members(this, des, scope, - net, method_name); + net, member_comp); } } @@ -3279,11 +3314,11 @@ NetExpr* PEIdent::elaborate_expr_net_idx_up_(Design*des, NetScope*scope, long lsv = base_c->value().as_long(); long offset = 0; // Get the signal range. - const list&packed = net->sig()->packed_dims(); + const list&packed = net->sig()->packed_dims(); ivl_assert(*this, packed.size() == prefix_indices.size()+1); // We want the last range, which is where we work. - const NetNet::range_t&rng = packed.back(); + const netrange_t&rng = packed.back(); if (rng.msb < rng.lsb) { offset = -wid + 1; } @@ -3494,7 +3529,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, long msv = msc->value().as_long(); - const list& sig_packed = net->sig()->packed_dims(); + const list& sig_packed = net->sig()->packed_dims(); if (prefix_indices.size()+2 <= sig_packed.size()) { // Special case: this is a slice of a multi-dimensional // packed array. For example: @@ -3561,7 +3596,7 @@ NetExpr* PEIdent::elaborate_expr_net_bit_(Design*des, NetScope*scope, return res; } - const list& sig_packed = net->sig()->packed_dims(); + const list& sig_packed = net->sig()->packed_dims(); if (prefix_indices.size()+2 <= sig_packed.size()) { // Special case: this is a slice of a multi-dimensional // packed array. For example: diff --git a/elab_lval.cc b/elab_lval.cc index 2cfb98016..bed52b95a 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -455,7 +455,7 @@ bool PEIdent::elaborate_lval_net_part_(Design*des, NetNet*reg = lv->sig(); ivl_assert(*this, reg); - const list&packed = reg->packed_dims(); + const list&packed = reg->packed_dims(); // Part selects cannot select slices. So there must be enough // prefix_indices to get all the way to the final dimension. @@ -544,11 +544,11 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, long lsv = base_c->value().as_long(); long offset = 0; // Get the signal range. - const list&packed = reg->packed_dims(); + const list&packed = reg->packed_dims(); ivl_assert(*this, packed.size() == prefix_indices.size()+1); // We want the last range, which is where we work. - const NetNet::range_t&rng = packed.back(); + const netrange_t&rng = packed.back(); if (((rng.msb < rng.lsb) && use_sel == index_component_t::SEL_IDX_UP) || ((rng.msb > rng.lsb) && @@ -621,8 +621,7 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } -bool PEIdent::elaborate_lval_net_packed_member_(Design*des, - NetScope*, +bool PEIdent::elaborate_lval_net_packed_member_(Design*des, NetScope*scope, NetAssign_*lv, const perm_string&member_name) const { @@ -649,7 +648,57 @@ bool PEIdent::elaborate_lval_net_packed_member_(Design*des, return false; } - lv->set_part(new NetEConst(verinum(off)), member->width()); + unsigned long use_width = member->width(); + + // We are processing the tail of a string of names. For + // example, the verilog may be "a.b.c", so we are processing + // "c" at this point. Of course, "c" is the name of the member + // we are working on and "a.b" is the name of reg. + const name_component_t&name_tail = path_.back(); + + if (name_tail.index.size() > member->packed_dims.size()) { + cerr << get_fileline() << ": error: Too make index expressions for member." << endl; + des->errors += 1; + return false; + } + + // Get the index component type. At this point, we only + // support bit select or none. + index_component_t::ctype_t use_sel = index_component_t::SEL_NONE; + if (!name_tail.index.empty()) + use_sel = name_tail.index.back().sel; + + ivl_assert(*this, use_sel == index_component_t::SEL_NONE || use_sel == index_component_t::SEL_BIT); + + if (name_tail.index.size() > 0) { + // Evaluate all but the last index expression, into prefix_indices. + listprefix_indices; + bool rc = evaluate_index_prefix(des, scope, prefix_indices, name_tail.index); + ivl_assert(*this, rc); + + // Evaluate the last index expression into a constant long. + NetExpr*texpr = elab_and_eval(des, scope, name_tail.index.back().msb, -1, true); + long tmp; + if (texpr == 0 || !eval_as_long(tmp, texpr)) { + cerr << get_fileline() << ": error: " + "Array index expressions must be constant here." << endl; + des->errors += 1; + return false; + } + + delete texpr; + + // Now use the prefix_to_slice function to calculate the + // offset and width of the addressed slice of the member. + long loff; + unsigned long lwid; + prefix_to_slice(member->packed_dims, prefix_indices, tmp, loff, lwid); + + off += loff; + use_width = lwid; + } + + lv->set_part(new NetEConst(verinum(off)), use_width); return true; } diff --git a/elab_sig.cc b/elab_sig.cc index f5ba9d4ca..93b6aa06b 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -514,8 +514,8 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const des->errors += 1; } - list packed; - packed.push_back(NetNet::range_t(mnum, lnum)); + list packed; + packed.push_back(netrange_t(mnum, lnum)); ret_sig = new NetNet(scope, fname, NetNet::REG, packed); ret_sig->set_scalar(false); @@ -813,61 +813,15 @@ void PWhile::elaborate_sig(Design*des, NetScope*scope) const statement_->elaborate_sig(des, scope); } -static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, - struct_type_t*struct_type) -{ - netstruct_t*res = new netstruct_t; - - res->packed(struct_type->packed_flag); - - for (list::iterator cur = struct_type->members->begin() - ; cur != struct_type->members->end() ; ++ cur) { - - struct_member_t*curp = *cur; - long use_msb = 0; - long use_lsb = 0; - if (curp->range.get() && ! curp->range->empty()) { - ivl_assert(*curp, curp->range->size() == 1); - pform_range_t&rangep = curp->range->front(); - PExpr*msb_pex = rangep.first; - PExpr*lsb_pex = rangep.second; - - NetExpr*tmp = elab_and_eval(des, scope, msb_pex, -2, true); - ivl_assert(*curp, tmp); - bool rc = eval_as_long(use_msb, tmp); - ivl_assert(*curp, rc); - - tmp = elab_and_eval(des, scope, lsb_pex, -2, true); - ivl_assert(*curp, tmp); - rc = eval_as_long(use_lsb, tmp); - ivl_assert(*curp, rc); - } - - for (list::iterator name = curp->names->begin() - ; name != curp->names->end() ; ++ name) { - decl_assignment_t*namep = *name; - - netstruct_t::member_t memb; - memb.name = namep->name; - memb.type = curp->type; - memb.msb = use_msb; - memb.lsb = use_lsb; - res->append_member(memb); - } - } - - return res; -} - static bool evaluate_ranges(Design*des, NetScope*scope, - list&llist, + list&llist, const list&rlist) { bool bad_msb = false, bad_lsb = false; for (list::const_iterator cur = rlist.begin() ; cur != rlist.end() ; ++cur) { - NetNet::range_t lrng; + netrange_t lrng; NetExpr*texpr = elab_and_eval(des, scope, cur->first, -1, true); if (! eval_as_long(lrng.msb, texpr)) { @@ -901,13 +855,49 @@ static bool evaluate_ranges(Design*des, NetScope*scope, return bad_msb | bad_lsb; } -bool test_ranges_eeq(const list&lef, const list&rig) +static netstruct_t* elaborate_struct_type(Design*des, NetScope*scope, + struct_type_t*struct_type) +{ + netstruct_t*res = new netstruct_t; + + res->packed(struct_type->packed_flag); + + for (list::iterator cur = struct_type->members->begin() + ; cur != struct_type->members->end() ; ++ cur) { + + listpacked_dimensions; + + struct_member_t*curp = *cur; + if (curp->range.get() && ! curp->range->empty()) { + bool bad_range; + bad_range = evaluate_ranges(des, scope, packed_dimensions, *curp->range); + ivl_assert(*curp, !bad_range); + } else { + packed_dimensions.push_back(netrange_t(0,0)); + } + + for (list::iterator name = curp->names->begin() + ; name != curp->names->end() ; ++ name) { + decl_assignment_t*namep = *name; + + netstruct_t::member_t memb; + memb.name = namep->name; + memb.type = curp->type; + memb.packed_dims = packed_dimensions; + res->append_member(memb); + } + } + + return res; +} + +bool test_ranges_eeq(const list&lef, const list&rig) { if (lef.size() != rig.size()) return false; - list::const_iterator lcur = lef.begin(); - list::const_iterator rcur = rig.begin(); + list::const_iterator lcur = lef.begin(); + list::const_iterator rcur = rig.begin(); while (lcur != lef.end()) { if (lcur->msb != rcur->msb) return false; @@ -942,7 +932,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } unsigned wid = 1; - listpacked_dimensions; + listpacked_dimensions; des->errors += error_cnt_; @@ -983,7 +973,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const if (port_set_ || net_set_) { bool bad_range = false; - list plist, nlist; + list plist, nlist; /* If they exist get the port definition MSB and LSB */ if (port_set_ && !port_.empty()) { bad_range |= evaluate_ranges(des, scope, plist, port_); @@ -1049,7 +1039,7 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } packed_dimensions = nlist; - wid = NetNet::vector_width(packed_dimensions); + wid = netrange_width(packed_dimensions); } diff --git a/netlist.cc b/netlist.cc index ef0b6c1a6..8dec0c40b 100644 --- a/netlist.cc +++ b/netlist.cc @@ -458,7 +458,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, unsigned npins) assert(npins>0); // Synthesize a single range to describe this canonical vector. - packed_dims_.push_back(NetNet::range_t(npins-1, 0)); + packed_dims_.push_back(netrange_t(npins-1, 0)); Link::DIR dir = Link::PASSIVE; @@ -496,7 +496,7 @@ void NetNet::initialize_dir_(Link::DIR dir) } NetNet::NetNet(NetScope*s, perm_string n, Type t, - const list&packed) + const list&packed) : NetObj(s, n, 1), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), is_scalar_(false), local_flag_(false), @@ -544,7 +544,7 @@ static unsigned calculate_count(long s, long e) } NetNet::NetNet(NetScope*s, perm_string n, Type t, - const list&packed, long array_s, long array_e) + const list&packed, long array_s, long array_e) : NetObj(s, n, calculate_count(array_s, array_e)), type_(t), port_type_(NOT_A_PORT), data_type_(IVL_VT_NO_TYPE), signed_(false), isint_(false), @@ -605,7 +605,7 @@ NetNet::NetNet(NetScope*s, perm_string n, Type t, netstruct_t*ty) dimensions_(0), s0_(0), e0_(0), eref_count_(0), lref_count_(0) { - packed_dims_.push_back(range_t(calculate_count(ty)-1, 0)); + packed_dims_.push_back(netrange_t(calculate_count(ty)-1, 0)); Link::DIR dir = Link::PASSIVE; switch (t) { @@ -764,27 +764,11 @@ void NetNet::set_discipline(ivl_discipline_t dis) discipline_ = dis; } -unsigned long NetNet::vector_width(const list&packed) -{ - unsigned wid = 1; - for (list::const_iterator cur = packed.begin() - ; cur != packed.end() ; ++cur) { - unsigned use_wid; - if (cur->msb >= cur->lsb) - use_wid = cur->msb - cur->lsb + 1; - else - use_wid = cur->lsb - cur->msb + 1; - wid *= use_wid; - } - - return wid; -} - bool NetNet::sb_is_valid(const list&indices, long sb) const { ivl_assert(*this, indices.size()+1 == packed_dims_.size()); assert(packed_dims_.size() == 1); - const range_t&rng = packed_dims_.back(); + const netrange_t&rng = packed_dims_.back(); if (rng.msb >= rng.lsb) return (sb <= rng.msb) && (sb >= rng.lsb); else @@ -795,7 +779,7 @@ long NetNet::sb_to_idx(const list&indices, long sb) const { ivl_assert(*this, indices.size()+1 == packed_dims_.size()); - list::const_iterator pcur = packed_dims_.end(); + list::const_iterator pcur = packed_dims_.end(); -- pcur; long acc_off; @@ -832,50 +816,7 @@ long NetNet::sb_to_idx(const list&indices, long sb) const bool NetNet::sb_to_slice(const list&indices, long sb, long&loff, unsigned long&lwid) const { ivl_assert(*this, indices.size() < packed_dims_.size()); - - size_t acc_wid = 1; - list::const_iterator pcur = packed_dims_.end(); - for (size_t idx = indices.size()+1 ; idx < packed_dims_.size() ; idx += 1) { - -- pcur; - acc_wid *= pcur->width(); - } - - lwid = acc_wid; - - -- pcur; - if (sb < pcur->msb && sb < pcur->lsb) - return false; - if (sb > pcur->msb && sb > pcur->lsb) - return false; - - long acc_off = 0; - if (pcur->msb >= pcur->lsb) - acc_off += (sb - pcur->lsb) * acc_wid; - else - acc_off += (sb - pcur->msb) * acc_wid; - - if (indices.size() == 0) { - loff = acc_off; - return true; - } - - lwid *= pcur->width(); - - list::const_iterator icur = indices.end(); - do { - -- pcur; - -- icur; - acc_wid *= pcur->width(); - if (pcur->msb >= pcur->lsb) - acc_off += (*icur - pcur->lsb) * acc_wid; - else - acc_off += (*icur - pcur->msb) * acc_wid; - - } while (icur != indices.begin()); - - loff = acc_off; - - return true; + return prefix_to_slice(packed_dims_, indices, sb, loff, lwid); } @@ -2461,14 +2402,14 @@ NetNet* NetESignal::sig() */ long NetESignal::lsi() const { - const list&packed = net_->packed_dims(); + const list&packed = net_->packed_dims(); ivl_assert(*this, packed.size() == 1); return packed.back().lsb; } long NetESignal::msi() const { - const list&packed = net_->packed_dims(); + const list&packed = net_->packed_dims(); ivl_assert(*this, packed.size() == 1); return packed.back().msb; } diff --git a/netlist.h b/netlist.h index ba9ff80e3..0300f5cc8 100644 --- a/netlist.h +++ b/netlist.h @@ -35,6 +35,7 @@ # include "ivl_target_priv.h" # include "pform_types.h" # include "config.h" +# include "nettypes.h" # include "verinum.h" # include "verireal.h" # include "StringHeap.h" @@ -563,21 +564,6 @@ class NetNet : public NetObj { enum PortType { NOT_A_PORT, PIMPLICIT, PINPUT, POUTPUT, PINOUT, PREF }; - struct range_t { - inline range_t() : msb(0), lsb(0) { } - inline range_t(long m, long l) : msb(m), lsb(l) { } - inline range_t(const range_t&that) - : msb(that.msb), lsb(that.lsb) { } - inline range_t& operator = (const range_t&that) - { msb = that.msb; lsb = that.lsb; return *this; } - - long msb; - long lsb; - - inline unsigned long width()const - { if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; } - }; - public: // The width in this case is a shorthand for ms=width-1 and // ls=0. Only one pin is created, the width is of the vector @@ -589,9 +575,9 @@ class NetNet : public NetObj { // dimensions. If s0==e0, then this is not an array after // all. explicit NetNet(NetScope*s, perm_string n, Type t, - const std::list&packed); + const std::list&packed); explicit NetNet(NetScope*s, perm_string n, Type t, - const std::list&packed, long s0, long e0); + const std::list&packed, long s0, long e0); // This form builds a NetNet from its record definition. explicit NetNet(NetScope*s, perm_string n, Type t, netstruct_t*type); @@ -633,14 +619,11 @@ class NetNet : public NetObj { for the vector. These are arranged as a list where the first range in the list (front) is the left-most range in the verilog declaration. */ - const std::list& packed_dims() const { return packed_dims_; } + const std::list& packed_dims() const { return packed_dims_; } /* The vector_width returns the bit width of the packed array, - vector or scaler that is this NetNet object. The static - method is also a convenient way to convert a range list to - a vector width. */ - static unsigned long vector_width(const std::list&); - unsigned long vector_width() const { return vector_width(packed_dims_); } + vector or scaler that is this NetNet object. */ + unsigned long vector_width() const { return netrange_width(packed_dims_); } /* Given a prefix of indices, figure out how wide the resulting slice would be. This is a generalization of the @@ -722,7 +705,7 @@ class NetNet : public NetObj { netstruct_t*struct_type_; ivl_discipline_t discipline_; - std::list packed_dims_; + std::list packed_dims_; const unsigned dimensions_; long s0_, e0_; @@ -736,7 +719,7 @@ class NetNet : public NetObj { vector delay_paths_; }; -extern std::ostream&operator << (std::ostream&out, const std::list&rlist); +extern std::ostream&operator << (std::ostream&out, const std::list&rlist); /* * This object type is used to contain a logical scope within a diff --git a/netmisc.cc b/netmisc.cc index 9ce4ebf00..06b8d0a3d 100644 --- a/netmisc.cc +++ b/netmisc.cc @@ -320,24 +320,24 @@ NetExpr *normalize_variable_base(NetExpr *base, long msb, long lsb, * vector. For now, we assert that there is only one set of dimensions. */ NetExpr *normalize_variable_base(NetExpr *base, - const list&dims, + const list&dims, unsigned long wid, bool is_up) { ivl_assert(*base, dims.size() == 1); - const NetNet::range_t&rng = dims.back(); + const netrange_t&rng = dims.back(); return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up); } NetExpr *normalize_variable_bit_base(const list&indices, NetExpr*base, const NetNet*reg) { - const list&packed_dims = reg->packed_dims(); + const list&packed_dims = reg->packed_dims(); ivl_assert(*base, indices.size()+1 == packed_dims.size()); // Get the canonical offset of the slice within which we are // addressing. We need that address as a slice offset to // calculate the proper complete address - const NetNet::range_t&rng = packed_dims.back(); + const netrange_t&rng = packed_dims.back(); long slice_off = reg->sb_to_idx(indices, rng.lsb); return normalize_variable_base(base, rng.msb, rng.lsb, 1, true, slice_off); @@ -347,13 +347,13 @@ NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, const NetNet*reg, unsigned long wid, bool is_up) { - const list&packed_dims = reg->packed_dims(); + const list&packed_dims = reg->packed_dims(); ivl_assert(*base, indices.size()+1 == packed_dims.size()); // Get the canonical offset of the slice within which we are // addressing. We need that address as a slice offset to // calculate the proper complete address - const NetNet::range_t&rng = packed_dims.back(); + const netrange_t&rng = packed_dims.back(); long slice_off = reg->sb_to_idx(indices, rng.lsb); return normalize_variable_base(base, rng.msb, rng.lsb, wid, is_up, slice_off); @@ -362,10 +362,10 @@ NetExpr *normalize_variable_part_base(const list&indices, NetExpr*base, NetExpr *normalize_variable_slice_base(const list&indices, NetExpr*base, const NetNet*reg, unsigned long&lwid) { - const list&packed_dims = reg->packed_dims(); + const list&packed_dims = reg->packed_dims(); ivl_assert(*base, indices.size() < packed_dims.size()); - list::const_iterator pcur = packed_dims.end(); + list::const_iterator pcur = packed_dims.end(); for (size_t idx = indices.size() ; idx < packed_dims.size(); idx += 1) { -- pcur; } diff --git a/netmisc.h b/netmisc.h index 0504db472..f9104910f 100644 --- a/netmisc.h +++ b/netmisc.h @@ -102,7 +102,7 @@ extern NetExpr*normalize_variable_base(NetExpr *base, long msb, long lsb, unsigned long wid, bool is_up, long slice_off =0); extern NetExpr*normalize_variable_base(NetExpr *base, - const list&dims, + const list&dims, unsigned long wid, bool is_up); /* diff --git a/netstruct.h b/netstruct.h index b84df6a4a..0ffb2d55c 100644 --- a/netstruct.h +++ b/netstruct.h @@ -22,6 +22,7 @@ # include "LineInfo.h" # include # include "ivl_target.h" +# include "nettypes.h" class netstruct_t : public LineInfo { @@ -29,8 +30,7 @@ class netstruct_t : public LineInfo { struct member_t { perm_string name; ivl_variable_type_t type; - long msb; - long lsb; + list packed_dims; long width() const; ivl_variable_type_t data_type() const { return type; }; // We need to keep the individual element sign information. @@ -63,11 +63,6 @@ class netstruct_t : public LineInfo { inline bool netstruct_t::packed(void) const { return packed_; } inline long netstruct_t::member_t::width() const -{ - if (msb >= lsb) - return msb - lsb + 1; - else - return lsb - msb + 1; -} +{ return netrange_width(packed_dims); } #endif diff --git a/nettypes.cc b/nettypes.cc new file mode 100644 index 000000000..bec698378 --- /dev/null +++ b/nettypes.cc @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "nettypes.h" +# include + +using namespace std; + +unsigned long netrange_width(const list&packed) +{ + unsigned wid = 1; + for (list::const_iterator cur = packed.begin() + ; cur != packed.end() ; ++cur) { + unsigned use_wid; + if (cur->msb >= cur->lsb) + use_wid = cur->msb - cur->lsb + 1; + else + use_wid = cur->lsb - cur->msb + 1; + wid *= use_wid; + } + + return wid; +} + +/* + * Given a netrange_t list (which represent packed dimensions) and a + * prefix of calculated index values, calculate the canonical offset + * and width of the resulting slice. In this case, the "sb" argument + * is an extra index of the prefix. + */ +bool prefix_to_slice(const std::list&dims, + const std::list&prefix, long sb, + long&loff, unsigned long&lwid) +{ + assert(prefix.size() < dims.size()); + + size_t acc_wid = 1; + list::const_iterator pcur = dims.end(); + for (size_t idx = prefix.size()+1 ; idx < dims.size() ; idx += 1) { + -- pcur; + acc_wid *= pcur->width(); + } + + lwid = acc_wid; + + -- pcur; + if (sb < pcur->msb && sb < pcur->lsb) + return false; + if (sb > pcur->msb && sb > pcur->lsb) + return false; + + long acc_off = 0; + if (pcur->msb >= pcur->lsb) + acc_off += (sb - pcur->lsb) * acc_wid; + else + acc_off += (sb - pcur->msb) * acc_wid; + + if (prefix.size() == 0) { + loff = acc_off; + return true; + } + + lwid *= pcur->width(); + + list::const_iterator icur = prefix.end(); + do { + -- pcur; + -- icur; + acc_wid *= pcur->width(); + if (pcur->msb >= pcur->lsb) + acc_off += (*icur - pcur->lsb) * acc_wid; + else + acc_off += (*icur - pcur->msb) * acc_wid; + + } while (icur != prefix.begin()); + + loff = acc_off; + + return true; +} diff --git a/nettypes.h b/nettypes.h new file mode 100644 index 000000000..6c1c5e60b --- /dev/null +++ b/nettypes.h @@ -0,0 +1,55 @@ +#ifndef __nettypes_H +#define __nettypes_H +/* + * Copyright (c) 2012 Stephen Williams (steve@icarus.com) + * + * This source code is free software; you can redistribute it + * and/or modify it in source code form under the terms of the GNU + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include + +class netrange_t { + + public: + inline netrange_t() : msb(0), lsb(0) { } + inline netrange_t(long m, long l) : msb(m), lsb(l) { } + + inline netrange_t(const netrange_t&that) + : msb(that.msb), lsb(that.lsb) { } + + inline netrange_t& operator = (const netrange_t&that) + { msb = that.msb; lsb = that.lsb; return *this; } + + public: + long msb; + long lsb; + + inline unsigned long width()const + { if (msb >= lsb) return msb-lsb+1; else return lsb-msb+1; } +}; + +extern unsigned long netrange_width(const std::list&dims); + +/* + * Take as input a list of packed dimensions and a list of prefix + * indices, and calculate the offset/width of the resulting slice into + * the packed array. + */ +extern bool prefix_to_slice(const std::list&dims, + const std::list&prefix, long sb, + long&loff, unsigned long&lwid); + +#endif diff --git a/t-dll.cc b/t-dll.cc index e16f8477f..2381d1202 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -2387,7 +2387,7 @@ void dll_target::signal(const NetNet*net) ivl_signal_t object. */ { size_t idx = 0; - list::const_iterator cur; + list::const_iterator cur; obj->packed_dims.resize(net->packed_dims().size()); for (cur = net->packed_dims().begin(), idx = 0 ; cur != net->packed_dims().end() ; ++cur, idx += 1) { diff --git a/t-dll.h b/t-dll.h index 2bdae36bb..9b64f2831 100644 --- a/t-dll.h +++ b/t-dll.h @@ -690,7 +690,7 @@ struct ivl_signal_s { /* These encode the declared packed dimensions for the signal, in case they are needed by the run-time */ - std::vector packed_dims; + std::vector packed_dims; perm_string name_; ivl_scope_t scope_;