diff --git a/Statement.cc b/Statement.cc index 5ce819311..1b7e4e389 100644 --- a/Statement.cc +++ b/Statement.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2008,2010,2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2008,2010,2012-2013 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 @@ -341,6 +341,16 @@ PRepeat::~PRepeat() delete statement_; } +PReturn::PReturn(PExpr*e) +: expr_(e) +{ +} + +PReturn::~PReturn() +{ + delete expr_; +} + PTrigger::PTrigger(const pform_name_t&e) : event_(e) { diff --git a/Statement.h b/Statement.h index 82289be76..510298e43 100644 --- a/Statement.h +++ b/Statement.h @@ -466,6 +466,19 @@ class PRelease : public Statement { PExpr*lval_; }; +class PReturn : public Statement { + + public: + explicit PReturn(PExpr*e); + ~PReturn(); + + NetProc* elaborate(Design*des, NetScope*scope) const; + virtual void dump(std::ostream&out, unsigned ind) const; + + private: + PExpr*expr_; +}; + /* * The PTrigger statement sends a trigger to a named event. Take the * name here. diff --git a/elab_expr.cc b/elab_expr.cc index f2dbcc0d1..18235b735 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope, { perm_string name = peek_tail_name(path_); + if (name=="$ivlh_to_unsigned") { + ivl_assert(*this, parms_.size() == 2); + // The Icarus Verilog specific $ivl_unsigned() system + // task takes a second argument which is the output + // size. This can be an arbitrary constant function. + PExpr*pexpr = parms_[1]; + if (pexpr == 0) { + cerr << get_fileline() << ": error: " + << "Missing $ivlh_to_unsigned width." << endl; + return 0; + } + + NetExpr*nexpr = elab_and_eval(des, scope, pexpr, -1, true); + if (nexpr == 0) { + cerr << get_fileline() << ": error: " + << "Unable to evaluate " << name + << " width argument: " << *pexpr << endl; + return 0; + } + + long value = 0; + bool rc = eval_as_long(value, nexpr); + ivl_assert(*this, rc && value>=0); + + expr_width_ = value; + signed_flag_= false; + return expr_width_; + } + if (name=="$signed" || name=="$unsigned") { PExpr*expr = parms_[0]; if (expr == 0) @@ -1232,6 +1261,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, { perm_string name = peek_tail_name(path_); + /* Catch the special case that the system function is the + $ivl_unsigned function. In this case the second argument is + the size of the expression, but should already be accounted + for so treat this very much like the $unsigned() function. */ + if (name=="$ivlh_to_unsigned") { + ivl_assert(*this, parms_.size()==2); + + PExpr*expr = parms_[0]; + ivl_assert(*this, expr); + NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags); + return cast_to_width_(sub, expr_wid); + } + /* Catch the special case that the system function is the $signed function. Its argument will be evaluated as a self-determined expression. */ @@ -1918,6 +1960,23 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds bool need_const = NEED_CONST & flags; + // If this is a constant expression, it is possible that we + // are being elaborated before the function definition. If + // that's the case, try to elaborate the function as a const + // function. + if (need_const && ! def->proc()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PECallFunction::elaborate_base_: " + << "Try to elaborate " << scope_path(dscope) + << " as constant function." << endl; + } + dscope->set_elab_stage(2); + dscope->need_const_func(true); + const PFunction*pfunc = dscope->func_pform(); + ivl_assert(*this, pfunc); + pfunc->elaborate(des, dscope); + } + unsigned parms_count = parms_.size(); if ((parms_count == 1) && (parms_[0] == 0)) parms_count = 0; @@ -2049,6 +2108,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope, perm_string method_name = peek_tail_name(use_path); use_path.pop_back(); + // If there is no object to the left of the method name, then + // give up on the idea of looking for an object method. + if (use_path.empty()) { + return 0; + } + NetNet *net = 0; const NetExpr *par; NetEvent *eve; diff --git a/elab_sig.cc b/elab_sig.cc index 70934d9b9..87862e8f7 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -983,6 +983,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const vector plist, nlist; /* If they exist get the port definition MSB and LSB */ if (port_set_ && !port_.empty()) { + if (debug_elaborate) { + cerr << get_fileline() << ": PWire::elaborate_sig: " + << "Evaluate ranges for port " << basename() << endl; + } bad_range |= evaluate_ranges(des, scope, plist, port_); nlist = plist; /* An implicit port can have a range so note that here. */ @@ -993,10 +997,20 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const /* If they exist get the net/etc. definition MSB and LSB */ if (net_set_ && !net_.empty() && !bad_range) { nlist.clear(); + if (debug_elaborate) { + cerr << get_fileline() << ": PWire::elaborate_sig: " + << "Evaluate ranges for net " << basename() << endl; + } bad_range |= evaluate_ranges(des, scope, nlist, net_); } assert(net_set_ || net_.empty()); + if (debug_elaborate) { + cerr << get_fileline() << ": PWire::elaborate_sig: " + << "Calculated ranges for " << basename() + << ". Now check for consistency." << endl; + } + /* If we find errors here, then give up on this signal. */ if (bad_range) return 0; diff --git a/elaborate.cc b/elaborate.cc index 3abe21e21..b519634af 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2799,14 +2799,6 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const if (nscope->calls_sys_task()) scope->calls_sys_task(true); - if (!wires.empty()) { - if (scope->need_const_func()) { - cerr << get_fileline() << ": sorry: Block variables inside " - "a constant function are not yet supported." << endl; - } - scope->is_const_func(false); - } - cur->set_line(*this); return cur; } @@ -4451,6 +4443,69 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const return proc; } +NetProc* PReturn::elaborate(Design*des, NetScope*scope) const +{ + NetScope*target = scope; + for (;;) { + if (target == 0) { + cerr << get_fileline() << ": error: " + << "Return statement is not in a function." << endl; + des->errors += 1; + return 0; + } + + if (target->type() == NetScope::FUNC) + break; + + if (target->type() == NetScope::TASK) { + cerr << get_fileline() << ": error: " + << "Cannot \"return\" from tasks." << endl; + des->errors += 1; + return 0; + } + + if (target->type()==NetScope::BEGIN_END) { + target = target->parent(); + continue; + } + + cerr << get_fileline() << ": error: " + << "Cannot \"return\" from this scope: " << scope_path(target) << endl; + des->errors += 1; + return 0; + } + + // We don't yet support void functions, so require an + // expression for the return statement. + if (expr_ == 0) { + cerr << get_fileline() << ": error: " + << "Return from " << scope_path(target) + << " requires a return value expression." << endl; + des->errors += 1; + return 0; + } + + NetNet*res = target->find_signal(target->basename()); + ivl_variable_type_t lv_type = res->data_type(); + unsigned long wid = res->vector_width(); + NetAssign_*lv = new NetAssign_(res); + + NetExpr*val = elaborate_rval_expr(des, scope, lv_type, wid, expr_); + + NetBlock*proc = new NetBlock(NetBlock::SEQU, 0); + proc->set_line( *this ); + + NetAssign*assn = new NetAssign(lv, val); + assn->set_line( *this ); + proc->append(assn); + + NetDisable*disa = new NetDisable(target); + disa->set_line( *this ); + proc->append( disa ); + + return proc; +} + /* * A task definition is elaborated by elaborating the statement that * it contains, and connecting its ports to NetNet objects. The diff --git a/eval_tree.cc b/eval_tree.cc index 1fc452bfe..6e9eb73c2 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -480,7 +480,7 @@ NetEConst* NetEBComp::eval_gteq_(const NetExpr*le, const NetExpr*re) const if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL) return eval_leeq_real_(re, le, true); - const NetEConst*l = dynamic_cast(left_); + const NetEConst*l = dynamic_cast(le); if (l == 0) return 0; verinum lv = l->value(); diff --git a/lexor.lex b/lexor.lex index 2a362be39..2408cdf7a 100644 --- a/lexor.lex +++ b/lexor.lex @@ -367,6 +367,13 @@ TU [munpf] \\[^ \t\b\f\r\n]+ { yylval.text = strdupnew(yytext+1); + if (gn_system_verilog()) { + if (PPackage*pkg = pform_test_package_identifier(yylval.text)) { + delete[]yylval.text; + yylval.package = pkg; + return PACKAGE_IDENTIFIER; + } + } if (gn_system_verilog()) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) { delete[]yylval.text; diff --git a/net_func_eval.cc b/net_func_eval.cc index f5bef42c4..3777328d6 100644 --- a/net_func_eval.cc +++ b/net_func_eval.cc @@ -60,7 +60,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vectorcontext_map; if (debug_eval_tree) { - cerr << loc.get_fileline() << ": debug: " + cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " << "Evaluate function " << scope_->basename() << endl; } @@ -78,7 +78,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vectorevaluate_function(loc, context_map); + if (debug_eval_tree && !flag) { + cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " + << "Cannot evaluate " << scope_path(scope_) << "." << endl; + } + // Extract the result... ptr = context_map.find(scope_->basename()); NetExpr*res = ptr->second.value; @@ -112,9 +123,32 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector"; + cerr << endl; + } return res; + } + + if (debug_eval_tree) { + cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: " + << "Evaluation failed." << endl; + } delete res; return 0; @@ -181,9 +215,15 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, map::iterator ptr = context_map.find(lval->name()); ivl_assert(*this, ptr != context_map.end()); + LocalVar*var = & ptr->second; + while (var->nwords == -1) { + assert(var->ref); + var = var->ref; + } + NetExpr*old_lval; - unsigned word = 0; - if (ptr->second.nwords > 0) { + int word = 0; + if (var->nwords > 0) { NetExpr*word_result = lval->word()->evaluate_function(loc, context_map); if (word_result == 0) { delete rval_result; @@ -198,12 +238,13 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, word = word_const->value().as_long(); - if (word >= ptr->second.nwords) + if (word >= var->nwords) return true; - old_lval = ptr->second.array[word]; + old_lval = var->array[word]; } else { - old_lval = ptr->second.value; + assert(var->nwords == 0); + old_lval = var->value; } if (const NetExpr*base_expr = lval->get_base()) { @@ -245,15 +286,16 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc, delete old_lval; if (debug_eval_tree) { - cerr << get_fileline() << ": debug: " - << "NetAssign::evaluate_function: " << lval->name() - << " = " << *rval_result << endl; + cerr << get_fileline() << ": NetAssign::evaluate_function: " + << lval->name() << " = " << *rval_result << endl; } - if (ptr->second.nwords > 0) - ptr->second.array[word] = rval_result; - else - ptr->second.value = rval_result; + if (var->nwords > 0) { + var->array[word] = rval_result; + } else { + assert(var->nwords == 0); + var->value = rval_result; + } return true; } @@ -303,16 +345,56 @@ bool NetAssign::evaluate_function(const LineInfo&loc, bool NetBlock::evaluate_function(const LineInfo&loc, map&context_map) const { + if (last_ == 0) return true; + + // If we need to make a local scope, then this context map + // will be filled in and used for statements within this block. + maplocal_context_map; + bool use_local_context_map = false; + + if (subscope_!=0) { + // First, copy the containing scope symbols into the new + // scope as references. + for (map::iterator cur = context_map.begin() + ; cur != context_map.end() ; ++cur) { + LocalVar&cur_var = local_context_map[cur->first]; + cur_var.nwords = -1; + if (cur->second.nwords == -1) + cur_var.ref = cur->second.ref; + else + cur_var.ref = &cur->second; + } + + // Now collect the new locals. + subscope_->evaluate_function_find_locals(loc, local_context_map); + use_local_context_map = true; + } + + // Now use the local context map if there is any local + // context, or the containing context map. + map&use_context_map = use_local_context_map? local_context_map : context_map; + bool flag = true; NetProc*cur = last_; - if (cur == 0) return true; - do { cur = cur->next_; - bool cur_flag = cur->evaluate_function(loc, context_map); + if (debug_eval_tree) { + cerr << get_fileline() << ": NetBlock::evaluate_function: " + << "Execute statement (" << typeid(*cur).name() + << ") at " << cur->get_fileline() << "." << endl; + } + + bool cur_flag = cur->evaluate_function(loc, use_context_map); flag = flag && cur_flag; } while (cur != last_ && !disable); + if (debug_eval_tree) { + cerr << get_fileline() << ": NetBlock::evaluate_function: " + << "subscope_=" << subscope_ + << ", disable=" << disable + << ", flag=" << (flag?"true":"false") << endl; + } + if (disable == subscope_) disable = 0; return flag; @@ -437,8 +519,13 @@ bool NetCondit::evaluate_function(const LineInfo&loc, map&context_map) const { NetExpr*cond = expr_->evaluate_function(loc, context_map); - if (cond == 0) + if (cond == 0) { + if (debug_eval_tree) { + cerr << get_fileline() << ": NetCondit::evaluate_function: " + << "Unable to evaluate condition (" << *expr_ <<")" << endl; + } return false; + } NetEConst*cond_const = dynamic_cast (cond); ivl_assert(loc, cond_const); @@ -446,18 +533,32 @@ bool NetCondit::evaluate_function(const LineInfo&loc, long val = cond_const->value().as_long(); delete cond; + bool flag; + if (val) // The condition is true, so evaluate the if clause - return (if_ == 0) || if_->evaluate_function(loc, context_map); + flag = (if_ == 0) || if_->evaluate_function(loc, context_map); else // The condition is false, so evaluate the else clause - return (else_ == 0) || else_->evaluate_function(loc, context_map); + flag = (else_ == 0) || else_->evaluate_function(loc, context_map); + + if (debug_eval_tree) { + cerr << get_fileline() << ": NetCondit::evaluate_function: " + << "Finished, flag=" << (flag?"true":"false") << endl; + } + return flag; } bool NetDisable::evaluate_function(const LineInfo&, map&) const { disable = target_; + + if (debug_eval_tree) { + cerr << get_fileline() << ": NetDisable::evaluate_function: " + << "disable " << scope_path(disable) << endl; + } + return true; } @@ -530,7 +631,7 @@ bool NetWhile::evaluate_function(const LineInfo&loc, bool flag = true; if (debug_eval_tree) { - cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " + cerr << get_fileline() << ": NetWhile::evaluate_function: " << "Start loop" << endl; } @@ -561,8 +662,8 @@ bool NetWhile::evaluate_function(const LineInfo&loc, } if (debug_eval_tree) { - cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " - << "Done loop" << endl; + cerr << get_fileline() << ": NetWhile::evaluate_function: " + << "Done loop, flag=" << (flag?"true":"false") << endl; } return flag; @@ -674,8 +775,15 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc, return 0; } + // Follow indirect references to the actual variable. + LocalVar*var = & ptr->second; + while (var->nwords == -1) { + assert(var->ref); + var = var->ref; + } + NetExpr*value = 0; - if (ptr->second.nwords > 0) { + if (var->nwords > 0) { ivl_assert(loc, word_); NetExpr*word_result = word_->evaluate_function(loc, context_map); if (word_result == 0) @@ -684,12 +792,12 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc, NetEConst*word_const = dynamic_cast(word_result); ivl_assert(loc, word_const); - unsigned word = word_const->value().as_long(); + int word = word_const->value().as_long(); - if (word_const->value().is_defined() && (word < ptr->second.nwords)) - value = ptr->second.array[word]; + if (word_const->value().is_defined() && (word < var->nwords)) + value = var->array[word]; } else { - value = ptr->second.value; + value = var->value; } if (value == 0) { diff --git a/netlist.h b/netlist.h index 936c94d14..39543e1e3 100644 --- a/netlist.h +++ b/netlist.h @@ -760,10 +760,11 @@ class NetNet : public NetObj, public PortType { * evaluating constant user functions. */ struct LocalVar { - unsigned nwords; // zero for a simple variable + int nwords; // zero for a simple variable, -1 for reference union { NetExpr* value; // a simple variable NetExpr** array; // an array variable + LocalVar* ref; // A reference to a previous scope }; }; diff --git a/parse.y b/parse.y index 32548fb11..a9230f221 100644 --- a/parse.y +++ b/parse.y @@ -1244,12 +1244,14 @@ jump_statement /* IEEE1800-2005: A.6.5 */ $$ = 0; } | K_return ';' - { yyerror(@1, "sorry: return statements not supported."); - $$ = 0; + { PReturn*tmp = new PReturn(0); + FILE_NAME(tmp, @1); + $$ = tmp; } | K_return expression ';' - { yyerror(@1, "sorry: return statements not supported."); - $$ = 0; + { PReturn*tmp = new PReturn($2); + FILE_NAME(tmp, @1); + $$ = tmp; } ; diff --git a/pform_dump.cc b/pform_dump.cc index 41251c679..0a69ba2a1 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 1998-2013 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 @@ -938,6 +938,13 @@ void PRepeat::dump(ostream&out, unsigned ind) const statement_->dump(out, ind+3); } +void PReturn::dump(ostream&fd, unsigned ind) const +{ + fd << setw(ind) << "" << "return ("; + if (expr_) fd << *expr_; + fd << ")" << endl; +} + void PTask::dump(ostream&out, unsigned ind) const { out << setw(ind) << "" << "task "; diff --git a/symbol_search.cc b/symbol_search.cc index 3302bff5a..1b26bb22a 100644 --- a/symbol_search.cc +++ b/symbol_search.cc @@ -65,6 +65,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope, assert(scope); bool prefix_scope = false; bool recurse_flag = false; + + ivl_assert(*li, ! path.empty()); name_component_t path_tail = path.back(); path.pop_back(); diff --git a/tgt-stub/statement.c b/tgt-stub/statement.c index ea020b6f0..eed16f055 100644 --- a/tgt-stub/statement.c +++ b/tgt-stub/statement.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2004-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2004-2013 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 @@ -153,6 +153,12 @@ static void show_stmt_delayx(ivl_statement_t net, unsigned ind) show_statement(ivl_stmt_sub_stmt(net), ind+2); } +static void show_stmt_disable(ivl_statement_t net, unsigned ind) +{ + ivl_scope_t scope = ivl_stmt_call(net); + fprintf(out, "%*sdisable %s\n", ind, "", ivl_scope_basename(scope)); +} + static void show_stmt_force(ivl_statement_t net, unsigned ind) { unsigned idx; @@ -378,6 +384,10 @@ void show_statement(ivl_statement_t net, unsigned ind) show_stmt_delayx(net, ind); break; + case IVL_ST_DISABLE: + show_stmt_disable(net, ind); + break; + case IVL_ST_FORCE: show_stmt_force(net, ind); break; diff --git a/vhdlpp/Makefile.in b/vhdlpp/Makefile.in index de6e0b8df..da356cc13 100644 --- a/vhdlpp/Makefile.in +++ b/vhdlpp/Makefile.in @@ -59,14 +59,17 @@ LIBS = @LIBS@ @EXTRALIBS@ M = StringHeap.o LineInfo.o O = main.o architec.o compiler.o entity.o \ - expression.o package.o scope.o sequential.o vsignal.o vtype.o \ + expression.o package.o scope.o sequential.o subprogram.o vsignal.o vtype.o \ + vtype_match.o \ architec_elaborate.o entity_elaborate.o expression_elaborate.o \ expression_evaluate.o \ sequential_elaborate.o \ + vtype_elaborate.o \ entity_stream.o expression_stream.o vtype_stream.o \ lexor.o lexor_keyword.o parse.o \ parse_misc.o library.o vhdlreal.o vhdlint.o \ - architec_emit.o entity_emit.o expression_emit.o sequential_emit.o vtype_emit.o \ + architec_emit.o entity_emit.o expression_emit.o package_emit.o \ + sequential_emit.o subprogram_emit.o vtype_emit.o \ debug.o architec_debug.o expression_debug.o sequential_debug.o \ $M diff --git a/vhdlpp/architec.cc b/vhdlpp/architec.cc index acf9eafad..f223e8b90 100644 --- a/vhdlpp/architec.cc +++ b/vhdlpp/architec.cc @@ -26,7 +26,7 @@ using namespace std; -Architecture::Architecture(perm_string name, const ScopeBase&ref, +Architecture::Architecture(perm_string name, const ActiveScope&ref, list&s) : Scope(ref), name_(name) { diff --git a/vhdlpp/architec.h b/vhdlpp/architec.h index 33224f485..594f350eb 100644 --- a/vhdlpp/architec.h +++ b/vhdlpp/architec.h @@ -63,7 +63,7 @@ class Architecture : public Scope, public LineInfo { public: // Create an architecture from its name and its statements. // NOTE: The statement list passed in is emptied. - Architecture(perm_string name, const ScopeBase&ref, + Architecture(perm_string name, const ActiveScope&ref, std::list&s); ~Architecture(); diff --git a/vhdlpp/architec_elaborate.cc b/vhdlpp/architec_elaborate.cc index 0e85dd05d..3ffc8c6da 100644 --- a/vhdlpp/architec_elaborate.cc +++ b/vhdlpp/architec_elaborate.cc @@ -32,12 +32,12 @@ int Architecture::elaborate(Entity*entity) // from the constant declaration itself. Elaborate the value // expression with the declared type. - for (map::iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++cur) { + for (map::iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { cur->second->val->elaborate_expr(entity, this, cur->second->typ); } - for (map::iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++cur) { + for (map::iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { cur->second->val->elaborate_expr(entity, this, cur->second->typ); } @@ -174,9 +174,54 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*) return -1; const Expression*ce_raw = stmt->peek_condition(); + // Now we have matched this pattern: + // process() begin if ... + // The is the condition. - // We expect the condition to be 'event AND ='1'. - // If it's not a logical AND, I give up. + if (const ExpFunc*ce_func = dynamic_cast(ce_raw)) { + if (ce_func->func_args() != 1) + return -1; + if (ce_func->func_name()!="rising_edge" && ce_func->func_name()!="falling_edge") + return -1; + + if (! se->symbolic_compare(ce_func->func_arg(0))) + return -1; + + // We've matched this pattern: + // process() if (rising_edge()) then ... + // and we can convert it to: + // always @(posedge ) ... + + ExpEdge::fun_t use_edge; + if (ce_func->func_name()=="rising_edge") + use_edge = ExpEdge::POSEDGE; + else if (ce_func->func_name()=="falling_edge") + use_edge = ExpEdge::NEGEDGE; + else + use_edge = ExpEdge::ANYEDGE; + + // Replace the sensitivity expression with an edge + // expression. The ExpEdge expression signals that this + // is an always-@(edge) statement. + ExpEdge*edge = new ExpEdge(use_edge, se); + assert(sensitivity_list_.size() == 1); + sensitivity_list_.pop_front(); + sensitivity_list_.push_front(edge); + + // Replace the statement with the body of the always + // statement, which is the true clause of the top "if" + // statement. There should be no "else" clause. + assert(statements_list_.size() == 1); + statements_list_.pop_front(); + stmt->extract_true(statements_list_); + + delete stmt; + return 0; + } + + // Here we expect the condition to be + // 'event AND ='1'. + // So if ce_raw is not a logical AND, I give up. const ExpLogical*ce = dynamic_cast (ce_raw); if (ce == 0) return -1; diff --git a/vhdlpp/architec_emit.cc b/vhdlpp/architec_emit.cc index 0f517294b..b53f94acf 100644 --- a/vhdlpp/architec_emit.cc +++ b/vhdlpp/architec_emit.cc @@ -69,8 +69,8 @@ int Architecture::emit(ostream&out, Entity*entity) // of the full definition. typedef_context_t typedef_ctx; - for (map::iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + for (map::iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { const VTypeDef*def = dynamic_cast(cur->second); if (def == 0) @@ -79,15 +79,15 @@ int Architecture::emit(ostream&out, Entity*entity) errors += def->emit_typedef(out, typedef_ctx); } - for (map::iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++cur) { + for (map::iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { out << "localparam " << cur->first << " = "; errors += cur->second->val->emit(out, entity, this); out << ";" << endl; } - for (map::iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++cur) { + for (map::iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { out << "localparam " << cur->first << " = "; errors += cur->second->val->emit(out, entity, this); diff --git a/vhdlpp/compiler.h b/vhdlpp/compiler.h index f0ae81ad5..380ca0f01 100644 --- a/vhdlpp/compiler.h +++ b/vhdlpp/compiler.h @@ -36,5 +36,6 @@ extern StringHeapLex filename_strings; extern void library_set_work_path(const char*work_path); extern void library_add_directory(const char*directory); +extern int emit_packages(void); #endif diff --git a/vhdlpp/debug.cc b/vhdlpp/debug.cc index 972150778..a6f9542b9 100644 --- a/vhdlpp/debug.cc +++ b/vhdlpp/debug.cc @@ -22,6 +22,7 @@ # include "architec.h" # include "expression.h" # include "parse_types.h" +# include "sequential.h" # include "vsignal.h" # include "vtype.h" # include @@ -100,31 +101,36 @@ void ComponentBase::dump_ports(ostream&out, int indent) const void Scope::dump_scope(ostream&out) const { // Dump types - for (map::const_iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + out << " -- imported types" << endl; + for (map::const_iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { out << " " << cur->first << ": "; cur->second->show(out); out << endl; } - for (map::const_iterator cur = new_types_.begin() - ; cur != new_types_.end() ; ++cur) { + out << " -- Types from this scope" << endl; + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { out << " " << cur->first << ": "; cur->second->show(out); out << endl; } // Dump constants - for (map::const_iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++cur) { + out << " -- imported constants" << endl; + for (map::const_iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { out << " constant " << cur->first << " = "; out << endl; } - for (map::const_iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++cur) { + out << " -- Constants from this scope" << endl; + for (map::const_iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { out << " constant " << cur->first << " = "; out << endl; } // Dump signal declarations + out << " -- Signals" << endl; for (map::const_iterator cur = old_signals_.begin() ; cur != old_signals_.end() ; ++cur) { if (cur->second) @@ -138,8 +144,24 @@ void Scope::dump_scope(ostream&out) const cur->second->dump(out, 3); else out << " signal " << cur->first.str() << ": ???" << endl; + } + // Dump subprograms + out << " -- Imported Subprograms" << endl; + for (map::const_iterator cur = use_subprograms_.begin() + ; cur != use_subprograms_.end() ; ++cur) { + out << " subprogram " << cur->first << " is" << endl; + cur->second->dump(out); + out << " end subprogram " << cur->first << endl; + } + out << " -- Subprograms from this scope" << endl; + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + out << " subprogram " << cur->first << " is" << endl; + cur->second->dump(out); + out << " end subprogram " << cur->first << endl; } // Dump component declarations + out << " -- Components" << endl; for (map::const_iterator cur = old_components_.begin() ; cur != old_components_.end() ; ++cur) { out << " component " << cur->first << " is" << endl; @@ -148,10 +170,11 @@ void Scope::dump_scope(ostream&out) const out << " end component " << cur->first << endl; } for (map::const_iterator cur = new_components_.begin() - ; cur != new_components_.end() ; ++cur) { - out << " component " << cur->first << " is" << endl; - cur->second->dump_ports(out); - out << " end component " << cur->first << endl; + ; cur != new_components_.end() ; ++cur) { + out << " component " << cur->first << " is" << endl; + cur->second->dump_generics(out); + cur->second->dump_ports(out); + out << " end component " << cur->first << endl; } } @@ -436,3 +459,41 @@ ostream& ExpInteger::dump_inline(ostream&out) const out << value_; return out; } + +void Subprogram::dump(ostream&fd) const +{ + fd << " " << name_; + + if (ports_->empty()) { + fd << "()"; + + } else { + fd << "("; + + list::const_iterator cur = ports_->begin(); + InterfacePort*curp = *cur; + fd << curp->name << ":"; + curp->type->show(fd); + + for (++ cur ; cur != ports_->end() ; ++ cur) { + curp = *cur; + fd << "; " << curp->name << ":"; + curp->type->show(fd); + } + fd << ")"; + } + + fd << " return "; + return_type_->show(fd); + fd << endl; + + if (statements_== 0 || statements_->empty()) { + fd << " " << endl; + } else { + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + SequentialStmt*curp = *cur; + curp->dump(fd, 8); + } + } +} diff --git a/vhdlpp/entity_elaborate.cc b/vhdlpp/entity_elaborate.cc index 2727bd34e..861029ca7 100644 --- a/vhdlpp/entity_elaborate.cc +++ b/vhdlpp/entity_elaborate.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -113,6 +114,10 @@ int Entity::elaborate_ports_(void) continue; } + // Elaborate the type to elaborate any expressions that + // are used by the types. + errors += type->elaborate(this, bind_arch_); + VType::decl_t cur_decl; cur_decl.type = type; declarations_[cur_port->name] = cur_decl; diff --git a/vhdlpp/expression.cc b/vhdlpp/expression.cc index 5cb7be4d5..74e143c63 100644 --- a/vhdlpp/expression.cc +++ b/vhdlpp/expression.cc @@ -1,5 +1,6 @@ /* * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / 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 @@ -39,7 +40,7 @@ Expression::~Expression() void Expression::set_type(const VType*typ) { - assert(type_ == 0); + assert(type_==0 || type_==typ); type_ = typ; } @@ -260,12 +261,12 @@ ExpEdge::~ExpEdge() } ExpFunc::ExpFunc(perm_string nn) -: name_(nn), argv_(0) +: name_(nn), def_(0) { } ExpFunc::ExpFunc(perm_string nn, list*args) -: name_(nn), argv_(args->size()) +: name_(nn), argv_(args->size()), def_(0) { for (size_t idx = 0; idx < argv_.size() ; idx += 1) { ivl_assert(*this, !args->empty()); diff --git a/vhdlpp/expression.h b/vhdlpp/expression.h index 0271abe37..e5c143e3e 100644 --- a/vhdlpp/expression.h +++ b/vhdlpp/expression.h @@ -1,7 +1,8 @@ #ifndef __expression_H #define __expression_H /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -31,6 +32,7 @@ class prange_t; class Entity; class Architecture; class ScopeBase; +class Subprogram; class VType; class VTypeArray; class VTypePrimitive; @@ -90,6 +92,10 @@ class Expression : public LineInfo { // class fills in the details of what exactly happened. virtual int emit(ostream&out, Entity*ent, Architecture*arc) =0; + // The emit_package virtual message is similar, but is called + // in a package context and to emit SV packages. + virtual int emit_package(std::ostream&out); + // 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 @@ -187,6 +193,9 @@ class ExpBinary : public Expression { void dump_operands(ostream&out, int indent = 0) const; + private: + virtual const VType*resolve_operand_types_(const VType*t1, const VType*t2) const; + private: Expression*operand1_; Expression*operand2_; @@ -299,6 +308,9 @@ class ExpArithmetic : public ExpBinary { virtual bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; + private: + const VType* resolve_operand_types_(const VType*t1, const VType*t2) const; + private: fun_t fun_; }; @@ -457,6 +469,10 @@ class ExpFunc : public Expression { ExpFunc(perm_string nn, std::list*args); ~ExpFunc(); + inline perm_string func_name() const { return name_; } + inline size_t func_args() const { return argv_.size(); } + inline const Expression*func_arg(size_t idx) const { return argv_[idx]; } + public: // Base methods int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); @@ -466,6 +482,7 @@ class ExpFunc : public Expression { private: perm_string name_; std::vector argv_; + Subprogram*def_; }; class ExpInteger : public Expression { @@ -478,6 +495,7 @@ class ExpInteger : public Expression { int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); void write_to_stream(std::ostream&fd); int emit(ostream&out, Entity*ent, Architecture*arc); + int emit_package(std::ostream&out); bool is_primary(void) const; bool evaluate(ScopeBase*scope, int64_t&val) const; void dump(ostream&out, int indent = 0) const; diff --git a/vhdlpp/expression_elaborate.cc b/vhdlpp/expression_elaborate.cc index a201de334..2ca201d35 100644 --- a/vhdlpp/expression_elaborate.cc +++ b/vhdlpp/expression_elaborate.cc @@ -1,6 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / 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 @@ -328,6 +328,9 @@ const VType* ExpBinary::probe_type(Entity*ent, Architecture*arc) const if (t1 == t2) return t1; + if (const VType*tb = resolve_operand_types_(t1, t2)) + return tb; + // FIXME: I should at this point try harder to find an // operator that has the proper argument list and use this // here, but for now we leave it for the back-end to figure out. @@ -337,6 +340,11 @@ const VType* ExpBinary::probe_type(Entity*ent, Architecture*arc) const return 0; } +const VType*ExpBinary::resolve_operand_types_(const VType*t1, const VType*t2) const +{ + return 0; +} + int ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype) { int errors = 0; @@ -491,6 +499,21 @@ int ExpArithmetic::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltyp return errors; } +const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t2) const +{ + while (const VTypeRange*tmp = dynamic_cast (t1)) + t1 = tmp->base_type(); + while (const VTypeRange*tmp = dynamic_cast (t2)) + t2 = tmp->base_type(); + + if (t1->type_match(t2)) + return t1; + if (t2->type_match(t2)) + return t2; + + return 0; +} + const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const { base_->probe_type(ent, arc); @@ -637,6 +660,12 @@ int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*) { int errors = 0; + ivl_assert(*this, arc); + Subprogram*prog = arc->find_subprogram(name_); + + ivl_assert(*this, def_==0); + def_ = prog; + for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) { const VType*tmp = argv_[idx]->probe_type(ent, arc); errors += argv_[idx]->elaborate_expr(ent, arc, tmp); diff --git a/vhdlpp/expression_emit.cc b/vhdlpp/expression_emit.cc index c0d22210b..07916d159 100644 --- a/vhdlpp/expression_emit.cc +++ b/vhdlpp/expression_emit.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / 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 @@ -20,10 +21,12 @@ # include "expression.h" # include "vtype.h" # include "architec.h" +# include "package.h" # include "parse_types.h" # include # include # include +# include # include "ivl_assert.h" # include @@ -37,6 +40,14 @@ int Expression::emit(ostream&out, Entity*, Architecture*) return 1; } +int Expression::emit_package(ostream&out) +{ + out << " /* " << get_fileline() << ": internal error: " + << "I don't know how to emit_package this expression! " + << "type=" << typeid(*this).name() << " */ "; + return 1; +} + bool Expression::is_primary(void) const { return false; @@ -270,16 +281,14 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc) the down to a literal integer at compile time, and all it needs is the type of the base expression. (The base expression doesn't even need to be evaluated.) */ - if (name_ == "length") { - int64_t val; - bool rc = evaluate(ent, arc, val); - out << val; - if (rc) - return errors; - else - return errors + 1; + if (name_=="length") { + out << "$bits("; + errors += base_->emit(out, ent, arc); + out << ")"; + return errors; } + out << "$ivl_attribute("; errors += base_->emit(out, ent, arc); out << ", \"" << name_ << "\")"; @@ -531,13 +540,12 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) out << ")"; } else if (name_ == "to_unsigned" && argv_.size() == 2) { - int64_t use_size; - bool rc = argv_[1]->evaluate(ent, arc, use_size); - ivl_assert(*this, rc); - out << "$unsigned(" << use_size << "'("; + out << "$ivlh_to_unsigned("; errors += argv_[0]->emit(out, ent, arc); - out << "))"; + out << ", "; + errors += argv_[1]->emit(out, ent, arc); + out << ")"; } else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) { int64_t use_size; @@ -547,7 +555,28 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc) errors += argv_[0]->emit(out, ent, arc); out << ")"; + } else if (name_ == "rising_edge" && argv_.size()==1) { + out << "$ivlh_rising_edge("; + errors += argv_[0]->emit(out, ent, arc); + out << ")"; + + } else if (name_ == "falling_edge" && argv_.size()==1) { + out << "$ivlh_falling_edge("; + errors += argv_[0]->emit(out, ent, arc); + out << ")"; + } else { + // If this function has an elaborated defintion, and if + // that definition is in a package, then include the + // package name as a scope qualifier. This assures that + // the SV elaborator finds the correct VHDL elaborated + // definition. + if (def_) { + const Package*pkg = dynamic_cast (def_->get_parent()); + if (pkg != 0) + out << "\\" << pkg->name() << " ::"; + } + out << "\\" << name_ << " ("; for (size_t idx = 0; idx < argv_.size() ; idx += 1) { if (idx > 0) out << ", "; @@ -565,6 +594,12 @@ int ExpInteger::emit(ostream&out, Entity*, Architecture*) return 0; } +int ExpInteger::emit_package(ostream&out) +{ + out << value_; + return 0; +} + bool ExpInteger::is_primary(void) const { return true; @@ -713,6 +748,18 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA const VTypePrimitive*etype = dynamic_cast (arr->element_type()); assert(etype); + // Detect the special case that this is an array of + // CHARACTER. In this case, emit at a Verilog string. + if (etype->type()==VTypePrimitive::CHARACTER) { + vector tmp (value_.size() + 3); + tmp[0] = '"'; + memcpy(&tmp[1], &value_[0], value_.size()); + tmp[value_.size()+1] = '"'; + tmp[value_.size()+2] = 0; + out << &tmp[0]; + return errors; + } + assert(etype->type() != VTypePrimitive::INTEGER); out << value_.size() << "'b"; for (size_t idx = 0 ; idx < value_.size() ; idx += 1) { @@ -728,6 +775,9 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA out << "z"; break; default: + cerr << get_fileline() << ": internal error: " + << "Don't know how to handle bit " << value_[idx] + << " with etype==" << etype->type() << endl; assert(etype->type() == VTypePrimitive::STDLOGIC); out << "x"; break; diff --git a/vhdlpp/library.cc b/vhdlpp/library.cc index 435778020..86c7c8ccc 100644 --- a/vhdlpp/library.cc +++ b/vhdlpp/library.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -119,7 +120,8 @@ void dump_libraries(ostream&file) /* * This function saves a package into the named library. Create the - * library if necessary. + * library if necessary. The parser uses this when it is finished with + * a package declaration. */ void library_save_package(perm_string parse_library_name, Package*pack) { @@ -134,6 +136,29 @@ void library_save_package(perm_string parse_library_name, Package*pack) // library right now, then store it in the work library. if (parse_library_name.str() == 0) store_package_in_work(pack); + else + pack->set_library(parse_library_name); +} + +/* + * The parser uses this function in the package body rule to recall + * the package that was declared earlier. + */ +Package*library_recall_package(perm_string parse_library_name, perm_string package_name) +{ + perm_string use_libname = parse_library_name.str() + ? parse_library_name + : perm_string::literal("work"); + + map::iterator lib = libraries.find(use_libname); + if (lib == libraries.end()) + return 0; + + map::iterator pkg = lib->second.packages.find(package_name); + if (pkg == lib->second.packages.end()) + return 0; + + return pkg->second; } static void import_library_name(const YYLTYPE&loc, perm_string name) @@ -254,7 +279,7 @@ static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name) if (all_flag || name == "std_logic_vector") { vector dims (1); - res->bind_name(perm_string::literal("std_logic_vector"), + res->use_name(perm_string::literal("std_logic_vector"), new VTypeArray(primitive_STDLOGIC, dims, false)); } } @@ -269,12 +294,12 @@ static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); - res->bind_name(perm_string::literal("signed"), + res->use_name(perm_string::literal("signed"), new VTypeArray(primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); - res->bind_name(perm_string::literal("unsigned"), + res->use_name(perm_string::literal("unsigned"), new VTypeArray(primitive_BIT, dims, false)); } } @@ -285,12 +310,12 @@ static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name) if (all_flag || name == "signed") { vector dims (1); - res->bind_name(perm_string::literal("signed"), + res->use_name(perm_string::literal("signed"), new VTypeArray(primitive_STDLOGIC, dims, true)); } if (all_flag || name == "unsigned") { vector dims (1); - res->bind_name(perm_string::literal("unsigned"), + res->use_name(perm_string::literal("unsigned"), new VTypeArray(primitive_STDLOGIC, dims, false)); } } @@ -322,20 +347,24 @@ const VTypePrimitive* primitive_BOOLEAN = new VTypePrimitive(VTypePrimitive::BO const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BIT); const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER); const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC); +const VTypePrimitive* primitive_CHARACTER= new VTypePrimitive(VTypePrimitive::CHARACTER); const VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0); -const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); -const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); +static const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector (1)); +static const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector (1)); +static const VTypeArray* primitive_STRING = new VTypeArray(primitive_CHARACTER, vector (1)); void generate_global_types(ActiveScope*res) { - res->bind_name(perm_string::literal("boolean"), primitive_BOOLEAN); - res->bind_name(perm_string::literal("bit"), primitive_BIT); - res->bind_name(perm_string::literal("integer"), primitive_INTEGER); - res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC); - res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); - res->bind_name(perm_string::literal("natural"), primitive_NATURAL); + res->use_name(perm_string::literal("boolean"), primitive_BOOLEAN); + res->use_name(perm_string::literal("bit"), primitive_BIT); + res->use_name(perm_string::literal("integer"), primitive_INTEGER); + res->use_name(perm_string::literal("std_logic"), primitive_STDLOGIC); + res->use_name(perm_string::literal("character"), primitive_CHARACTER); + res->use_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); + res->use_name(perm_string::literal("string"), primitive_STRING); + res->use_name(perm_string::literal("natural"), primitive_NATURAL); } bool is_global_type(perm_string name) @@ -344,7 +373,9 @@ bool is_global_type(perm_string name) if (name == "bit") return true; if (name == "integer") return true; if (name == "std_logic") return true; + if (name == "character") return true; if (name == "bit_vector") return true; + if (name == "string") return true; if (name == "natural") return true; return false; } @@ -363,3 +394,25 @@ static void store_package_in_work(const Package*pack) pack->write_to_stream(file); } + +static int emit_packages(perm_string lib_name, const map&packages) +{ + int errors = 0; + for (map::const_iterator cur = packages.begin() + ; cur != packages.end() ; ++cur) { + errors += cur->second->emit_package(cout); + } + + return errors; +} + +int emit_packages(void) +{ + int errors = 0; + for (map::iterator cur = libraries.begin() + ; cur != libraries.end() ; ++cur) { + errors += emit_packages(cur->first, cur->second.packages); + } + + return 0; +} diff --git a/vhdlpp/main.cc b/vhdlpp/main.cc index ce3fa2df6..45fb02e9d 100644 --- a/vhdlpp/main.cc +++ b/vhdlpp/main.cc @@ -218,17 +218,24 @@ int main(int argc, char*argv[]) } if (errors > 0) { - parser_cleanup(); + parser_cleanup(); return 2; } errors = elaborate_entities(); if (errors > 0) { fprintf(stderr, "%d errors elaborating design.\n", errors); - parser_cleanup(); + parser_cleanup(); return 3; } + errors = emit_packages(); + if (errors > 0) { + fprintf(stderr, "%d errors emitting packages.\n", errors); + parser_cleanup(); + return 4; + } + errors = emit_entities(); if (errors > 0) { fprintf(stderr, "%d errors emitting design.\n", errors); diff --git a/vhdlpp/package.cc b/vhdlpp/package.cc index 338bbddae..d3d4a8b06 100644 --- a/vhdlpp/package.cc +++ b/vhdlpp/package.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -20,8 +21,9 @@ # include "package.h" # include "entity.h" # include "parse_misc.h" +# include "ivl_assert.h" -Package::Package(perm_string n, const ScopeBase&ref) +Package::Package(perm_string n, const ActiveScope&ref) : Scope(ref), name_(n) { } @@ -31,6 +33,12 @@ Package::~Package() ScopeBase::cleanup(); } +void Package::set_library(perm_string lname) +{ + ivl_assert(*this, from_library_.str() == 0); + from_library_ = lname; +} + /* * The Package::write_to_stream is used to write the package to the * work space (or library) so writes proper VHDL that the library @@ -43,24 +51,29 @@ void Package::write_to_stream(ostream&fd) const // Start out pre-declaring all the type definitions so that // there is no confusion later in the package between types // and identifiers. - for (map::const_iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + for (map::const_iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { + const VTypeDef*def = dynamic_cast (cur->second); + if (def == 0) + continue; + fd << "type " << cur->first << ";" << endl; + } + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { const VTypeDef*def = dynamic_cast (cur->second); if (def == 0) continue; fd << "type " << cur->first << ";" << endl; } - for (map::const_iterator cur = new_types_.begin() - ; cur != new_types_.end() ; ++cur) { - const VTypeDef*def = dynamic_cast (cur->second); - if (def == 0) + for (map::const_iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++ cur) { + if (cur->second==0 || cur->second->typ==0) { + fd << "-- const " << cur->first + << " has errors." << endl; continue; - fd << "type " << cur->first << ";" << endl; - } + } - for (map::const_iterator cur = old_constants_.begin() - ; cur != old_constants_.end() ; ++ cur) { fd << "constant " << cur->first << ": "; cur->second->typ->write_to_stream(fd); fd << " := "; @@ -68,17 +81,21 @@ void Package::write_to_stream(ostream&fd) const fd << ";" << endl; } - for (map::const_iterator cur = new_constants_.begin() - ; cur != new_constants_.end() ; ++ cur) { - fd << "constant " << cur->first << ": "; - cur->second->typ->write_to_stream(fd); - fd << " := "; - cur->second->val->write_to_stream(fd); - fd << ";" << endl; - } + for (map::const_iterator cur = use_types_.begin() + ; cur != use_types_.end() ; ++cur) { - for (map::const_iterator cur = old_types_.begin() - ; cur != old_types_.end() ; ++cur) { + // Do not include global types in types dump + if (is_global_type(cur->first)) + continue; + if (cur->first == "std_logic_vector") + continue; + + fd << "type " << cur->first << " is "; + cur->second->write_type_to_stream(fd); + fd << "; -- imported" << endl; + } + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++cur) { // Do not include global types in types dump if (is_global_type(cur->first)) @@ -90,18 +107,10 @@ void Package::write_to_stream(ostream&fd) const cur->second->write_type_to_stream(fd); fd << ";" << endl; } - for (map::const_iterator cur = new_types_.begin() - ; cur != new_types_.end() ; ++cur) { - // Do not include primitive types in type dump - if (is_global_type(cur->first)) - continue; - if (cur->first == "std_logic_vector") - continue; - - fd << "type " << cur->first << " is "; - cur->second->write_type_to_stream(fd); - fd << ";" << endl; + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++cur) { + cur->second->write_to_stream(fd); } for (map::const_iterator cur = old_components_.begin() diff --git a/vhdlpp/package.h b/vhdlpp/package.h index 8f9fd04ae..046708c30 100644 --- a/vhdlpp/package.h +++ b/vhdlpp/package.h @@ -1,7 +1,8 @@ #ifndef __package_H #define __package_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -26,15 +27,24 @@ class Package : public Scope, public LineInfo { public: - Package(perm_string name, const ScopeBase&ref); + Package(perm_string name, const ActiveScope&ref); ~Package(); + // The the library from which this package came. Having a + // source library influences the emit_package() method. + void set_library(perm_string); + perm_string name() const { return name_; } + Subprogram* recall_subprogram(perm_string name) const; + // This method writes a package header to a library file. void write_to_stream(std::ostream&fd) const; + int emit_package(std::ostream&fd) const; + private: + perm_string from_library_; perm_string name_; }; diff --git a/vhdlpp/package_emit.cc b/vhdlpp/package_emit.cc new file mode 100644 index 000000000..5792cd728 --- /dev/null +++ b/vhdlpp/package_emit.cc @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "package.h" +# include +# include "ivl_assert.h" + +using namespace std; + +int Package::emit_package(ostream&fd) const +{ + // Don't emit the package if there is nothing in it that SV + // cares about. + if (cur_types_.empty() && cur_constants_.empty() && cur_subprograms_.empty()) + return 0; + + // If this package was imported from a library, then do not + // emit it again. + if (from_library_.str() != 0) { + fd << "/* Suppress package " << name() + << " from library " << from_library_ << " */" << endl; + return 0; + } + + int errors = 0; + + fd << "package \\" << name() << " ;" << endl; + + // Only emit types that were defined within this package. Skip + // the types that were imported from elsewhere. + for (map::const_iterator cur = cur_types_.begin() + ; cur != cur_types_.end() ; ++ cur) { + fd << "typedef "; + errors += cur->second->emit_def(fd); + fd << " \\" << cur->first << " ;" << endl; + } + + for (map::const_iterator cur = use_constants_.begin() + ; cur != use_constants_.end() ; ++cur) { + fd << "localparam \\" << cur->first << " = "; + errors += cur->second->val->emit_package(fd); + fd << ";" << endl; + } + for (map::const_iterator cur = cur_constants_.begin() + ; cur != cur_constants_.end() ; ++cur) { + fd << "localparam " << cur->first << " = "; + errors += cur->second->val->emit_package(fd); + fd << ";" << endl; + } + + for (map::const_iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++ cur) { + errors += cur->second->emit_package(fd); + } + + fd << "endpackage" << endl; + + return errors; +} diff --git a/vhdlpp/parse.y b/vhdlpp/parse.y index 3c4d0b174..05c1dea36 100644 --- a/vhdlpp/parse.y +++ b/vhdlpp/parse.y @@ -6,8 +6,8 @@ %parse-param {perm_string parse_library_name} %{ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) - * Copyright CERN 2012 / Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2012-2013 / 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 @@ -34,7 +34,8 @@ # include "architec.h" # include "expression.h" # include "sequential.h" -# include "package.h" +# include "subprogram.h" +# include "package.h" # include "vsignal.h" # include "vtype.h" # include @@ -181,6 +182,16 @@ static list* record_elements(list*names, return res; } +static void touchup_interface_for_functions(std::list*ports) +{ + for (list::iterator cur = ports->begin() + ; cur != ports->end() ; ++cur) { + InterfacePort*curp = *cur; + if (curp->mode == PORT_NONE) + curp->mode = PORT_IN; + } +} + %} @@ -222,6 +233,7 @@ static list* record_elements(list*names, std::list*range_list; ExpArithmetic::fun_t arithmetic_op; + std::list*adding_terms; ExpAggregate::choice_t*choice; std::list*choice_list; @@ -234,6 +246,8 @@ static list* record_elements(list*names, Architecture::Statement* arch_statement; std::list* arch_statement_list; + + Subprogram*subprogram; }; /* The keywords are all tokens. */ @@ -274,6 +288,7 @@ static list* record_elements(list*names, %type direction %type adding_operator +%type simple_expression_terms %type interface_element interface_list %type port_clause port_clause_opt @@ -301,7 +316,7 @@ static list* record_elements(list*names, %type expression_logical_xnor expression_logical_xor %type name prefix selected_name %type shift_expression signal_declaration_assign_opt -%type simple_expression term waveform_element +%type simple_expression simple_expression_2 term waveform_element %type interface_element_expression %type waveform waveform_elements @@ -319,11 +334,12 @@ static list* record_elements(list*names, %type element_declaration element_declaration_list %type architecture_body_start package_declaration_start +%type package_body_start %type identifier_opt identifier_colon_opt logical_name suffix %type logical_name_list identifier_list %type enumeration_literal_list enumeration_literal -%type sequence_of_statements if_statement_else +%type if_statement_else sequence_of_statements subprogram_statement_part %type sequential_statement if_statement signal_assignment_statement %type case_statement procedure_call procedure_call_statement %type loop_statement variable_assignment_statement @@ -341,6 +357,8 @@ static list* record_elements(list*names, %type else_when_waveform %type else_when_waveforms +%type function_specification subprogram_specification + %% /* The design_file is the root for the VHDL parse. This rule is also @@ -658,6 +676,15 @@ composite_type_definition delete $2; $$ = tmp; } + + /* 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 r; + VTypeArray*tmp = new VTypeArray($6, &r); + $$ = tmp; + } + | record_type_definition { $$ = $1; } ; @@ -1143,6 +1170,16 @@ for_generate_statement function_specification /* IEEE 1076-2008 P4.2.1 */ : K_function IDENTIFIER '(' interface_list ')' K_return IDENTIFIER + { perm_string type_name = lex_strings.make($7); + perm_string name = lex_strings.make($2); + const VType*type_mark = active_scope->find_type(type_name); + touchup_interface_for_functions($4); + Subprogram*tmp = new Subprogram(name, $4, type_mark); + FILE_NAME(tmp,@1); + delete[]$2; + delete[]$7; + $$ = tmp; + } ; generate_statement /* IEEE 1076-2008 P11.8 */ @@ -1316,6 +1353,16 @@ index_constraint } ; + /* The identifier should be a type name */ +index_subtype_definition /* IEEE 1076-2008 P5.3.2.1 */ + : IDENTIFIER K_range BOX + ; + +index_subtype_definition_list + : index_subtype_definition_list ',' index_subtype_definition + | index_subtype_definition + ; + instantiation_list : identifier_list { @@ -1599,20 +1646,40 @@ package_declarative_part_opt | ; -package_body - : K_package K_body IDENTIFIER K_is +package_body /* IEEE 1076-2008 P4.8 */ + : package_body_start K_is package_body_declarative_part_opt K_end K_package_opt identifier_opt ';' - { sorrymsg(@1, "Package body is not yet supported.\n"); - delete[] $3; - if($8) delete[] $8; + { perm_string name = lex_strings.make($1); + if ($6 && name != $6) + errormsg(@6, "Package name (%s) doesn't match closing name (%s).\n", $1, $6); + delete[] $1; + if($6) delete[]$6; + pop_scope(); } - | K_package K_body IDENTIFIER K_is - error - K_end K_package_opt identifier_opt ';' - { errormsg(@1, "Errors in package body.\n"); + | package_body_start K_is error K_end K_package_opt identifier_opt ';' + { errormsg(@1, "Errors in package %s body.\n", $1); yyerrok; + pop_scope(); + } + ; + +/* + * This is a portion of the package_body rule that we factor out so + * that we can use this rule to start the scope. + */ +package_body_start + : K_package K_body IDENTIFIER + { perm_string name = lex_strings.make($3); + push_scope(); + Package*pkg = library_recall_package(parse_library_name, name); + if (pkg != 0) { + active_scope->set_package_header(pkg); + } else { + errormsg(@1, "Package body for %s has no matching header.\n", $3); + } + $$ = $3; } ; @@ -1723,12 +1790,12 @@ procedure_call $$ = tmp; } | IDENTIFIER '(' error ')' - { - errormsg(@1, "Errors in procedure call.\n"); - yyerrok; - delete[]$1; - $$ = 0; - }; + { errormsg(@1, "Errors in procedure call.\n"); + yyerrok; + delete[]$1; + $$ = 0; + } + ; procedure_call_statement : IDENTIFIER ':' procedure_call { $$ = $3; } @@ -2002,6 +2069,11 @@ sequential_statement shift_expression : simple_expression { $$ = $1; } ; +sign + : '+' + | '-' + ; + signal_declaration_assign_opt : VASSIGN expression { $$ = $2; } | { $$ = 0; } @@ -2020,18 +2092,55 @@ signal_declaration_assign_opt * Note that although the concatenation operator '&' is syntactically * an addition operator, it is handled differently during elaboration * so detect it and create a different expression type. + * + * Note too that I'm using *right* recursion to implement the {...} + * part of the rule. This is normally bad, but expression lists aren't + * normally that long, and the while loop going through the formed + * list fixes up the associations. */ simple_expression + : sign simple_expression_2 + { sorrymsg(@1, "Unary expression +- not supported.\n"); + $$ = $2; + } + | simple_expression_2 + { $$ = $1; } + ; + +simple_expression_2 : term { $$ = $1; } - | simple_expression adding_operator term - { Expression*tmp; - if ($2 == ExpArithmetic::xCONCAT) { - tmp = new ExpConcat($1, $3); - } else { - tmp = new ExpArithmetic($2, $1, $3); + | term simple_expression_terms + { Expression*tmp = $1; + list*lst = $2; + while (! lst->empty()) { + struct adding_term item = lst->front(); + lst->pop_front(); + if (item.op == ExpArithmetic::xCONCAT) + tmp = new ExpConcat(tmp, item.term); + else + tmp = new ExpArithmetic(item.op, tmp, item.term); } - FILE_NAME(tmp, @2); + delete lst; + $$ = tmp; + } + ; + +simple_expression_terms + : adding_operator term + { struct adding_term item; + item.op = $1; + item.term = $2; + list*tmp = new list; + tmp->push_back(item); + $$ = tmp; + } + | simple_expression_terms adding_operator term + { list*tmp = $1; + struct adding_term item; + item.op = $2; + item.term = $3; + tmp->push_back(item); $$ = tmp; } ; @@ -2051,13 +2160,24 @@ signal_assignment_statement } ; + /* This is a function/task body. This may have a matching subprogram + declaration, and if so it will be in the active scope. */ + subprogram_body /* IEEE 1076-2008 P4.3 */ : subprogram_specification K_is subprogram_declarative_part K_begin subprogram_statement_part K_end subprogram_kind_opt identifier_opt ';' - { sorrymsg(@2, "Subprogram bodies not supported.\n"); - if ($8) delete[]$8; + { Subprogram*prog = $1; + Subprogram*tmp = active_scope->recall_subprogram(prog->name()); + if (tmp && prog->compare_specification(tmp)) { + delete prog; + prog = tmp; + } else if (tmp) { + errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str()); + } + prog->set_program_body($5); + active_scope->bind_name(prog->name(), prog); } | subprogram_specification K_is @@ -2066,14 +2186,14 @@ subprogram_body /* IEEE 1076-2008 P4.3 */ subprogram_kind_opt identifier_opt ';' { errormsg(@2, "Syntax errors in subprogram body.\n"); yyerrok; + if ($1) delete $1; if ($8) delete[]$8; } ; subprogram_declaration : subprogram_specification ';' - { sorrymsg(@1, "Subprogram specifications not supported.\n"); - } + { if ($1) active_scope->bind_name($1->name(), $1); } ; subprogram_declarative_item /* IEEE 1079-2008 P4.3 */ @@ -2098,7 +2218,7 @@ subprogram_kind /* IEEE 1076-2008 P4.3 */ subprogram_kind_opt : subprogram_kind | ; subprogram_specification - : function_specification + : function_specification { $$ = $1; } ; /* This is an implementation of the rule: @@ -2107,8 +2227,8 @@ subprogram_specification sequential_statement. Also handle the special case of an empty list here. */ subprogram_statement_part - : sequence_of_statements - | + : sequence_of_statements { $$ = $1; } + | { $$ = 0; } ; subtype_declaration @@ -2132,12 +2252,13 @@ subtype_indication delete[]$1; $$ = tmp; } - | IDENTIFIER '(' simple_expression direction simple_expression ')' - { const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $3, $4, $5); + | IDENTIFIER index_constraint + { const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $2); if (tmp == 0) { errormsg(@1, "Unable to calculate bounds for array of %s.\n", $1); } delete[]$1; + delete $2; $$ = tmp; } | IDENTIFIER K_range simple_expression direction simple_expression @@ -2148,11 +2269,6 @@ subtype_indication delete[]$1; $$ = tmp; } - | IDENTIFIER '(' error ')' - { errormsg(@1, "Syntax error in subtype indication.\n"); - yyerrok; - $$ = new VTypeERROR; - } ; suffix diff --git a/vhdlpp/parse_misc.cc b/vhdlpp/parse_misc.cc index 10c058966..0049388bf 100644 --- a/vhdlpp/parse_misc.cc +++ b/vhdlpp/parse_misc.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -19,6 +20,7 @@ */ # include "parse_misc.h" +# include "parse_types.h" # include "parse_api.h" # include "entity.h" # include "architec.h" @@ -65,11 +67,11 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch) } } -const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, - ScopeBase* /* scope */, - Expression*array_left, - bool /* downto*/ , - Expression*array_right) +static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, + ScopeBase* /* scope */, + Expression*array_left, + bool /* downto*/ , + Expression*array_right) { const VType*base_type = parse_type_by_name(lex_strings.make(base_name)); @@ -98,6 +100,21 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, return base_type; } +const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, + ScopeBase*scope, list*ranges) +{ + if (ranges->size() == 1) { + prange_t*tmpr = ranges->front(); + Expression*lef = tmpr->expr_left(); + Expression*rig = tmpr->expr_right(); + return calculate_subtype_array(loc, base_name, scope, + lef, tmpr->is_downto(), rig); + } + + sorrymsg(loc, "Don't know how to handle multiple ranges here.\n"); + return 0; +} + const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, diff --git a/vhdlpp/parse_misc.h b/vhdlpp/parse_misc.h index da1fd0135..1e4c27669 100644 --- a/vhdlpp/parse_misc.h +++ b/vhdlpp/parse_misc.h @@ -1,7 +1,8 @@ #ifndef __parse_misc_H #define __parse_misc_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -25,6 +26,7 @@ class ActiveScope; class Architecture; class Expression; class Package; +class prange_t; class ScopeBase; class VType; @@ -33,9 +35,7 @@ extern void bind_architecture_to_entity(const char*ename, Architecture*arch); extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, - Expression*array_left, - bool downto, - Expression*array_right); + std::list*ranges); extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, ScopeBase*scope, Expression*range_left, @@ -57,6 +57,8 @@ extern const VType* parse_type_by_name(perm_string name); */ extern void library_save_package(perm_string library_parse_name, Package*pack); +extern Package*library_recall_package(perm_string library_parse_name, perm_string name); + extern void library_import(const YYLTYPE&loc, const std::list*names); extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident); diff --git a/vhdlpp/parse_types.h b/vhdlpp/parse_types.h index 2a8b27520..2773aead8 100644 --- a/vhdlpp/parse_types.h +++ b/vhdlpp/parse_types.h @@ -1,7 +1,8 @@ #ifndef __parse_types_H #define __parse_types_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -74,10 +75,12 @@ class prange_t { ~prange_t() { delete left_; delete right_; } void dump(ostream&out, int indent) const; - Expression*msb() { return direction_? left_ : right_; } - Expression*lsb() { return direction_? right_: left_; } + inline Expression*msb() { return direction_? left_ : right_; } + inline Expression*lsb() { return direction_? right_: left_; } inline bool is_downto() const { return direction_; } + inline Expression*expr_left() { return left_; } + inline Expression*expr_right() { return right_; } private: Expression *left_, *right_; @@ -87,4 +90,10 @@ class prange_t { prange_t(const prange_t&); prange_t operator=(const prange_t&); }; + +struct adding_term { + ExpArithmetic::fun_t op; + Expression*term; +}; + #endif diff --git a/vhdlpp/parse_wrap.h b/vhdlpp/parse_wrap.h index d129fec43..ceca8439e 100644 --- a/vhdlpp/parse_wrap.h +++ b/vhdlpp/parse_wrap.h @@ -31,6 +31,7 @@ # include "architec.h" # include "expression.h" # include "sequential.h" +# include "subprogram.h" # include "parse_types.h" class VType; diff --git a/vhdlpp/scope.cc b/vhdlpp/scope.cc index 0455f7a88..c6f783628 100644 --- a/vhdlpp/scope.cc +++ b/vhdlpp/scope.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -18,9 +19,11 @@ */ # include "scope.h" +# include "package.h" # include # include # include +# include using namespace std; @@ -30,13 +33,11 @@ using namespace std; * "old_*_" variables. This clears up the "new_*_" variables to * accumulate new scope values. */ -ScopeBase::ScopeBase(const ScopeBase&ref) +ScopeBase::ScopeBase(const ActiveScope&ref) { - merge(ref.old_constants_.begin(), ref.old_constants_.end(), - ref.new_constants_.begin(), ref.new_constants_.end(), - insert_iterator >( - old_constants_, old_constants_.end()) - ); + use_constants_ = ref.use_constants_; + cur_constants_ = ref.cur_constants_; + merge(ref.old_signals_.begin(), ref.old_signals_.end(), ref.new_signals_.begin(), ref.new_signals_.end(), insert_iterator >( @@ -52,11 +53,20 @@ ScopeBase::ScopeBase(const ScopeBase&ref) insert_iterator >( old_components_, old_components_.end()) ); - merge(ref.old_types_.begin(), ref.old_types_.end(), - ref.new_types_.begin(), ref.new_types_.end(), - insert_iterator >( - old_types_, old_types_.end()) - ); + use_types_ = ref.use_types_; + cur_types_ = ref.cur_types_; + + use_subprograms_ = ref.use_subprograms_; + cur_subprograms_ = ref.cur_subprograms_; + + // This constructor is invoked when the parser is finished with + // an active scope and is making the actual scope. At this point + // we know that "this" is the parent scope for the subprograms, + // so set it now. + for (map::iterator cur = cur_subprograms_.begin() + ; cur != cur_subprograms_.end() ; ++ cur) { + cur->second->set_parent(this); + } } ScopeBase::~ScopeBase() @@ -74,16 +84,17 @@ void ScopeBase::cleanup() */ delete_all(new_signals_); delete_all(new_components_); - delete_all(new_types_); - delete_all(new_constants_); + delete_all(cur_types_); + delete_all(cur_constants_); + delete_all(cur_subprograms_); } const VType*ScopeBase::find_type(perm_string by_name) { - map::const_iterator cur = new_types_.find(by_name); - if (cur == new_types_.end()) { - cur = old_types_.find(by_name); - if (cur == old_types_.end()) + map::const_iterator cur = cur_types_.find(by_name); + if (cur == cur_types_.end()) { + cur = use_types_.find(by_name); + if (cur == use_types_.end()) return 0; else return cur->second; @@ -93,10 +104,10 @@ const VType*ScopeBase::find_type(perm_string by_name) bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp) { - map::const_iterator cur = new_constants_.find(by_name); - if (cur == new_constants_.end()) { - cur = old_constants_.find(by_name); - if (cur == old_constants_.end()) + map::const_iterator cur = cur_constants_.find(by_name); + if (cur == cur_constants_.end()) { + cur = use_constants_.find(by_name); + if (cur == use_constants_.end()) return false; else { typ = cur->second->typ; @@ -138,6 +149,25 @@ Variable* ScopeBase::find_variable(perm_string by_name) const } } +Subprogram* ScopeBase::find_subprogram(perm_string name) const +{ + map::const_iterator cur; + + cur = cur_subprograms_.find(name); + if (cur != cur_subprograms_.end()) + return cur->second; + + cur = use_subprograms_.find(name); + if (cur != use_subprograms_.end()) + return cur->second; + + return 0; +} + +/* + * This method is only used by the ActiveScope derived class to import + * definition from another scope. + */ void ScopeBase::do_use_from(const ScopeBase*that) { for (map::const_iterator cur = that->old_components_.begin() @@ -146,36 +176,51 @@ void ScopeBase::do_use_from(const ScopeBase*that) continue; old_components_[cur->first] = cur->second; } - for (map::const_iterator cur = that->new_components_.begin() + for (map::const_iterator cur = that->new_components_.begin() ; cur != that->new_components_.end() ; ++ cur) { if (cur->second == 0) continue; old_components_[cur->first] = cur->second; } - for (map::const_iterator cur = that->old_types_.begin() - ; cur != that->old_types_.end() ; ++ cur) { + for (map::const_iterator cur = that->cur_subprograms_.begin() + ; cur != that->cur_subprograms_.end() ; ++ cur) { if (cur->second == 0) continue; - old_types_[cur->first] = cur->second; - } - for (map::const_iterator cur = that->new_types_.begin() - ; cur != that->new_types_.end() ; ++ cur) { - if (cur->second == 0) - continue; - old_types_[cur->first] = cur->second; + use_subprograms_[cur->first] = cur->second; } - for (map::const_iterator cur = that->old_constants_.begin() - ; cur != that->old_constants_.end() ; ++ cur) { - old_constants_[cur->first] = cur->second; + + for (map::const_iterator cur = that->cur_types_.begin() + ; cur != that->cur_types_.end() ; ++ cur) { + if (cur->second == 0) + continue; + use_types_[cur->first] = cur->second; } - for (map::const_iterator cur = that->new_constants_.begin() - ; cur != that->new_constants_.end() ; ++ cur) { - old_constants_[cur->first] = cur->second; + + for (map::const_iterator cur = that->cur_constants_.begin() + ; cur != that->cur_constants_.end() ; ++ cur) { + use_constants_[cur->first] = cur->second; } } +void ActiveScope::set_package_header(Package*pkg) +{ + assert(package_header_ == 0); + package_header_ = pkg; +} + +Subprogram* ActiveScope::recall_subprogram(perm_string name) const +{ + if (Subprogram*tmp = find_subprogram(name)) + return tmp; + + if (package_header_) + return package_header_->find_subprogram(name); + + return 0; +} + bool ActiveScope::is_vector_name(perm_string name) const { if (find_signal(name)) @@ -189,7 +234,7 @@ bool ActiveScope::is_vector_name(perm_string name) const return false; } -Scope::Scope(const ScopeBase&ref) +Scope::Scope(const ActiveScope&ref) : ScopeBase(ref) { } diff --git a/vhdlpp/scope.h b/vhdlpp/scope.h index e0fbfb0b3..790c709c9 100644 --- a/vhdlpp/scope.h +++ b/vhdlpp/scope.h @@ -1,7 +1,8 @@ #ifndef __scope_H #define __scope_H /* - * Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -23,12 +24,16 @@ # include # include # include "StringHeap.h" -# include "entity.h" -# include "expression.h" -# include "vsignal.h" +# include "entity.h" +# include "expression.h" +# include "subprogram.h" +# include "vsignal.h" +class ActiveScope; class Architecture; class ComponentBase; +class Package; +class Subprogram; class VType; template @@ -45,13 +50,14 @@ class ScopeBase { public: ScopeBase() { } - explicit ScopeBase(const ScopeBase&ref); + explicit ScopeBase(const ActiveScope&ref); virtual ~ScopeBase() =0; const VType* find_type(perm_string by_name); bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp); Signal* find_signal(perm_string by_name) const; Variable* find_variable(perm_string by_name) const; + Subprogram* find_subprogram(perm_string by_name) const; protected: void cleanup(); @@ -66,6 +72,12 @@ class ScopeBase { for_each(c.begin(), c.end(), ::delete_pair_second()); } + // The new_*_ maps below are managed only by the ActiveScope + // derived class. When any scope is constructed from the + // ActiveScope, the new_*_ and old_*_ maps are merged and + // installed into the old_*_ maps. Thus, all other derived + // classes should only use the old_*_ maps. + // Signal declarations... std::map old_signals_; //previous scopes std::map new_signals_; //current scope @@ -76,8 +88,8 @@ class ScopeBase { std::map old_components_; //previous scopes std::map new_components_; //current scope // Type declarations... - std::map old_types_; //previous scopes - std::map new_types_; //current scope + std::map use_types_; //imported types + std::map cur_types_; //current types // Constant declarations... struct const_t { ~const_t() {delete typ; delete val;} @@ -86,8 +98,11 @@ class ScopeBase { const VType*typ; Expression*val; }; - std::map old_constants_; //previous scopes - std::map new_constants_; //current scope + std::map use_constants_; //imported constants + std::map cur_constants_; //current constants + + std::map use_subprograms_; //imported + std::map cur_subprograms_; //current void do_use_from(const ScopeBase*that); }; @@ -95,7 +110,7 @@ class ScopeBase { class Scope : public ScopeBase { public: - explicit Scope(const ScopeBase&ref); + explicit Scope(const ActiveScope&ref); ~Scope(); ComponentBase* find_component(perm_string by_name); @@ -118,18 +133,28 @@ class Scope : public ScopeBase { class ActiveScope : public ScopeBase { public: - ActiveScope() : context_entity_(0) { } - ActiveScope(ActiveScope*par) : ScopeBase(*par), context_entity_(0) { } + ActiveScope() : package_header_(0), context_entity_(0) { } + ActiveScope(ActiveScope*par) : ScopeBase(*par), package_header_(0), context_entity_(0) { } ~ActiveScope() { } - void use_from(const ScopeBase*that) { do_use_from(that); } + void set_package_header(Package*); + + // Pull items from "that" scope into "this" scope as is + // defined by a "use" directive. The parser uses this method + // to implement the "use ::*" directive. + void use_from(const Scope*that) { do_use_from(that); } // This function returns true if the name is a vectorable // name. The parser uses this to distinguish between function // calls and array index operations. bool is_vector_name(perm_string name) const; + // Locate the subprogram by name. The subprogram body uses + // this to locate the sobprogram declaration. Note that the + // subprogram may be in a package header. + Subprogram* recall_subprogram(perm_string name) const; + /* All bind_name function check if the given name was present * in previous scopes. If it is found, it is erased (but the pointer * is not freed), in order to implement name shadowing. The pointer @@ -159,16 +184,26 @@ class ActiveScope : public ScopeBase { void bind_name(perm_string name, const VType* t) { map::iterator it; - if((it = old_types_.find(name)) != old_types_.end() ) - old_types_.erase(it); - new_types_[name] = t; + if((it = use_types_.find(name)) != use_types_.end() ) + use_types_.erase(it); + cur_types_[name] = t; } + inline void use_name(perm_string name, const VType* t) + { use_types_[name] = t; } + void bind_name(perm_string name, const VType*obj, Expression*val) { map::iterator it; - if((it = old_constants_.find(name)) != old_constants_.end() ) - old_constants_.erase(it); - new_constants_[name] = new const_t(obj, val); + if((it = use_constants_.find(name)) != use_constants_.end() ) + use_constants_.erase(it); + cur_constants_[name] = new const_t(obj, val); + } + + inline void bind_name(perm_string name, Subprogram*obj) + { map::iterator it; + if((it = use_subprograms_.find(name)) != use_subprograms_.end() ) + use_subprograms_.erase(it); + cur_subprograms_[name] = obj;; } void bind(Entity*ent) @@ -184,6 +219,10 @@ class ActiveScope : public ScopeBase { std::map incomplete_types; private: + // If this is a package body, then there is a Package header + // already declared. + Package*package_header_; + Entity*context_entity_; }; diff --git a/vhdlpp/sequential.h b/vhdlpp/sequential.h index bd553fef6..5e12ec503 100644 --- a/vhdlpp/sequential.h +++ b/vhdlpp/sequential.h @@ -1,7 +1,8 @@ #ifndef __sequential_H #define __sequential_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -116,6 +117,7 @@ class ReturnStmt : public SequentialStmt { ~ReturnStmt(); public: + int emit(ostream&out, Entity*entity, Architecture*arc); void dump(ostream&out, int indent) const; private: diff --git a/vhdlpp/sequential_emit.cc b/vhdlpp/sequential_emit.cc index a7e8e40f4..e3c0fab71 100644 --- a/vhdlpp/sequential_emit.cc +++ b/vhdlpp/sequential_emit.cc @@ -1,5 +1,6 @@ /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -82,6 +83,14 @@ int IfSequential::Elsif::statement_emit(ostream&out, Entity*ent, Architecture*ar return errors; } +int ReturnStmt::emit(ostream&out, Entity*ent, Architecture*arc) +{ + int errors = 0; + out << "return "; + errors += val_->emit(out, ent, arc); + out << ";" << endl; + return errors; +} int SignalSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc) { @@ -203,13 +212,23 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc) ivl_assert(*this, start_rc); ivl_assert(*this, finish_rc); - if (range_->is_downto() && start_val < finish_val) { - out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl; + if (! range_->is_downto()) { + int64_t tmp = start_val; + start_val = finish_val; + finish_val = tmp; + } + + if (range_->is_downto() && (start_val < finish_val)) { + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " downto " << finish_val << " */ end" << endl; return errors; } if (!range_->is_downto() && start_val > finish_val) { - out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl; + out << "begin /* Degenerate loop at " << get_fileline() + << ": " << start_val + << " to " << finish_val << " */ end" << endl; return errors; } diff --git a/vhdlpp/subprogram.cc b/vhdlpp/subprogram.cc new file mode 100644 index 000000000..47641550c --- /dev/null +++ b/vhdlpp/subprogram.cc @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "subprogram.h" +# include "entity.h" +# include "vtype.h" +# include "ivl_assert.h" + +using namespace std; + +Subprogram::Subprogram(perm_string nam, list*ports, + const VType*return_type) +: name_(nam), parent_(0), ports_(ports), return_type_(return_type), statements_(0) +{ +} + +Subprogram::~Subprogram() +{ +} + +void Subprogram::set_parent(const ScopeBase*par) +{ + ivl_assert(*this, parent_ == 0); + parent_ = par; +} + +void Subprogram::set_program_body(list*stmt) +{ + ivl_assert(*this, statements_==0); + statements_ = stmt; +} + +bool Subprogram::compare_specification(Subprogram*that) const +{ + if (name_ != that->name_) + return false; + + if (return_type_==0) { + if (that->return_type_!=0) + return false; + } else { + if (that->return_type_==0) + return false; + + if (! return_type_->type_match(that->return_type_)) + return false; + } + + if (ports_==0) { + if (that->ports_!=0) + return false; + + } else { + if (that->ports_==0) + return false; + + if (ports_->size() != that->ports_->size()) + return false; + } + + return true; +} + +void Subprogram::write_to_stream(ostream&fd) const +{ + fd << " function " << name_ << "("; + if (ports_ && ! ports_->empty()) { + list::const_iterator cur = ports_->begin(); + InterfacePort*curp = *cur; + fd << curp->name << " : "; + curp->type->write_to_stream(fd); + for (++cur ; cur != ports_->end() ; ++cur) { + curp = *cur; + fd << "; " << curp->name << " : "; + curp->type->write_to_stream(fd); + } + } + fd << ") return "; + return_type_->write_to_stream(fd); + fd << ";" << endl; +} diff --git a/vhdlpp/subprogram.h b/vhdlpp/subprogram.h new file mode 100644 index 000000000..304fa06cf --- /dev/null +++ b/vhdlpp/subprogram.h @@ -0,0 +1,65 @@ +#ifndef __subprogram_H +#define __subprogram_H +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "StringHeap.h" +# include "LineInfo.h" +# include +# include + +class InterfacePort; +class ScopeBase; +class SequentialStmt; +class VType; + +class Subprogram : public LineInfo { + + public: + Subprogram(perm_string name, std::list*ports, + const VType*return_type); + ~Subprogram(); + + void set_parent(const ScopeBase*par); + inline const ScopeBase*get_parent() const { return parent_; } + + inline const perm_string&name() const { return name_; } + + void set_program_body(std::list*statements); + + // Return true if the specification (name, types, ports) + // matches this subprogram and that subprogram. + bool compare_specification(Subprogram*that) const; + + // Emit a definition as it would show up in a package. + int emit_package(std::ostream&fd) const; + + void write_to_stream(std::ostream&fd) const; + void dump(std::ostream&fd) const; + + private: + perm_string name_; + const ScopeBase*parent_; + std::list*ports_; + const VType*return_type_; + std::list*statements_; +}; + +#endif diff --git a/vhdlpp/subprogram_emit.cc b/vhdlpp/subprogram_emit.cc new file mode 100644 index 000000000..efd586bd0 --- /dev/null +++ b/vhdlpp/subprogram_emit.cc @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "subprogram.h" +# include "sequential.h" +# include "vtype.h" +# include + +using namespace std; + +int Subprogram::emit_package(ostream&fd) const +{ + int errors = 0; + + if (return_type_) { + fd << "function "; + return_type_->emit_def(fd); + fd << " " << name_; + fd << "("; + } else { + fd << "task " << name_ << ";" << endl; + } + + for (list::const_iterator cur = ports_->begin() + ; cur != ports_->end() ; ++cur) { + if (cur != ports_->begin()) + fd << ", "; + InterfacePort*curp = *cur; + switch (curp->mode) { + case PORT_IN: + fd << "input "; + break; + case PORT_OUT: + fd << "output "; + break; + case PORT_NONE: + fd << "inout /* PORT_NONE? */ "; + break; + } + + errors += curp->type->emit_def(fd); + fd << " \\" << curp->name << " "; + } + + fd << ");" << endl; + + if (statements_) { + for (list::const_iterator cur = statements_->begin() + ; cur != statements_->end() ; ++cur) { + errors += (*cur)->emit(fd, 0, 0); + } + } else { + fd << " begin /* empty body */ end" << endl; + } + + if (return_type_) + fd << "endfunction" << endl; + else + fd << "endtask" << endl; + + return errors; +} diff --git a/vhdlpp/vtype.cc b/vhdlpp/vtype.cc index b8e704d11..34787c6a0 100644 --- a/vhdlpp/vtype.cc +++ b/vhdlpp/vtype.cc @@ -32,7 +32,7 @@ VType::~VType() void VType::show(ostream&out) const { - out << typeid(*this).name(); + write_to_stream(out); } VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt) @@ -53,6 +53,9 @@ void VTypePrimitive::show(ostream&out) const case BIT: out << "BIT"; break; + case CHARACTER: + out << "CHARACTER"; + break; case INTEGER: out << "INTEGER"; break; diff --git a/vhdlpp/vtype.h b/vhdlpp/vtype.h index 4da22363d..e18e9ecbd 100644 --- a/vhdlpp/vtype.h +++ b/vhdlpp/vtype.h @@ -1,7 +1,8 @@ #ifndef __vtype_H #define __vtype_H /* - * Copyright (c) 2011 Stephen Williams (steve@icarus.com) + * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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 @@ -27,6 +28,8 @@ # include # include "StringHeap.h" +class Architecture; +class Entity; class Expression; class prange_t; class VTypeDef; @@ -45,6 +48,15 @@ class VType { VType() { } virtual ~VType() =0; + // This is rarely used, but some types may have expressions + // that need to be elaborated. + virtual int elaborate(Entity*end, Architecture*arc) const; + + // This virtual method returns true if that is equivalent to + // this type. This method is used for example to compare + // function prototypes. + virtual bool type_match(const VType*that) const; + // This virtual method writes a VHDL-accurate representation // of this type to the designated stream. This is used for // writing parsed types to library files. @@ -112,7 +124,7 @@ class VTypeERROR : public VType { class VTypePrimitive : public VType { public: - enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC }; + enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC, CHARACTER }; public: VTypePrimitive(type_t); @@ -134,6 +146,7 @@ extern const VTypePrimitive* primitive_BOOLEAN; extern const VTypePrimitive* primitive_BIT; extern const VTypePrimitive* primitive_INTEGER; extern const VTypePrimitive* primitive_STDLOGIC; +extern const VTypePrimitive* primitive_CHARACTER; /* * An array is a compound N-dimensional array of element type. The @@ -164,6 +177,7 @@ class VTypeArray : public VType { VTypeArray(const VType*etype, std::list*r, bool signed_vector =false); ~VTypeArray(); + int elaborate(Entity*ent, Architecture*arc) const; void write_to_stream(std::ostream&fd) const; void show(std::ostream&) const; @@ -191,6 +205,10 @@ class VTypeRange : public VType { VTypeRange(const VType*base, int64_t max_val, int64_t min_val); ~VTypeRange(); + // Get the type that is limited by the range. + inline const VType* base_type() const { return base_; } + + public: // Virtual methods void write_to_stream(std::ostream&fd) const; int emit_def(std::ostream&out) const; diff --git a/vhdlpp/vtype_elaborate.cc b/vhdlpp/vtype_elaborate.cc new file mode 100644 index 000000000..f3611d9f4 --- /dev/null +++ b/vhdlpp/vtype_elaborate.cc @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "vtype.h" +# include "expression.h" + +int VType::elaborate(Entity*, Architecture*) const +{ + return 0; +} + +int VTypeArray::elaborate(Entity*ent, Architecture*arc) const +{ + int errors = 0; + etype_->elaborate(ent, arc); + + for (vector::const_iterator cur = ranges_.begin() + ; cur != ranges_.end() ; ++ cur) { + + Expression*tmp = cur->msb(); + if (tmp) errors += tmp->elaborate_expr(ent, arc, 0); + + tmp = cur->lsb(); + if (tmp) errors += tmp->elaborate_expr(ent, arc, 0); + } + + return errors; +} diff --git a/vhdlpp/vtype_emit.cc b/vhdlpp/vtype_emit.cc index a3ca1add5..7508ee8c4 100644 --- a/vhdlpp/vtype_emit.cc +++ b/vhdlpp/vtype_emit.cc @@ -88,9 +88,15 @@ int VTypeArray::emit_def(ostream&out) const cur = dims.front(); dims.pop_front(); out << "["; - errors += cur->dimension(0).msb()->emit(out, 0, 0); + if (cur->dimension(0).msb()) + errors += cur->dimension(0).msb()->emit(out, 0, 0); + else + out << "?error?"; out << ":"; - errors += cur->dimension(0).lsb()->emit(out, 0, 0); + if (cur->dimension(0).lsb()) + errors += cur->dimension(0).lsb()->emit(out, 0, 0); + else + out << "?error?"; out << "]"; } @@ -130,6 +136,9 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const case INTEGER: out << "bool [31:0]"; break; + case CHARACTER: + out << "char"; + break; default: assert(0); break; diff --git a/vhdlpp/vtype_match.cc b/vhdlpp/vtype_match.cc new file mode 100644 index 000000000..e0559d24d --- /dev/null +++ b/vhdlpp/vtype_match.cc @@ -0,0 +1,26 @@ +/* + * Copyright (c) 2013 Stephen Williams (steve@icarus.com) + * Copyright CERN 2013 / 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +# include "vtype.h" + +bool VType::type_match(const VType*that) const +{ + return this == that; +} diff --git a/vhdlpp/vtype_stream.cc b/vhdlpp/vtype_stream.cc index 661626e6a..ed21e5a99 100644 --- a/vhdlpp/vtype_stream.cc +++ b/vhdlpp/vtype_stream.cc @@ -17,9 +17,11 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +# define __STDC_LIMIT_MACROS # include "vtype.h" # include "expression.h" # include +# include # include using namespace std; @@ -115,6 +117,15 @@ void VTypePrimitive::write_to_stream(ostream&fd) const void VTypeRange::write_to_stream(ostream&fd) const { + // Detect some special cases that can be written as ieee or + // standard types. + if (const VTypePrimitive*tmp = dynamic_cast (base_)) { + if (min_==0 && max_==INT64_MAX && tmp->type()==VTypePrimitive::INTEGER) { + fd << "natural"; + return; + } + } + base_->write_to_stream(fd); fd << " range " << min_ << " to " << max_; }