From 950e7a632c09c3451682d6c184b58991f3d72a31 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 4 Feb 2012 16:19:27 -0800 Subject: [PATCH] Parse multi-dimension packed arrays to pform. --- PExpr.cc | 4 +-- PWire.cc | 69 +++++++++++++++++++++++++++++++++---------- PWire.h | 24 ++++++++++----- elab_sig.cc | 68 +++++++++++++++++++++++------------------- parse.y | 15 +++++++--- pform.cc | 82 ++++++++++++++++++++++++++++++++------------------- pform.h | 5 ++-- pform_dump.cc | 16 ++++++---- 8 files changed, 185 insertions(+), 98 deletions(-) diff --git a/PExpr.cc b/PExpr.cc index b301cb3cb..7cbc649a4 100644 --- a/PExpr.cc +++ b/PExpr.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams + * Copyright (c) 1998-2012 Stephen Williams * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -346,7 +346,7 @@ void PEIdent::declare_implicit_nets(LexicalScope*scope, NetNet::Type type) PWire*net = new PWire(name, type, NetNet::NOT_A_PORT, IVL_VT_LOGIC); net->set_file(get_file()); net->set_lineno(get_lineno()); - net->set_range(0, 0, SR_NET, true); + net->set_range_scalar(SR_NET); scope->wires[name] = net; if (warn_implicit) { cerr << get_fileline() << ": warning: implicit " diff --git a/PWire.cc b/PWire.cc index a5d5407a3..e5402a6cc 100644 --- a/PWire.cc +++ b/PWire.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1999-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1999-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 @@ -28,8 +28,7 @@ PWire::PWire(perm_string n, ivl_variable_type_t dt) : name_(n), type_(t), port_type_(pt), data_type_(dt), signed_(false), isint_(false), - port_msb_(0), port_lsb_(0), port_set_(false), - net_msb_(0), net_lsb_(0), net_set_(false), is_scalar_(false), + port_set_(false), net_set_(false), is_scalar_(false), error_cnt_(0), lidx_(0), ridx_(0), enum_type_(0), struct_type_(0), discipline_(0) { @@ -149,8 +148,9 @@ bool PWire::get_scalar() const return is_scalar_; } -void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) +void PWire::set_range_scalar(PWSRType type) { + is_scalar_ = true; switch (type) { case SR_PORT: if (port_set_) { @@ -158,10 +158,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) << "'' has already been declared a port." << endl; error_cnt_ += 1; } else { - port_msb_ = m; - port_lsb_ = l; port_set_ = true; - is_scalar_ = is_scalar; } return; @@ -171,10 +168,7 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) << "'' has already been declared." << endl; error_cnt_ += 1; } else { - net_msb_ = m; - net_lsb_ = l; net_set_ = true; - is_scalar_ = is_scalar; } return; @@ -191,13 +185,58 @@ void PWire::set_range(PExpr*m, PExpr*l, PWSRType type, bool is_scalar) error_cnt_ += 1; } } else { - port_msb_ = m; - port_lsb_ = l; port_set_ = true; - net_msb_ = m; - net_lsb_ = l; net_set_ = true; - is_scalar_ = is_scalar; + } + return; + } +} + +void PWire::set_range(const list&rlist, PWSRType type) +{ + switch (type) { + case SR_PORT: + if (port_set_) { + cerr << get_fileline() << ": error: Port ``" << name_ + << "'' has already been declared a port." << endl; + error_cnt_ += 1; + } else { + port_ = rlist; + port_set_ = true; + is_scalar_ = false; + } + return; + + case SR_NET: + if (net_set_) { + cerr << get_fileline() << ": error: Net ``" << name_ + << "'' has already been declared." << endl; + error_cnt_ += 1; + } else { + net_ = rlist; + net_set_ = true; + is_scalar_ = false; + } + return; + + case SR_BOTH: + if (port_set_ || net_set_) { + if (port_set_) { + cerr << get_fileline() << ": error: Port ``" << name_ + << "'' has already been declared a port." << endl; + error_cnt_ += 1; + } + if (net_set_) { + cerr << get_fileline() << ": error: Net ``" << name_ + << "'' has already been declared." << endl; + error_cnt_ += 1; + } + } else { + port_ = rlist; + port_set_ = true; + net_ = rlist; + net_set_ = true; + is_scalar_ = false; } return; } diff --git a/PWire.h b/PWire.h index 96f1b4964..5b6606fae 100644 --- a/PWire.h +++ b/PWire.h @@ -1,7 +1,7 @@ #ifndef __PWire_H #define __PWire_H /* - * Copyright (c) 1998-2009 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2009,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 @@ -21,8 +21,8 @@ # include "netlist.h" # include "LineInfo.h" +# include # include -# include "svector.h" # include "StringHeap.h" #ifdef HAVE_IOSFWD @@ -51,6 +51,11 @@ enum PWSRType {SR_PORT, SR_NET, SR_BOTH}; * the wire name. */ class PWire : public LineInfo { + public: + struct range_t { + PExpr*msb; + PExpr*lsb; + }; public: PWire(perm_string name, @@ -75,7 +80,8 @@ class PWire : public LineInfo { bool set_data_type(ivl_variable_type_t dt); ivl_variable_type_t get_data_type() const; - void set_range(PExpr*msb, PExpr*lsb, PWSRType type, bool is_scalar); + void set_range_scalar(PWSRType type); + void set_range(const std::list&ranges, PWSRType type); void set_memory_idx(PExpr*ldx, PExpr*rdx); @@ -101,12 +107,14 @@ class PWire : public LineInfo { bool isint_; // original type of integer // These members hold expressions for the bit width of the - // wire. If they do not exist, the wire is 1 bit wide. - PExpr*port_msb_; - PExpr*port_lsb_; + // wire. If they do not exist, the wire is 1 bit wide. If they + // do exist, they represent the packed dimensions of the + // bit. The first item in the list is the first range, and so + // on. For example "reg [3:0][7:0] ..." will contains the + // range_t object for [3:0] first and [7:0] last. + std::listport_; bool port_set_; - PExpr*net_msb_; - PExpr*net_lsb_; + std::listnet_; bool net_set_; bool is_scalar_; unsigned error_cnt_; diff --git a/elab_sig.cc b/elab_sig.cc index 1c749413a..06854a52b 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2000-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 @@ -890,29 +890,31 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const long pmsb = 0, plsb = 0, nmsb = 0, nlsb = 0; bool bad_lsb = false, bad_msb = false; /* If they exist get the port definition MSB and LSB */ - if (port_set_ && port_msb_ != 0) { - NetExpr*texpr = elab_and_eval(des, scope, port_msb_, -1, true); + if (port_set_ && !port_.empty()) { + assert(port_.size() == 1); + PWire::range_t rng = port_.front(); + NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); if (! eval_as_long(pmsb, texpr)) { - cerr << port_msb_->get_fileline() << ": error: " + cerr << rng.msb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << port_msb_->get_fileline() << " : " + cerr << rng.msb->get_fileline() << " : " "This MSB expression violates the rule: " - << *port_msb_ << endl; + << *rng.msb << endl; des->errors += 1; bad_msb = true; } delete texpr; - texpr = elab_and_eval(des, scope, port_lsb_, -1, true); + texpr = elab_and_eval(des, scope, rng.lsb, -1, true); if (! eval_as_long(plsb, texpr)) { - cerr << port_lsb_->get_fileline() << ": error: " + cerr << rng.lsb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << port_lsb_->get_fileline() << " : " + cerr << rng.lsb->get_fileline() << " : " "This LSB expression violates the rule: " - << *port_lsb_ << endl; + << *rng.lsb << endl; des->errors += 1; bad_lsb = true; } @@ -923,49 +925,53 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const /* An implicit port can have a range so note that here. */ is_implicit_scalar = false; } - if (!port_set_) assert(port_msb_ == 0 && port_lsb_ == 0); - if (port_msb_ == 0) assert(port_lsb_ == 0); - if (port_lsb_ == 0) assert(port_msb_ == 0); + if (!port_set_) assert(port_.empty()); + + if (net_.size() > 1) { + cerr << net_.back().msb->get_fileline() << ": sorry: " + << "Multi-dimension packed arrays not supported." + << endl; + des->errors += 1; + } /* If they exist get the net/etc. definition MSB and LSB */ - if (net_set_ && net_msb_ != 0 && !bad_msb && !bad_lsb) { - NetExpr*texpr = elab_and_eval(des, scope, net_msb_, -1, true); + if (net_set_ && !net_.empty() && !bad_msb && !bad_lsb) { + PWire::range_t rng = net_.front(); + NetExpr*texpr = elab_and_eval(des, scope, rng.msb, -1, true); if (! eval_as_long(nmsb, texpr)) { - cerr << net_msb_->get_fileline() << ": error: " + cerr << rng.msb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << net_msb_->get_fileline() << " : " + cerr << rng.msb->get_fileline() << " : " "This MSB expression violates the rule: " - << *net_msb_ << endl; + << *rng.msb << endl; des->errors += 1; bad_msb = true; } delete texpr; - texpr = elab_and_eval(des, scope, net_lsb_, -1, true); + texpr = elab_and_eval(des, scope, rng.lsb, -1, true); if (! eval_as_long(nlsb, texpr)) { - cerr << net_lsb_->get_fileline() << ": error: " + cerr << rng.lsb->get_fileline() << ": error: " "Range expressions must be constant." << endl; - cerr << net_lsb_->get_fileline() << " : " + cerr << rng.lsb->get_fileline() << " : " "This LSB expression violates the rule: " - << *net_lsb_ << endl; + << *rng.lsb << endl; des->errors += 1; bad_lsb = true; } delete texpr; } - if (!net_set_) assert(net_msb_ == 0 && net_lsb_ == 0); - if (net_msb_ == 0) assert(net_lsb_ == 0); - if (net_lsb_ == 0) assert(net_msb_ == 0); + if (!net_set_) assert(net_.empty()); /* We have a port size error */ if (port_set_ && net_set_ && (pmsb != nmsb || plsb != nlsb)) { /* Scalar port with a vector net/etc. definition */ - if (port_msb_ == 0) { + if (port_.empty()) { if (!gn_io_range_error_flag) { cerr << get_fileline() << ": warning: Scalar port ``" << name_ @@ -982,8 +988,8 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } /* Vectored port with a scalar net/etc. definition */ - if (net_msb_ == 0) { - cerr << port_msb_->get_fileline() + if (net_.empty()) { + cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" << name_ << "'' [" << pmsb << ":" << plsb << "] has a scalar net declaration at " @@ -993,12 +999,12 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const } /* Both vectored, but they have different ranges. */ - if (port_msb_ != 0 && net_msb_ != 0) { - cerr << port_msb_->get_fileline() + if (!port_.empty() && !net_.empty()) { + cerr << port_.front().msb->get_fileline() << ": error: Vectored port ``" << name_ << "'' [" << pmsb << ":" << plsb << "] has a net declaration [" << nmsb << ":" - << nlsb << "] at " << net_msb_->get_fileline() + << nlsb << "] at " << net_.front().msb->get_fileline() << " that does not match." << endl; des->errors += 1; return 0; diff --git a/parse.y b/parse.y index dbb46dd31..149f19af7 100644 --- a/parse.y +++ b/parse.y @@ -1,7 +1,7 @@ %{ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -3931,12 +3931,19 @@ range tmp->push_back($4); $$ = tmp; } + | range '[' expression ':' expression ']' + { list*tmp = $1; + tmp->push_back($3); + tmp->push_back($5); + $$ = tmp; + } ; range_opt - : range - | { $$ = 0; } - ; + : range + | { $$ = 0; } + ; + dimensions_opt : { $$ = 0; } | dimensions { $$ = $1; } diff --git a/pform.cc b/pform.cc index 8ff97b60a..9716ffdd9 100644 --- a/pform.cc +++ b/pform.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -1480,6 +1480,20 @@ void pform_make_udp(perm_string name, bool synchronous_flag, delete init_expr; } +static void ranges_from_list(list&rlist, const list*range) +{ + // There must be an even number of expressions in the + // range. The parser will assure that for us. + assert(range->size()%2 == 0); + list::const_iterator rcur = range->begin(); + while (rcur != range->end()) { + PWire::range_t rng; + rng.msb = *rcur; ++rcur; + rng.lsb = *rcur; ++rcur; + rlist.push_back(rng); + } +} + /* * This function attaches a range to a given name. The function is * only called by the parser within the scope of the net declaration, @@ -1500,11 +1514,12 @@ static void pform_set_net_range(perm_string name, if (range == 0) { /* This is the special case that we really mean a scalar. Set a fake range. */ - cur->set_range(0, 0, rt, true); + cur->set_range_scalar(rt); } else { - assert(range->size() == 2); - cur->set_range(range->front(), range->back(), rt, false); + list rlist; + ranges_from_list(rlist, range); + cur->set_range(rlist, rt); } cur->set_signed(signed_flag); @@ -1515,15 +1530,14 @@ static void pform_set_net_range(perm_string name, void pform_set_net_range(list*names, list*range, bool signed_flag, - ivl_variable_type_t dt, - PWSRType rt) + ivl_variable_type_t dt) { - assert((range == 0) || (range->size() == 2)); + assert((range == 0) || (range->size()%2 == 0)); for (list::iterator cur = names->begin() ; cur != names->end() ; ++ cur ) { perm_string txt = *cur; - pform_set_net_range(txt, range, signed_flag, dt, rt); + pform_set_net_range(txt, range, signed_flag, dt, SR_NET); } delete names; @@ -1884,17 +1898,12 @@ void pform_module_define_port(const struct vlltype&li, cur->set_signed(signed_flag); if (range == 0) { - cur->set_range(0, 0, (type == NetNet::IMPLICIT) ? SR_PORT : - SR_BOTH, - true); + cur->set_range_scalar((type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } else { - assert(range->size() == 2); - assert(range->front()); - assert(range->back()); - cur->set_range(range->front(), range->back(), - (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH, - false); + list rlist; + ranges_from_list(rlist, range); + cur->set_range(rlist, (type == NetNet::IMPLICIT) ? SR_PORT : SR_BOTH); } pform_bind_attributes(cur->attributes, attr); @@ -1981,7 +1990,7 @@ void pform_makewire(const vlltype&li, perm_string name, << " to " << dt << "." << endl; } ivl_assert(*cur, flag); - cur->set_range(0, 0, SR_NET, true); + cur->set_range_scalar(SR_NET); cur->set_signed(true); break; default: @@ -2168,8 +2177,9 @@ svector*pform_make_task_ports(NetNet::PortType pt, /* If there is a range involved, it needs to be set. */ if (range) { - assert(range->size() == 2); - curw->set_range(range->front(), range->back(), SR_PORT, false); + list rlist; + ranges_from_list(rlist, range); + curw->set_range(rlist, SR_PORT); } svector*tmp = new svector(*res, curw); @@ -2458,9 +2468,12 @@ static void pform_set_reg_integer(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::INTEGER, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - cur->set_range(new PENumber(new verinum(integer_width-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + PWire::range_t rng; + rng.msb = new PENumber(new verinum(integer_width-1, integer_width)); + rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); cur->set_signed(true); } @@ -2479,9 +2492,12 @@ static void pform_set_reg_time(perm_string name) PWire*cur = pform_get_make_wire_in_scope(name, NetNet::REG, NetNet::NOT_A_PORT, IVL_VT_LOGIC); assert(cur); - cur->set_range(new PENumber(new verinum(TIME_WIDTH-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + PWire::range_t rng; + rng.msb = new PENumber(new verinum(TIME_WIDTH-1, integer_width)); + rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); } void pform_set_reg_time(list*names) @@ -2500,9 +2516,13 @@ static void pform_set_integer_2atom(uint64_t width, bool signed_flag, perm_strin assert(cur); cur->set_signed(signed_flag); - cur->set_range(new PENumber(new verinum(width-1, integer_width)), - new PENumber(new verinum((uint64_t)0, integer_width)), - SR_NET, false); + + PWire::range_t rng; + rng.msb = new PENumber(new verinum(width-1, integer_width)); + rng.lsb = new PENumber(new verinum((uint64_t)0, integer_width)); + listrlist; + rlist.push_back(rng); + cur->set_range(rlist, SR_NET); } void pform_set_integer_2atom(uint64_t width, bool signed_flag, list*names) @@ -2545,7 +2565,9 @@ static void pform_set_enum(const struct vlltype&li, enum_type_t*enum_type, assert(enum_type->range.get() != 0); assert(enum_type->range->size() == 2); - cur->set_range(enum_type->range->front(), enum_type->range->back(), SR_NET, false); + listrlist; + ranges_from_list(rlist, enum_type->range.get()); + cur->set_range(rlist, SR_NET); cur->set_enumeration(enum_type); } diff --git a/pform.h b/pform.h index dbdf85942..b32ccce70 100644 --- a/pform.h +++ b/pform.h @@ -1,7 +1,7 @@ #ifndef __pform_H #define __pform_H /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -287,8 +287,7 @@ extern void pform_set_port_type(perm_string nm, NetNet::PortType pt, extern void pform_set_net_range(list*names, list*, bool signed_flag, - ivl_variable_type_t, - PWSRType rt = SR_NET); + ivl_variable_type_t); extern void pform_set_reg_idx(perm_string name, PExpr*l, PExpr*r); extern void pform_set_reg_integer(list*names); extern void pform_set_reg_time(list*names); diff --git a/pform_dump.cc b/pform_dump.cc index 88fa71520..9d13320f1 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-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 @@ -351,17 +351,23 @@ void PWire::dump(ostream&out, unsigned ind) const } if (port_set_) { - if (port_msb_ == 0) { + if (port_.empty()) { out << " port"; } else { - out << " port[" << *port_msb_ << ":" << *port_lsb_ << "]"; + out << " port"; + for (list::const_iterator cur = port_.begin() + ; cur != port_.end() ; ++cur) + out << "[" << *cur->msb << ":" << *cur->lsb << "]"; } } if (net_set_) { - if (net_msb_ == 0) { + if (net_.empty()) { out << " net"; } else { - out << " net[" << *net_msb_ << ":" << *net_lsb_ << "]"; + out << " net"; + for (list::const_iterator cur = net_.begin() + ; cur != net_.end() ; ++cur) + out << "[" << *cur->msb << ":" << *cur->lsb << "]"; } }