Merge pull request #38 from orsonmmz/unbounded_array

Support for VHDL unbounded arrays.
This commit is contained in:
Stephen Williams 2014-08-27 09:15:28 -07:00
commit 3852545f21
16 changed files with 173 additions and 71 deletions

View File

@ -210,3 +210,5 @@ ostream& operator << (ostream&out, perm_string that)
out << that.str();
return out;
}
const perm_string empty_perm_string = perm_string::literal("");

View File

@ -52,6 +52,7 @@ class perm_string {
const char*text_;
};
extern const perm_string empty_perm_string;
extern bool operator == (perm_string a, perm_string b);
extern bool operator == (perm_string a, const char* b);
extern bool operator != (perm_string a, perm_string b);

View File

@ -41,6 +41,24 @@ int Architecture::elaborate(Entity*entity)
cur->second->val->elaborate_expr(entity, this, cur->second->typ);
}
// Elaborate initializer expressions for signals & variables
for (map<perm_string,Signal*>::iterator cur = old_signals_.begin()
; cur != old_signals_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
}
for (map<perm_string,Signal*>::iterator cur = new_signals_.begin()
; cur != new_signals_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
}
for (map<perm_string,Variable*>::iterator cur = old_variables_.begin()
; cur != old_variables_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
}
for (map<perm_string,Variable*>::iterator cur = new_variables_.begin()
; cur != new_variables_.end() ; ++cur) {
cur->second->elaborate_init_expr(entity, this);
}
for (list<Architecture::Statement*>::iterator cur = statements_.begin()
; cur != statements_.end() ; ++cur) {

View File

@ -638,6 +638,7 @@ class ExpString : public Expression {
int emit(ostream&out, Entity*ent, Architecture*arc);
bool is_primary(void) const;
void dump(ostream&out, int indent = 0) const;
const std::vector<char>& get_value() const { return value_; }
private:
int emit_as_array_(ostream&out, Entity*ent, Architecture*arc, const VTypeArray*arr);

View File

@ -159,7 +159,8 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V
ivl_assert(*this, rc);
rc = rang.lsb()->evaluate(ent, arc, use_lsb);
ivl_assert(*this, rc);
ivl_assert(*this, use_msb >= use_lsb);
if(use_msb < use_lsb)
swap(use_msb, use_lsb);
map<int64_t,choice_element*> element_map;
choice_element*element_other = 0;
@ -244,6 +245,10 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, Architecture*arc, const V
// Emit the elements as a concatenation. This works great for
// vectors of bits. We implement VHDL arrays as packed arrays,
// so this should be generally correct.
// TODO uncomment this once ivl supports assignments of '{}
/*if(!peek_type()->can_be_packed())
out << "'";*/
out << "{";
for (int64_t idx = use_msb ; idx >= use_lsb ; idx -= 1) {
choice_element*cur = element_map[idx];

View File

@ -409,6 +409,7 @@ static char*make_bitstring_bin(int width_prefix, bool sflag, bool,
while (*src) {
*rp++ = *src++;
}
*rp = 0;
return res;
}

View File

@ -343,11 +343,11 @@ static void import_ieee_use(ActiveScope*res, perm_string package, perm_string na
}
}
const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN);
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT);
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER);
const VTypePrimitive primitive_BOOLEAN(VTypePrimitive::BOOLEAN, true);
const VTypePrimitive primitive_BIT(VTypePrimitive::BIT, true);
const VTypePrimitive primitive_INTEGER(VTypePrimitive::INTEGER, true);
const VTypePrimitive primitive_REAL(VTypePrimitive::REAL);
const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC);
const VTypePrimitive primitive_STDLOGIC(VTypePrimitive::STDLOGIC, true);
const VTypePrimitive primitive_CHARACTER(VTypePrimitive::CHARACTER);
const VTypeRange primitive_NATURAL(&primitive_INTEGER, INT64_MAX, 0);

View File

@ -48,8 +48,8 @@ int Package::emit_package(ostream&fd) const
for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++ cur) {
fd << "typedef ";
errors += cur->second->emit_def(fd);
fd << " \\" << cur->first << " ;" << endl;
errors += cur->second->emit_def(fd, cur->first);
fd << " ;" << endl;
}
for (map<perm_string,struct const_t*>::const_iterator cur = use_constants_.begin()

View File

@ -684,8 +684,8 @@ composite_type_definition
/* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */
| K_array '(' index_subtype_definition_list ')' K_of subtype_indication
{ sorrymsg(@1, "unbounded_array_definition not supported.\n");
std::list<prange_t*> r;
{ std::list<prange_t*> r;
r.push_back(new prange_t(NULL, NULL, true)); // NULL boundaries indicate unbounded array type
VTypeArray*tmp = new VTypeArray($6, &r);
$$ = tmp;
}

View File

@ -82,6 +82,12 @@ static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_n
assert(array_left==0 || array_right!=0);
// unfold typedef, if it is the case
const VTypeDef*type_def = dynamic_cast<const VTypeDef*> (base_type);
if (type_def) {
base_type = type_def->peek_definition();
}
const VTypeArray*base_array = dynamic_cast<const VTypeArray*> (base_type);
if (base_array) {
assert(array_left && array_right);

View File

@ -31,7 +31,7 @@ int Subprogram::emit_package(ostream&fd) const
if (return_type_) {
fd << "function ";
return_type_->emit_def(fd);
return_type_->emit_def(fd, empty_perm_string);
fd << " " << name_;
fd << "(";
} else {
@ -55,8 +55,7 @@ int Subprogram::emit_package(ostream&fd) const
break;
}
errors += curp->type->emit_def(fd);
fd << " \\" << curp->name << " ";
errors += curp->type->emit_def(fd, curp->name);
}
fd << ");" << endl;

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright CERN 2014 / Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -33,6 +34,30 @@ SigVarBase::~SigVarBase()
{
}
void SigVarBase::elaborate_init_expr(Entity*ent, Architecture*arc)
{
if(init_expr_) {
// convert the initializing string to bitstring if applicable
const ExpString*string = dynamic_cast<const ExpString*>(init_expr_);
if(string) {
const std::vector<char>& val = string->get_value();
char buf[val.size() + 1];
std::copy(val.begin(), val.end(), buf);
buf[val.size()] = 0;
ExpBitstring*bitstring = new ExpBitstring(buf);
delete init_expr_;
init_expr_ = bitstring;
}
else {
ExpAggregate*aggr = dynamic_cast<ExpAggregate*>(init_expr_);
if(aggr) {
aggr->elaborate_expr(ent, arc, peek_type());
}
}
}
}
void SigVarBase::type_elaborate_(VType::decl_t&decl)
{
decl.type = type_;
@ -44,7 +69,7 @@ int Signal::emit(ostream&out, Entity*ent, Architecture*arc)
VType::decl_t decl;
type_elaborate_(decl);
if (peek_refcnt_sequ_() > 0)
if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed())
decl.reg_flag = true;
errors += decl.emit(out, peek_name_());
@ -63,7 +88,7 @@ int Variable::emit(ostream&out, Entity*, Architecture*)
VType::decl_t decl;
type_elaborate_(decl);
if (peek_refcnt_sequ_() > 0)
if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed())
decl.reg_flag = true;
errors += decl.emit(out, peek_name_());
out << ";" << endl;

View File

@ -41,6 +41,9 @@ class SigVarBase : public LineInfo {
void dump(ostream&out, int indent = 0) const;
// Elaborates initializer expressions if needed.
void elaborate_init_expr(Entity*ent, Architecture*arc);
protected:
perm_string peek_name_() const { return name_; }
unsigned peek_refcnt_sequ_() const { return refcnt_sequ_; }

View File

@ -35,8 +35,8 @@ void VType::show(ostream&out) const
write_to_stream(out);
}
VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt)
: type_(tt)
VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt, bool packed)
: type_(tt), packed_(packed)
{
}
@ -60,8 +60,8 @@ void VTypePrimitive::show(ostream&out) const
out << "INTEGER";
break;
case REAL:
out << "REAL";
break;
out << "REAL";
break;
case STDLOGIC:
out << "std_logic";
break;

View File

@ -2,7 +2,7 @@
#define IVL_vtype_H
/*
* Copyright (c) 2011-2014 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com),
* Copyright CERN 2014 / Stephen Williams (steve@icarus.com),
* Maciej Suminski (maciej.suminski@cern.ch)
*
* This source code is free software; you can redistribute it
@ -74,7 +74,7 @@ class VType {
// This virtual method emits a definition for the specific
// type. It is used to emit typedef's.
virtual int emit_def(std::ostream&out) const =0;
virtual int emit_def(std::ostream&out, perm_string name) const =0;
// This virtual method causes VTypeDef types to emit typedefs
// of themselves. The VTypeDef implementation of this method
@ -82,6 +82,9 @@ class VType {
// all the types that it emits.
virtual int emit_typedef(std::ostream&out, typedef_context_t&ctx) const;
// Determines if a type can be used in Verilog packed array.
virtual bool can_be_packed() const { return false; }
private:
friend class decl_t;
// This virtual method is called to emit the declaration. This
@ -100,6 +103,12 @@ class VType {
bool reg_flag;
};
protected:
inline void emit_name(std::ostream&out, perm_string name) const
{
if(name != empty_perm_string)
out << " \\" << name << " ";
}
};
inline std::ostream&operator << (std::ostream&out, const VType&item)
@ -115,7 +124,7 @@ extern void preload_global_types(void);
*/
class VTypeERROR : public VType {
public:
int emit_def(std::ostream&out) const;
int emit_def(std::ostream&out, perm_string name) const;
};
/*
@ -128,7 +137,7 @@ class VTypePrimitive : public VType {
enum type_t { BOOLEAN, BIT, INTEGER, REAL, STDLOGIC, CHARACTER };
public:
VTypePrimitive(type_t);
VTypePrimitive(type_t tt, bool packed = false);
~VTypePrimitive();
void write_to_stream(std::ostream&fd) const;
@ -137,10 +146,13 @@ class VTypePrimitive : public VType {
type_t type() const { return type_; }
int emit_primitive_type(std::ostream&fd) const;
int emit_def(std::ostream&out) const;
int emit_def(std::ostream&out, perm_string name) const;
bool can_be_packed() const { return packed_; }
private:
type_t type_;
bool packed_;
};
extern const VTypePrimitive primitive_BOOLEAN;
@ -191,8 +203,11 @@ class VTypeArray : public VType {
const VType* element_type() const;
int emit_def(std::ostream&out) const;
int emit_def(std::ostream&out, perm_string name) const;
int emit_typedef(std::ostream&out, typedef_context_t&ctx) const;
int emit_dimensions(std::ostream&out) const;
bool can_be_packed() const { return etype_->can_be_packed(); }
private:
const VType*etype_;
@ -212,7 +227,7 @@ class VTypeRange : public VType {
public: // Virtual methods
void write_to_stream(std::ostream&fd) const;
int emit_def(std::ostream&out) const;
int emit_def(std::ostream&out, perm_string name) const;
private:
const VType*base_;
@ -226,7 +241,7 @@ class VTypeEnum : public VType {
~VTypeEnum();
void show(std::ostream&) const;
int emit_def(std::ostream&out) const;
int emit_def(std::ostream&out, perm_string name) const;
private:
std::vector<perm_string>names_;
@ -259,7 +274,9 @@ class VTypeRecord : public VType {
void write_to_stream(std::ostream&fd) const;
void show(std::ostream&) const;
int emit_def(std::ostream&out) const;
int emit_def(std::ostream&out, perm_string name) const;
bool can_be_packed() const { return true; }
const element_t* element_by_name(perm_string name) const;
@ -288,7 +305,9 @@ class VTypeDef : public VType {
void write_type_to_stream(ostream&fd) const;
int emit_typedef(std::ostream&out, typedef_context_t&ctx) const;
int emit_def(std::ostream&out) const;
int emit_def(std::ostream&out, perm_string name) const;
bool can_be_packed() const { return type_->can_be_packed(); }
private:
int emit_decl(std::ostream&out, perm_string name, bool reg_flag) const;

View File

@ -33,7 +33,6 @@ int VType::decl_t::emit(ostream&out, perm_string name) const
return type->emit_decl(out, name, reg_flag);
}
int VType::emit_decl(ostream&out, perm_string name, bool reg_flag) const
{
int errors = 0;
@ -41,9 +40,8 @@ int VType::emit_decl(ostream&out, perm_string name, bool reg_flag) const
if (!reg_flag)
out << "wire ";
errors += emit_def(out);
out << " \\" << name << " ";
errors += emit_def(out, name);
out << " ";
return errors;
}
@ -52,53 +50,40 @@ int VType::emit_typedef(std::ostream&, typedef_context_t&) const
return 0;
}
int VTypeERROR::emit_def(ostream&out) const
int VTypeERROR::emit_def(ostream&out, perm_string) const
{
out << "/* ERROR */";
return 1;
}
int VTypeArray::emit_def(ostream&out) const
int VTypeArray::emit_def(ostream&out, perm_string name) const
{
int errors = 0;
list<const VTypeArray*> dims;
const VTypeArray*cur = this;
while (const VTypeArray*sub = dynamic_cast<const VTypeArray*> (cur->etype_)) {
dims.push_back(cur);
cur = sub;
}
const VType*raw_base = cur->etype_;
const VTypePrimitive*base = dynamic_cast<const VTypePrimitive*> (raw_base);
if (base) {
assert(dimensions() == 1);
base->emit_def(out);
base->emit_def(out, empty_perm_string);
if (signed_flag_)
out << " signed";
} else {
raw_base->emit_def(out);
raw_base->emit_def(out, empty_perm_string);
}
dims.push_back(cur);
while (! dims.empty()) {
cur = dims.front();
dims.pop_front();
out << "[";
if (cur->dimension(0).msb())
errors += cur->dimension(0).msb()->emit(out, 0, 0);
else
out << "?error?";
out << ":";
if (cur->dimension(0).lsb())
errors += cur->dimension(0).lsb()->emit(out, 0, 0);
else
out << "?error?";
out << "]";
if(raw_base->can_be_packed()) {
errors += emit_dimensions(out);
emit_name(out, name);
} else {
emit_name(out, name);
errors += emit_dimensions(out);
}
return errors;
@ -109,7 +94,36 @@ int VTypeArray::emit_typedef(std::ostream&out, typedef_context_t&ctx) const
return etype_->emit_typedef(out, ctx);
}
int VTypeEnum::emit_def(ostream&out) const
int VTypeArray::emit_dimensions(std::ostream&out) const
{
int errors = 0;
list<const VTypeArray*> dims;
const VTypeArray*cur = this;
while (const VTypeArray*sub = dynamic_cast<const VTypeArray*> (cur->etype_)) {
dims.push_back(cur);
cur = sub;
}
dims.push_back(cur);
while (! dims.empty()) {
cur = dims.front();
dims.pop_front();
out << "[";
if (cur->dimension(0).msb() && cur->dimension(0).lsb()) {
// bounded array, unbounded arrays have msb() & lsb() nullified
errors += cur->dimension(0).msb()->emit(out, 0, 0);
out << ":";
errors += cur->dimension(0).lsb()->emit(out, 0, 0);
}
out << "]";
}
return errors;
}
int VTypeEnum::emit_def(ostream&out, perm_string name) const
{
int errors = 0;
out << "enum {";
@ -119,6 +133,7 @@ int VTypeEnum::emit_def(ostream&out) const
out << ", \\" << names_[idx] << " ";
out << "}";
emit_name(out, name);
return errors;
}
@ -135,11 +150,11 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
out << "logic";
break;
case INTEGER:
out << "bool [31:0]";
out << "bool[31:0]";
break;
case REAL:
out << "real";
break;
case REAL:
out << "real";
break;
case CHARACTER:
out << "char";
break;
@ -150,22 +165,23 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
return errors;
}
int VTypePrimitive::emit_def(ostream&out) const
int VTypePrimitive::emit_def(ostream&out, perm_string name) const
{
int errors = 0;
errors += emit_primitive_type(out);
emit_name(out, name);
return errors;
}
int VTypeRange::emit_def(ostream&out) const
int VTypeRange::emit_def(ostream&out, perm_string name) const
{
int errors = 0;
out << "/* Internal error: Don't know how to emit range */";
errors += base_->emit_def(out);
errors += base_->emit_def(out, name);
return errors;
}
int VTypeRecord::emit_def(ostream&out) const
int VTypeRecord::emit_def(ostream&out, perm_string name) const
{
int errors = 0;
out << "struct packed {";
@ -174,11 +190,12 @@ int VTypeRecord::emit_def(ostream&out) const
; cur != elements_.end() ; ++cur) {
perm_string element_name = (*cur)->peek_name();
const VType*element_type = (*cur)->peek_type();
element_type->emit_def(out);
element_type->emit_def(out, empty_perm_string);
out << " \\" << element_name << " ; ";
}
out << "}";
emit_name(out, name);
return errors;
}
@ -187,10 +204,10 @@ int VTypeRecord::emit_def(ostream&out) const
* type. (We are defining a variable here, not the type itself.) The
* emit_typedef() method was presumably called to define type already.
*/
int VTypeDef::emit_def(ostream&out) const
int VTypeDef::emit_def(ostream&out, perm_string) const
{
int errors = 0;
out << "\\" << name_ << " ";
emit_name(out, name_);
return errors;
}
@ -202,8 +219,7 @@ int VTypeDef::emit_decl(ostream&out, perm_string name, bool reg_flag) const
else
out << "wire ";
errors += type_->emit_def(out);
out << " \\" << name << " ";
errors += type_->emit_def(out, name);
return errors;
}
@ -229,8 +245,14 @@ int VTypeDef::emit_typedef(ostream&out, typedef_context_t&ctx) const
int errors = type_->emit_typedef(out, ctx);
flag = MARKED;
// Array types are used directly anyway and typedefs for unpacked
// arrays do not work currently
if(dynamic_cast<const VTypeArray*>(type_))
out << "// ";
out << "typedef ";
errors += type_->emit_def(out);
out << " \\" << name_ << " ;" << endl;
errors += type_->emit_def(out, name_);
out << " ;" << endl;
return errors;
}