iverilog/vhdlpp/vtype.cc

407 lines
9.4 KiB
C++
Raw Normal View History

/*
* Copyright (c) 2011 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
2012-08-29 03:41:23 +02:00
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "vtype.h"
2011-11-05 23:55:17 +01:00
# include "parse_types.h"
# include "compiler.h"
# include <map>
# include <typeinfo>
# include <cassert>
2015-02-06 10:44:22 +01:00
# include <algorithm>
using namespace std;
VType::~VType()
{
}
void VType::show(ostream&out) const
{
write_to_stream(out);
}
perm_string VType::get_generic_typename() const
{
char buf[16] = {0,};
snprintf(buf, 16, "type_%p", this);
return lex_strings.make(buf);
}
VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt, bool packed)
: type_(tt), packed_(packed)
{
}
VTypePrimitive::~VTypePrimitive()
{
}
void VTypePrimitive::show(ostream&out) const
{
switch (type_) {
case BIT:
out << "BIT";
break;
case INTEGER:
out << "INTEGER";
break;
case NATURAL:
out << "NATURAL";
break;
2014-08-06 15:00:35 +02:00
case REAL:
out << "REAL";
break;
case STDLOGIC:
out << "STD_LOGIC";
break;
2015-05-20 18:53:29 +02:00
case TIME:
out << "TIME";
break;
}
}
int VTypePrimitive::get_width(ScopeBase*) const
2015-02-26 13:27:47 +01:00
{
switch(type_) {
case BIT:
case STDLOGIC:
return 1;
case INTEGER:
case NATURAL:
return 32;
default:
std::cerr << "sorry: primitive type " << type_ <<
" has no get_width() implementation." << std::endl;
break;
2015-02-26 13:27:47 +01:00
}
return -1;
}
VTypeArray::range_t*VTypeArray::range_t::clone() const
{
return new VTypeArray::range_t(safe_clone(msb_), safe_clone(lsb_), direction_);
}
VTypeArray::VTypeArray(const VType*element, const vector<VTypeArray::range_t>&r, bool sv)
: etype_(element), ranges_(r), signed_flag_(sv), parent_(NULL)
{
}
2011-11-05 23:55:17 +01:00
/*
* Create a VTypeArray range set from a list of parsed ranges.
* FIXME: We are copying pointers from the ExpRange object into the
* range_t. This means that we cannot delete the ExpRange object
2011-11-05 23:55:17 +01:00
* unless we invent a way to remove the pointers from that object. So
* this is a memory leak. Something to fix.
*/
VTypeArray::VTypeArray(const VType*element, std::list<ExpRange*>*r, bool sv)
: etype_(element), ranges_(r->size()), signed_flag_(sv), parent_(NULL)
2011-11-05 23:55:17 +01:00
{
for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) {
ExpRange*curp = r->front();
2011-11-05 23:55:17 +01:00
r->pop_front();
2016-08-15 04:37:02 +02:00
ranges_[idx] = range_t(curp->msb(), curp->lsb(),
(curp->direction() == ExpRange::DOWNTO
? true
: false));
2011-11-05 23:55:17 +01:00
}
}
VTypeArray::VTypeArray(const VType*element, int msb, int lsb, bool sv)
: etype_(element), ranges_(1), signed_flag_(sv), parent_(NULL)
{
bool down_to = msb > lsb;
ranges_[0] = range_t(new ExpInteger(msb), new ExpInteger(lsb), down_to);
}
2011-11-05 23:55:17 +01:00
VTypeArray::~VTypeArray()
{
}
VType*VTypeArray::clone() const {
std::vector<range_t> new_ranges;
new_ranges.reserve(ranges_.size());
for(std::vector<range_t>::const_iterator it = ranges_.begin();
it != ranges_.end(); ++it) {
new_ranges.push_back(*(it->clone()));
}
VTypeArray*a = new VTypeArray(etype_->clone(), new_ranges, signed_flag_);
a->set_parent_type(parent_);
return a;
}
const VType* VTypeArray::basic_type(bool typedef_allowed) const
{
const VType*t = etype_;
const VTypeDef*tdef = NULL;
bool progress = false;
do {
progress = false;
if((tdef = dynamic_cast<const VTypeDef*>(t))) {
t = tdef->peek_definition();
}
if(const VTypeArray*arr = dynamic_cast<const VTypeArray*>(t)) {
t = arr->element_type();
progress = true;
} else if(tdef) { // return the typedef if it does not define an array
t = typedef_allowed ? tdef : tdef->peek_definition();
}
} while(progress);
return t;
}
void VTypeArray::show(ostream&out) const
{
out << "array ";
for (vector<range_t>::const_iterator cur = ranges_.begin()
; cur != ranges_.end() ; ++cur) {
2011-11-06 01:22:30 +01:00
out << "(";
if (cur->msb())
cur->msb()->write_to_stream(out);
else
out << "<>";
out << " downto ";
if (cur->lsb())
cur->lsb()->write_to_stream(out);
else
out << "<>";
out << ")";
}
out << " of ";
if (signed_flag_)
out << "signed ";
if (etype_)
etype_->show(out);
else
out << "<nil>";
}
int VTypeArray::get_width(ScopeBase*scope) const
2015-02-26 13:27:47 +01:00
{
int64_t size = 1;
for(vector<range_t>::const_iterator it = ranges_.begin();
it != ranges_.end(); ++it) {
const VTypeArray::range_t&dim = *it;
int64_t msb_val, lsb_val;
if(dim.is_box())
return -1;
2015-02-26 13:27:47 +01:00
if(!dim.msb()->evaluate(scope, msb_val))
2015-02-26 13:27:47 +01:00
return -1;
if(!dim.lsb()->evaluate(scope, lsb_val))
2015-02-26 13:27:47 +01:00
return -1;
size *= 1 + labs(msb_val - lsb_val);
}
return element_type()->get_width(scope) * size;
2015-02-26 13:27:47 +01:00
}
bool VTypeArray::is_unbounded() const {
for(std::vector<range_t>::const_iterator it = ranges_.begin();
it != ranges_.end(); ++it)
{
if(it->is_box())
return true;
}
return etype_->is_unbounded();
}
bool VTypeArray::is_variable_length(ScopeBase*scope) const {
int64_t dummy;
if(is_unbounded())
return true;
for(std::vector<range_t>::const_iterator it = ranges_.begin();
it != ranges_.end(); ++it)
{
if(!it->lsb()->evaluate(scope, dummy))
return true;
if(!it->msb()->evaluate(scope, dummy))
return true;
}
return etype_->is_variable_length(scope);
}
void VTypeArray::evaluate_ranges(ScopeBase*scope) {
for(std::vector<range_t>::iterator it = ranges_.begin(); it != ranges_.end(); ++it ) {
int64_t lsb_val = -1, msb_val = -1;
if(it->msb()->evaluate(scope, msb_val) && it->lsb()->evaluate(scope, lsb_val)) {
assert(lsb_val >= 0);
assert(msb_val >= 0);
*it = range_t(new ExpInteger(msb_val), new ExpInteger(lsb_val), msb_val > lsb_val);
}
}
}
VTypeRange::VTypeRange(const VType*base)
: base_(base)
{
}
VTypeRange::~VTypeRange()
{
}
2011-10-02 02:04:04 +02:00
VTypeRangeConst::VTypeRangeConst(const VType*base, int64_t start_val, int64_t end_val)
: VTypeRange(base), start_(start_val), end_(end_val)
{
}
VTypeRangeExpr::VTypeRangeExpr(const VType*base, Expression*start_expr,
Expression*end_expr, bool downto)
: VTypeRange(base), start_(start_expr), end_(end_expr), downto_(downto)
{
}
VTypeRangeExpr::~VTypeRangeExpr()
{
delete start_;
delete end_;
}
VType*VTypeRangeExpr::clone() const {
return new VTypeRangeExpr(base_type()->clone(), start_->clone(),
end_->clone(), downto_);
}
2011-10-02 02:04:04 +02:00
VTypeEnum::VTypeEnum(const std::list<perm_string>*names)
: names_(names->size())
{
size_t idx = 0;
for (list<perm_string>::const_iterator cur = names->begin()
; cur != names->end() ; ++cur, ++idx) {
names_[idx] = *cur;
}
}
VTypeEnum::~VTypeEnum()
{
}
2011-10-10 00:25:35 +02:00
void VTypeEnum::show(ostream&out) const
{
out << "(";
if (names_.size() >= 1)
out << names_[0];
for (size_t idx = 1 ; idx < names_.size() ; idx += 1)
out << ", " << names_[idx];
out << ")";
}
2015-02-06 10:44:22 +01:00
bool VTypeEnum::has_name(perm_string name) const
{
return std::find(names_.begin(), names_.end(), name) != names_.end();
}
VTypeRecord::VTypeRecord(std::list<element_t*>*elements)
: elements_(elements->size())
{
for (size_t idx = 0 ; idx < elements_.size() ; idx += 1) {
elements_[idx] = elements->front();
elements->pop_front();
}
delete elements;
}
VTypeRecord::~VTypeRecord()
{
for (size_t idx = 0 ; idx < elements_.size() ; idx += 1)
delete elements_[idx];
}
void VTypeRecord::show(ostream&out) const
{
write_to_stream(out);
}
int VTypeRecord::get_width(ScopeBase*scope) const
2015-02-26 13:27:47 +01:00
{
int width = 0;
for(vector<element_t*>::const_iterator it = elements_.begin();
it != elements_.end(); ++it) {
int w = (*it)->peek_type()->get_width(scope);
2015-02-26 13:27:47 +01:00
if(w < 0)
return -1;
width += w;
}
return width;
}
const VTypeRecord::element_t* VTypeRecord::element_by_name(perm_string name, int*index) const
{
for (vector<element_t*>::const_iterator cur = elements_.begin()
; cur != elements_.end() ; ++cur) {
element_t*curp = *cur;
if (curp->peek_name() == name) {
if (index)
*index = std::distance(elements_.begin(), cur);
return curp;
}
}
return 0;
}
VTypeRecord::element_t::element_t(perm_string name, const VType*typ)
: name_(name), type_(typ)
{
}
VTypeDef::VTypeDef(perm_string nam)
: name_(nam), type_(0)
{
}
2011-10-10 00:25:35 +02:00
VTypeDef::VTypeDef(perm_string nam, const VType*typ)
: name_(nam), type_(typ)
{
}
VTypeDef::~VTypeDef()
{
}
void VTypeDef::set_definition(const VType*typ)
{
assert(type_ == 0);
type_ = typ;
}