From 7d552980a68344574daa25ba9c472381e9d89145 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 13 Feb 2011 19:01:21 -0800 Subject: [PATCH] Elaborate array subtypes of ports. There are internal types that are unbounded arrays. Allow subtype syntax that creates bounded versions of these arrays, and elaborate them as vectors at port boundaries. This makes some interesting types work out. Also start replacing vhdlint and vhdlreal with int64_t and double, which are reasonable values for universal_integer and universal_real from the VHDL standard. I need these cleaned up because the ints in particular are used for the literal expressions in array index constraints. --- vhdlpp/debug.cc | 13 +++++++++-- vhdlpp/entity_elaborate.cc | 22 +++++++++++++++++ vhdlpp/expression.cc | 20 ++++++++++++++++ vhdlpp/expression.h | 26 +++++++++++++++++++-- vhdlpp/expression_emit.cc | 7 ++++++ vhdlpp/lexor.lex | 35 ++++++++++++++++----------- vhdlpp/parse.y | 27 ++++++++++++--------- vhdlpp/parse_misc.cc | 38 ++++++++++++++++++++++++++++++ vhdlpp/parse_misc.h | 7 ++++++ vhdlpp/vtype.cc | 48 ++++++++++++++++++++++++++++++++++++++ vhdlpp/vtype.h | 16 +++++++++++++ 11 files changed, 230 insertions(+), 29 deletions(-) diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index cb8e83442..31ec3330c 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -67,8 +67,12 @@ void Entity::dump(ostream&out) const InterfacePort*item = *cur; out << setw(6) << "" << item->name << " : " << item->mode - << ", type=" << (item->type? typeid(*item->type).name() : "NOTYPE") - << ", file=" << item->get_fileline() << endl; + << ", type="; + if (item->type) + item->type->show(out); + else + out << ""; + out << ", file=" << item->get_fileline() << endl; } } @@ -112,6 +116,11 @@ void Expression::dump(ostream&out, int indent) const << " at " << get_fileline()<< endl; } +void ExpInteger::dump(ostream&out, int indent) const +{ + out << setw(indent) << "" << "Integer" << endl; +} + void ExpLogical::dump(ostream&out, int indent) const { const char*fun_name = "?"; diff --git a/vhdlpp/entity_elaborate.cc b/vhdlpp/entity_elaborate.cc index ed7708942..b1858776b 100644 --- a/vhdlpp/entity_elaborate.cc +++ b/vhdlpp/entity_elaborate.cc @@ -26,6 +26,7 @@ # include # include # include +# include using namespace std; @@ -118,6 +119,27 @@ int Entity::elaborate_ports_(void) break; } + } else if (const VTypeArray*arr_type = dynamic_cast(type)) { + const VTypePrimitive*base = dynamic_cast(arr_type->element_type()); + assert(base != 0); + + switch (base->type()) { + case VTypePrimitive::BOOLEAN: + case VTypePrimitive::BIT: + cur_decl.type = VBOOL; + break; + case VTypePrimitive::STDLOGIC: + cur_decl.type = VLOGIC; + break; + case VTypePrimitive::INTEGER: + cur_decl.type = VLOGIC; + assert(0); + break; + } + + cur_decl.msb = arr_type->dimension(0).msb(); + cur_decl.lsb = arr_type->dimension(0).lsb(); + } else { cerr << get_fileline() << ": error: " << "I don't know how to map port " << cur_port->name diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 3a08b33b9..563de85a6 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -27,6 +27,26 @@ Expression::~Expression() { } +bool Expression::evaluate(int64_t&) const +{ + return false; +} + +ExpInteger::ExpInteger(int64_t val) +: value_(val) +{ +} + +ExpInteger::~ExpInteger() +{ +} + +bool ExpInteger::evaluate(int64_t&val) const +{ + val = value_; + return true; +} + ExpLogical::ExpLogical(ExpLogical::fun_t ty, Expression*op1, Expression*op2) : fun_(ty), operand1_(op1), operand2_(op2) { diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index dae333c5c..2be9b628c 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -21,6 +21,7 @@ # include "StringHeap.h" # include "LineInfo.h" +# include class Entity; class Architecture; @@ -39,10 +40,16 @@ class Expression : public LineInfo { // The emit virtual method is called bu architecture emit to // output the generated code for the expression. The derived // class fills in the details of what exactly happend. - virtual int emit(ostream&out, Entity*ent, Architecture*arc); + virtual int emit(ostream&out, Entity*ent, Architecture*arc) =0; + + // The evaluate virtual method tries to evaluate expressions + // to constant literal values. Return true and set the val + // argument if the evaluation works, or return false if it + // cannot be done. + virtual bool evaluate(int64_t&val) const; // Debug dump of the expression. - virtual void dump(ostream&out, int indent) const; + virtual void dump(ostream&out, int indent) const =0; private: @@ -51,6 +58,20 @@ class Expression : public LineInfo { Expression& operator = (const Expression&); }; +class ExpInteger : public Expression { + + public: + ExpInteger(int64_t val); + ~ExpInteger(); + + int emit(ostream&out, Entity*ent, Architecture*arc); + bool evaluate(int64_t&val) const; + void dump(ostream&out, int indent) const; + + private: + int64_t value_; +}; + class ExpLogical : public Expression { public: @@ -86,4 +107,5 @@ class ExpName : public Expression { perm_string name_; }; + #endif diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index 97280ccf7..43cda40ad 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -31,6 +31,13 @@ int Expression::emit(ostream&out, Entity*, Architecture*) return 1; } +int ExpInteger::emit(ostream&out, Entity*, Architecture*) +{ + out << " /* " << get_fileline() << ": internal error: " + << "INTEGER LITERAL */ "; + return 1; +} + int ExpLogical::emit(ostream&out, Entity*ent, Architecture*arc) { int errors = 0; diff --git a/vhdlpp/lexor.lex b/vhdlpp/lexor.lex index 5a22fc8a8..18531b560 100644 --- a/vhdlpp/lexor.lex +++ b/vhdlpp/lexor.lex @@ -135,19 +135,26 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* return IDENTIFIER; } - {decimal_literal} { - if(!are_underscores_correct(yytext)) - std::cerr << "An invalid underscore in the decimal literal:" - << yytext << std::endl; - - if(strchr(yytext, '.')) { - yylval.real = new vhdlreal(yytext); - return REAL_LITERAL; - } else { - yylval.integer = new vhdlint(yytext); - return INT_LITERAL; - } + char*tmp = new char[strlen(yytext)+1]; + char*dst, *src; + int rc = INT_LITERAL; + for (dst = tmp, src = yytext ; *src ; ++src) { + if (*src == '_') + continue; + if (*src == '.') + rc = REAL_LITERAL; + *dst++ = *src; + } + *dst = 0; + + if (rc == REAL_LITERAL) { + yylval.uni_real = strtod(tmp, 0); + } else { + yylval.uni_integer = strtoimax(tmp, 0, 10); + } + delete[]tmp; + return rc; } {based_literal} { @@ -158,13 +165,13 @@ based_integer [0-9a-fA-F](_?[0-9a-fA-F])* if(strchr(yytext, '.')) { double val = make_double_from_based(yytext); - yylval.real = new vhdlreal(val); + yylval.uni_real = val; return REAL_LITERAL; } else { int64_t val = make_long_from_based(yytext); - yylval.integer = new vhdlint(val); + yylval.uni_integer = val; return INT_LITERAL; } } diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index b503b53be..8e2e67dbe 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -49,8 +49,9 @@ int parse_errors = 0; port_mode_t port_mode; char*text; - vhdlint* integer; - vhdlreal* real; + bool flag; + int64_t uni_integer; + double uni_real; Expression*expr; std::list* expr_list; @@ -91,14 +92,16 @@ int parse_errors = 0; %token K_xnor K_xor /* Identifiers that are not keywords are identifiers. */ %token IDENTIFIER -%token INT_LITERAL -%token REAL_LITERAL +%token INT_LITERAL +%token REAL_LITERAL %token STRING_LITERAL CHARACTER_LITERAL /* compound symbols */ %token LEQ GEQ VASSIGN NE BOX EXP ARROW DLT DGT /* The rules may have types. */ +%type direction + %type interface_element %type interface_list entity_header port_clause %type mode @@ -175,10 +178,6 @@ concurrent_statement : concurrent_signal_assignment_statement ; -constraint - : '(' simple_expression direction simple_expression ')' - ; - context_clause : context_items | ; context_item @@ -202,7 +201,8 @@ design_units | design_unit ; -direction : K_to | K_downto ; + /* Indicate the direction as a flag, with "downto" being TRUE. */ +direction : K_to { $$ = false; } | K_downto { $$ = true; } ; /* As an entity is declared, add it to the map of design entities. */ entity_declaration @@ -355,6 +355,11 @@ primary delete[]$1; $$ = tmp; } + | INT_LITERAL + { ExpInteger*tmp = new ExpInteger($1); + FILE_NAME(tmp, @1); + $$ = tmp; + } ; relation : shift_expression { $$ = $1; } ; @@ -379,8 +384,8 @@ subtype_indication delete[]$1; $$ = tmp; } - | IDENTIFIER constraint - { const VType*tmp = global_types[lex_strings.make($1)]; + | IDENTIFIER '(' simple_expression direction simple_expression ')' + { const VType*tmp = calculate_subtype($1, $3, $4, $5); delete[]$1; $$ = tmp; } diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 10b159af7..ac3acb562 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -22,8 +22,11 @@ # include "parse_api.h" # include "entity.h" # include "architec.h" +# include "expression.h" +# include "vtype.h" # include "compiler.h" # include +# include using namespace std; @@ -49,3 +52,38 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch) return; } } + +const VType* calculate_subtype(const char*base_name, + Expression*array_left, + bool downto, + Expression*array_right) +{ + const VType*base_type = global_types[lex_strings.make(base_name)]; + + assert(array_left==0 || array_right!=0); + + const VTypeArray*base_array = dynamic_cast (base_type); + if (base_array) { + assert(array_left && array_right); + + vector range (base_array->dimensions()); + + // For now, I only know how to handle 1 dimension + assert(base_array->dimensions() == 1); + + int64_t left_val; + int64_t right_val; + bool rc = array_left->evaluate(left_val); + assert(rc); + + rc = array_right->evaluate(right_val); + assert(rc); + + range[0] = VTypeArray::range_t(left_val, right_val); + + VTypeArray*subtype = new VTypeArray(base_array->element_type(), range); + return subtype; + } + + return base_type; +} diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index 9f2d0416d..794d6754d 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -20,7 +20,14 @@ */ class Architecture; +class Expression; +class VType; extern void bind_architecture_to_entity(const char*ename, Architecture*arch); +extern const VType* calculate_subtype(const char*base_name, + Expression*array_left, + bool downto, + Expression*array_right); + #endif diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index adec5a144..45ec781c3 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -18,6 +18,7 @@ */ # include "vtype.h" +# include using namespace std; @@ -45,6 +46,11 @@ VType::~VType() { } +void VType::show(ostream&out) const +{ + out << typeid(*this).name(); +} + VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt) : type_(tt) { @@ -54,6 +60,24 @@ VTypePrimitive::~VTypePrimitive() { } +void VTypePrimitive::show(ostream&out) const +{ + switch (type_) { + case BOOLEAN: + out << "BOOLEAN"; + break; + case BIT: + out << "BIT"; + break; + case INTEGER: + out << "INTEGER"; + break; + case STDLOGIC: + out << "std_logic"; + break; + } +} + VTypeArray::VTypeArray(const VType*element, const vector&r) : etype_(element), ranges_(r) { @@ -62,3 +86,27 @@ VTypeArray::VTypeArray(const VType*element, const vector&r) VTypeArray::~VTypeArray() { } + +size_t VTypeArray::dimensions() const +{ + return ranges_.size(); +} + +const VType* VTypeArray::element_type() const +{ + return etype_; +} + +void VTypeArray::show(ostream&out) const +{ + out << "array "; + for (vector::const_iterator cur = ranges_.begin() + ; cur != ranges_.end() ; ++cur) { + out << "(" << cur->msb() << " downto " << cur->lsb() << ")"; + } + out << " of "; + if (etype_) + etype_->show(out); + else + out << ""; +} diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index a62ec50f0..23e382b55 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -19,6 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ +# include # include # include # include @@ -34,8 +35,16 @@ class VType { public: VType() { } virtual ~VType() =0; + + virtual void show(std::ostream&) const; }; +inline std::ostream&operator << (std::ostream&out, const VType&item) +{ + item.show(out); + return out; +} + /* * The global_types variable maps type names to a type * definition. This is after the "use" statements bring in the types @@ -58,6 +67,8 @@ class VTypePrimitive : public VType { VTypePrimitive(type_t); ~VTypePrimitive(); + void show(std::ostream&) const; + type_t type() const { return type_; } private: @@ -97,7 +108,12 @@ class VTypeArray : public VType { VTypeArray(const VType*etype, const std::vector&r); ~VTypeArray(); + void show(std::ostream&) const; + size_t dimensions() const; + const range_t&dimension(size_t idx) const + { return ranges_[idx]; } + const VType* element_type() const; private: