diff --git a/PExpr.h b/PExpr.h index c19657cff..a7dd0701a 100644 --- a/PExpr.h +++ b/PExpr.h @@ -387,9 +387,9 @@ class PEIdent : public PExpr { bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*, index_component_t::ctype_t, bool need_const_idx) const; - bool elaborate_lval_net_class_member_(Design*, NetScope*, - NetAssign_*, - const perm_string&) const; + NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*, + NetNet*, + const perm_string&) const; bool elaborate_lval_net_packed_member_(Design*, NetScope*, NetAssign_*, const perm_string&) const; diff --git a/PTask.h b/PTask.h index cbd2d7e2a..a79e5f95c 100644 --- a/PTask.h +++ b/PTask.h @@ -110,6 +110,8 @@ class PFunction : public PTaskFunc { void set_statement(Statement *s); void set_return(const data_type_t*t); + inline Statement* get_statement() { return statement_; } + void elaborate_scope(Design*des, NetScope*scope) const; /* elaborate the ports and return value. */ diff --git a/Statement.cc b/Statement.cc index 79d63fb63..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 @@ -21,6 +21,7 @@ # include "Statement.h" # include "PExpr.h" +# include "ivl_assert.h" Statement::~Statement() { @@ -126,6 +127,17 @@ void PBlock::set_statement(const vector&st) list_ = st; } +void PBlock::push_statement_front(Statement*that) +{ + ivl_assert(*this, bl_type_==BL_SEQ); + + list_.resize(list_.size()+1); + for (size_t idx = list_.size()-1 ; idx > 0 ; idx -= 1) + list_[idx] = list_[idx-1]; + + list_[0] = that; +} + PCallTask::PCallTask(const pform_name_t&n, const list&p) : package_(0), path_(n), parms_(p.size()) { @@ -329,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 43f299443..510298e43 100644 --- a/Statement.h +++ b/Statement.h @@ -186,6 +186,10 @@ class PBlock : public PScope, public Statement { void set_statement(const std::vector&st); + // Copy the statement from that block to the front of this + // block. + void push_statement_front(Statement*that); + virtual void dump(ostream&out, unsigned ind) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const; @@ -462,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 dc24c0294..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) @@ -1135,7 +1164,11 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope, } const netclass_t* class_type = net->class_type(); - member_type = class_type->get_property(member_name); + int midx = class_type->property_idx_from_name(member_name); + if (midx >= 0) + member_type = class_type->get_prop_type(midx); + else + member_type = 0; use_path = tmp_path; use_darray = dynamic_cast (member_type); @@ -1228,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. */ @@ -1755,15 +1801,25 @@ static NetExpr* check_for_struct_members(const LineInfo*li, return sel; } +static NetExpr* class_static_property_expression(const LineInfo*li, + const netclass_t*class_type, + perm_string name) +{ + NetNet*sig = class_type->find_static_property(name); + ivl_assert(*li, sig); + NetESignal*expr = new NetESignal(sig); + expr->set_line(*li); + return expr; +} + static NetExpr* check_for_class_property(const LineInfo*li, - Design*des, NetScope*, + Design*des, NetScope*scope, NetNet*net, const name_component_t&comp) { const netclass_t*class_type = net->class_type(); - const ivl_type_s*ptype = class_type->get_property(comp.name); - - if (ptype == 0) { + int pidx = class_type->property_idx_from_name(comp.name); + if (pidx < 0) { cerr << li->get_fileline() << ": error: " << "Class " << class_type->get_name() << " has no property " << comp.name << "." << endl; @@ -1771,6 +1827,29 @@ static NetExpr* check_for_class_property(const LineInfo*li, return 0; } + if (debug_elaborate) { + cerr << li->get_fileline() << ": check_for_class_property: " + << "Property " << comp.name + << " of net " << net->name() + << ", context scope=" << scope_path(scope) + << endl; + } + + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << li->get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + + if (qual.test_static()) { + perm_string prop_name = lex_strings.make(class_type->get_prop_name(pidx)); + return class_static_property_expression(li, class_type, + prop_name); + } + NetEProperty*tmp = new NetEProperty(net, comp.name); tmp->set_line(*li); return tmp; @@ -1881,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; @@ -2012,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; @@ -2715,8 +2817,9 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode) } if (const netclass_t*class_type = net->class_type()) { - const ivl_type_s*ptype = class_type->get_property(method_name); - if (ptype) { + int pidx = class_type->property_idx_from_name(method_name); + if (pidx >= 0) { + ivl_type_t ptype = class_type->get_prop_type(pidx); expr_type_ = ptype->base_type(); expr_width_ = ptype->packed_width(); min_width_ = expr_width_; @@ -2823,7 +2926,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope, * not a method, or the name is not in the parent class, then * fail. Otherwise, return a NetEProperty. */ -NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope, +NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope, unsigned, unsigned) const { if (!gn_system_verilog()) @@ -2854,9 +2957,23 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope, cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: " << "Found member " << member_name << " is a member of class " << class_type->get_name() + << ", context scope=" << scope_path(scope) << ", so synthesizing a NetEProperty." << endl; } + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + } + + if (qual.test_static()) { + return class_static_property_expression(this, class_type, member_name); + } + NetEProperty*tmp = new NetEProperty(this_net, member_name); tmp->set_line(*this); return tmp; @@ -4464,13 +4581,35 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&) NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, ivl_type_t ntype, unsigned) const { - NetENew*obj = new NetENew(ntype); + NetExpr*obj = new NetENew(ntype); obj->set_line(*this); // Find the constructor for the class. If there is no // constructor then the result of this expression is the // allocation alone. const netclass_t*ctype = dynamic_cast (ntype); + + // If there is an initializer function, then pass the object + // through that function first. Note tha the initializer + // function has no arguments other then the object itself. + if (NetScope*new1_scope = ctype->method_from_name(perm_string::literal("new@"))) { + NetFuncDef*def1 = new1_scope->func_def(); + ivl_assert(*this, def1); + ivl_assert(*this, def1->port_count()==1); + vector parms1 (1); + parms1[0] = obj; + + // The return value of the initializer is the "this" + // variable, instead of the "new&" scope name. + NetNet*res1 = new1_scope->find_signal(perm_string::literal("@")); + ivl_assert(*this, res1); + + NetESignal*eres = new NetESignal(res1); + NetEUFunc*tmp = new NetEUFunc(scope, new1_scope, eres, parms1, true); + tmp->set_line(*this); + obj = tmp; + } + NetScope*new_scope = ctype->method_from_name(perm_string::literal("new")); if (new_scope == 0) { // No constructor. diff --git a/elab_lval.cc b/elab_lval.cc index 7e1d5193a..f4bc96e6b 100644 --- a/elab_lval.cc +++ b/elab_lval.cc @@ -256,8 +256,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, } if (reg->class_type() && !method_name.nil() && gn_system_verilog()) { - NetAssign_*lv = new NetAssign_(reg); - elaborate_lval_net_class_member_(des, use_scope, lv, method_name); + NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, method_name); return lv; } @@ -316,7 +315,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des, return lv; } -NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*, +NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des, NetScope*scope) const { if (!gn_system_verilog()) @@ -343,6 +342,40 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*, return 0; } + // Detect assignment to constant properties. Note that the + // initializer constructor MAY assign to constant properties, + // as this is how the property gets its value. + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_const()) { + if (class_type->get_prop_initialized(pidx)) { + cerr << get_fileline() << ": error: " + << "Property " << class_type->get_prop_name(pidx) + << " is constant in this method." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + + } else if (scope->basename()!="new" && scope->basename()!="new@") { + cerr << get_fileline() << ": error: " + << "Property " << class_type->get_prop_name(pidx) + << " is constant in this method." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + + } else { + + // Mark this property as initilized. This is used + // to know that we have initialized the constant + // object so the next assignment will be marked as + // illegal. + class_type->set_prop_initialized(pidx); + + if (debug_elaborate) { + cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: " + << "Found initilzers for property " << class_type->get_prop_name(pidx) << endl; + } + } + } + NetAssign_*this_lval = new NetAssign_(this_net); this_lval->set_property(member_name); @@ -812,31 +845,58 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des, return true; } -bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, - NetAssign_*lv, - const perm_string&method_name) const +NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope, + NetNet*sig, const perm_string&method_name) const { if (debug_elaborate) { cerr << get_fileline() << ": elaborate_lval_net_class_member_: " << "l-value is property " << method_name - << " of " << lv->sig()->name() << "." << endl; + << " of " << sig->name() << "." << endl; } - const netclass_t*class_type = lv->sig()->class_type(); + const netclass_t*class_type = sig->class_type(); ivl_assert(*this, class_type); /* Make sure the property is really present in the class. If not, then generate an error message and return an error. */ - ivl_type_t ptype = class_type->get_property(method_name); - if (ptype == 0) { + int pidx = class_type->property_idx_from_name(method_name); + if (pidx < 0) { cerr << get_fileline() << ": error: Class " << class_type->get_name() << " does not have a property " << method_name << "." << endl; des->errors += 1; - return false; + return 0; } + property_qualifier_t qual = class_type->get_prop_qual(pidx); + if (qual.test_local() && ! class_type->test_scope_is_method(scope)) { + cerr << get_fileline() << ": error: " + << "Local property " << class_type->get_prop_name(pidx) + << " is not accessible (l-value) in this context." + << " (scope=" << scope_path(scope) << ")" << endl; + des->errors += 1; + + } else if (qual.test_static()) { + + // Special case: this is a static property. Ignore the + // "this" sig and use the property itself, which is not + // part of the sig, as the l-value. + NetNet*psig = class_type->find_static_property(method_name); + ivl_assert(*this, psig); + + NetAssign_*lv = new NetAssign_(psig); + return lv; + + } else if (qual.test_const()) { + cerr << get_fileline() << ": error: " + << "Property " << class_type->get_prop_name(pidx) + << " is constant in this context." << endl; + des->errors += 1; + } + + NetAssign_*lv = new NetAssign_(sig); lv->set_property(method_name); + ivl_type_t ptype = class_type->get_prop_type(pidx); const netdarray_t*mtype = dynamic_cast (ptype); if (mtype) { const name_component_t&name_tail = path_.back(); @@ -848,7 +908,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, } } - return true; + return lv; } diff --git a/elab_scope.cc b/elab_scope.cc index 91c1b9fb5..7b0aa224a 100644 --- a/elab_scope.cc +++ b/elab_scope.cc @@ -293,8 +293,60 @@ static void elaborate_scope_enumerations(Design*des, NetScope*scope, } } -static void elaborate_scope_class(Design*des, NetScope*scope, - PClass*pclass) +/* + * If the pclass includes an implicit and explicit constructor, then + * merge the implicit constructor into the explicit constructor as + * statements in the beginning. + * + * This is not necessary for proper functionality, it is an + * optimization, so we can easily give up if it doesn't seem like it + * will obviously work. + */ +static void blend_class_constructors(PClass*pclass) +{ + perm_string new1 = perm_string::literal("new"); + perm_string new2 = perm_string::literal("new@"); + + map::iterator iter_new = pclass->funcs.find(new1); + if (iter_new == pclass->funcs.end()) + return; + + map::iterator iter_new2 = pclass->funcs.find(new2); + if (iter_new2 == pclass->funcs.end()) + return; + + PFunction*use_new = iter_new->second; + PFunction*use_new2 = iter_new2->second; + + // These constructors must be methods of the same class. + ivl_assert(*use_new, use_new->method_of() == use_new2->method_of()); + + Statement*def_new = use_new->get_statement(); + Statement*def_new2 = use_new2->get_statement(); + + // If either constructor has no definition, then give up. This + // might happen, for example, during parse errors or other + // degenerate situations. + if (def_new==0 || def_new2==0) + return; + + PBlock*blk_new = dynamic_cast (def_new); + + // For now, only do this if the functions are defined by + // statement blocks. That should be true by definition for + // implicit constructors, and common for explicit constructors. + if (blk_new==0) + return; + + ivl_assert(*blk_new, blk_new ->bl_type()==PBlock::BL_SEQ); + + blk_new->push_statement_front(def_new2); + + pclass->funcs.erase(iter_new2); + delete use_new2; +} + +static void elaborate_scope_class(Design*des, NetScope*scope, PClass*pclass) { class_type_t*use_type = pclass->type; netclass_t*use_class = new netclass_t(use_type->name); @@ -314,15 +366,15 @@ static void elaborate_scope_class(Design*des, NetScope*scope, // Collect the properties, elaborate them, and add them to the // elaborated class definition. - for (map::iterator cur = use_type->properties.begin() + for (map::iterator cur = use_type->properties.begin() ; cur != use_type->properties.end() ; ++ cur) { if (debug_scopes) { cerr << pclass->get_fileline() << ": elaborate_scope_class: " << " Property " << cur->first << endl; } - ivl_type_s*tmp = cur->second->elaborate_type(des, scope); + ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope); ivl_assert(*pclass, tmp); - use_class->set_property(cur->first, tmp); + use_class->set_property(cur->first, cur->second.qual, tmp); } for (map::iterator cur = pclass->tasks.begin() @@ -367,8 +419,10 @@ static void elaborate_scope_class(Design*des, NetScope*scope, static void elaborate_scope_classes(Design*des, NetScope*scope, const vector&classes) { - for (size_t idx = 0 ; idx < classes.size() ; idx += 1) + for (size_t idx = 0 ; idx < classes.size() ; idx += 1) { + blend_class_constructors(classes[idx]); elaborate_scope_class(des, scope, classes[idx]); + } } static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, diff --git a/elab_sig.cc b/elab_sig.cc index 35e867426..87862e8f7 100644 --- a/elab_sig.cc +++ b/elab_sig.cc @@ -314,6 +314,25 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const void netclass_t::elaborate_sig(Design*des, PClass*pclass) { + for (map::iterator cur = pclass->type->properties.begin() + ; cur != pclass->type->properties.end() ; ++ cur) { + + if (! cur->second.qual.test_static()) + continue; + + if (debug_elaborate) { + cerr << pclass->get_fileline() << ": netclass_t::elaborate_sig: " + << "Elaborate static property " << cur->first + << " as signal in scope " << scope_path(class_scope_) + << "." << endl; + } + + list nil_list; + ivl_type_t use_type = cur->second.type->elaborate_type(des, class_scope_); + NetNet*sig = new NetNet(class_scope_, cur->first, NetNet::REG, + nil_list, use_type); + } + for (map::iterator cur = pclass->funcs.begin() ; cur != pclass->funcs.end() ; ++ cur) { if (debug_elaborate) { @@ -538,7 +557,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const elaborate_sig_wires_(des, scope); NetNet*ret_sig; - if (gn_system_verilog() && fname == "new") { + if (gn_system_verilog() && fname=="new" || fname=="new@") { // Special case: this is a constructor, so the return // signal is also the first argument. For example, the // source code for the definition may be: @@ -964,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. */ @@ -974,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 418206c20..b519634af 100644 --- a/elaborate.cc +++ b/elaborate.cc @@ -2361,11 +2361,17 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const return cur; } +/* + * Assignments within program blocks can only write to certain types + * of variables. We can only write to: + * - variables in a program block + * - static properties of a class + */ static bool lval_not_program_variable(const NetAssign_*lv) { while (lv) { NetScope*sig_scope = lv->sig()->scope(); - if (! sig_scope->program_block()) + if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS) return true; lv = lv->more; @@ -2793,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; } @@ -4445,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 @@ -4883,6 +4944,13 @@ static void elaborate_classes(Design*des, NetScope*scope, ; cur != classes.end() ; ++ cur) { netclass_t*use_class = scope->find_class(cur->second->pscope_name()); use_class->elaborate(des, cur->second); + + if (use_class->test_for_missing_initializers()) { + cerr << cur->second->get_fileline() << ": error: " + << "Const properties of class " << use_class->get_name() + << " are missing initialization." << endl; + des->errors += 1; + } } } @@ -4962,6 +5030,19 @@ bool Module::elaborate(Design*des, NetScope*scope) const */ void netclass_t::elaborate(Design*des, PClass*pclass) { + if (! pclass->type->initialize_static.empty()) { + std::vector&stmt_list = pclass->type->initialize_static; + NetBlock*stmt = new NetBlock(NetBlock::SEQU, 0); + for (size_t idx = 0 ; idx < stmt_list.size() ; idx += 1) { + NetProc*tmp = stmt_list[idx]->elaborate(des, class_scope_); + if (tmp == 0) continue; + stmt->append(tmp); + } + NetProcTop*top = new NetProcTop(class_scope_, IVL_PR_INITIAL, stmt); + top->set_line(*pclass); + des->add_process(top); + } + for (map::iterator cur = pclass->funcs.begin() ; cur != pclass->funcs.end() ; ++ cur) { if (debug_elaborate) { 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_assign.cc b/net_assign.cc index d787478a8..0562fb1e5 100644 --- a/net_assign.cc +++ b/net_assign.cc @@ -96,9 +96,9 @@ unsigned NetAssign_::lwidth() const if (member_.nil()) return 1; - const ivl_type_s*ptype = class_type->get_property(member_); - ivl_assert(*sig_, ptype); - + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t ptype = class_type->get_prop_type(pidx); return ptype->packed_width(); } @@ -118,7 +118,9 @@ ivl_variable_type_t NetAssign_::expr_type() const if (member_.nil()) return sig_->data_type(); - const ivl_type_s*tmp = class_type->get_property(member_); + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t tmp = class_type->get_prop_type(pidx); return tmp->base_type(); } @@ -138,8 +140,9 @@ const ivl_type_s* NetAssign_::net_type() const if (member_.nil()) return sig_->net_type(); - const ivl_type_s*tmp = class_type->get_property(member_); - ivl_assert(*sig_, tmp); + int pidx = class_type->property_idx_from_name(member_); + ivl_assert(*sig_, pidx >= 0); + ivl_type_t tmp = class_type->get_prop_type(pidx); return tmp; } 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/netclass.cc b/netclass.cc index 690443f13..7f2fb97d3 100644 --- a/netclass.cc +++ b/netclass.cc @@ -32,7 +32,7 @@ netclass_t::~netclass_t() { } -bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype) +bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype) { map::const_iterator cur; cur = properties_.find(pname); @@ -41,7 +41,9 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype) prop_t tmp; tmp.name = pname; + tmp.qual = qual; tmp.type = ptype; + tmp.initialized_flag = false; property_table_.push_back(tmp); properties_[pname] = property_table_.size()-1; @@ -59,17 +61,6 @@ ivl_variable_type_t netclass_t::base_type() const return IVL_VT_CLASS; } -const ivl_type_s* netclass_t::get_property(perm_string pname) const -{ - map::const_iterator cur; - cur = properties_.find(pname); - if (cur == properties_.end()) - return 0; - - assert(property_table_.size() > cur->second); - return property_table_[cur->second].type; -} - int netclass_t::property_idx_from_name(perm_string pname) const { map::const_iterator cur; @@ -86,12 +77,43 @@ const char*netclass_t::get_prop_name(size_t idx) const return property_table_[idx].name; } +property_qualifier_t netclass_t::get_prop_qual(size_t idx) const +{ + assert(idx < property_table_.size()); + return property_table_[idx].qual; +} + ivl_type_t netclass_t::get_prop_type(size_t idx) const { assert(idx < property_table_.size()); return property_table_[idx].type; } +bool netclass_t::get_prop_initialized(size_t idx) const +{ + assert(idx < property_table_.size()); + return property_table_[idx].initialized_flag; +} + +void netclass_t::set_prop_initialized(size_t idx) const +{ + assert(idx < property_table_.size()); + assert(! property_table_[idx].initialized_flag); + property_table_[idx].initialized_flag = true; +} + +bool netclass_t::test_for_missing_initializers() const +{ + for (size_t idx = 0 ; idx < property_table_.size() ; idx += 1) { + if (property_table_[idx].initialized_flag) + continue; + if (property_table_[idx].qual.test_const()) + return true; + } + + return false; +} + NetScope*netclass_t::method_from_name(perm_string name) const { NetScope*task = class_scope_->child( hname_t(name) ); @@ -99,3 +121,21 @@ NetScope*netclass_t::method_from_name(perm_string name) const return task; } + +NetNet* netclass_t::find_static_property(perm_string name) const +{ + NetNet*tmp = class_scope_->find_signal(name); + return tmp; +} + +bool netclass_t::test_scope_is_method(const NetScope*scope) const +{ + while (scope && scope != class_scope_) { + scope = scope->parent(); + } + + if (scope == 0) + return false; + else + return true; +} diff --git a/netclass.h b/netclass.h index 30bd1d087..56039a56c 100644 --- a/netclass.h +++ b/netclass.h @@ -22,10 +22,12 @@ # include "LineInfo.h" # include "ivl_target.h" # include "nettypes.h" +# include "property_qual.h" # include # include class Design; +class NetNet; class NetScope; class PClass; @@ -37,7 +39,7 @@ class netclass_t : public ivl_type_s { // Set the property of the class during elaboration. Set the // name and type, and return true. If the name is already // present, then return false. - bool set_property(perm_string pname, ivl_type_s*ptype); + bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype); // Set the scope for the class. The scope has no parents and // is used for the elaboration of methods (tasks/functions). @@ -50,17 +52,37 @@ class netclass_t : public ivl_type_s { // This is the name of the class type inline perm_string get_name() const { return name_; } - const ivl_type_s* get_property(perm_string pname) const; - inline size_t get_properties(void) const { return properties_.size(); } + // Get information about each property. const char*get_prop_name(size_t idx) const; + property_qualifier_t get_prop_qual(size_t idx) const; ivl_type_t get_prop_type(size_t idx) const; + // These methods are used by the elaborator to note the + // initializer for constant properties. Properties start out + // as not initialized, and when elaboration detects an + // assignment to the property, it is marked initialized. + bool get_prop_initialized(size_t idx) const; + void set_prop_initialized(size_t idx) const; + + bool test_for_missing_initializers(void) const; + + // Map the name of a property to its index. int property_idx_from_name(perm_string pname) const; // The task method scopes from the method name. NetScope*method_from_name(perm_string mname) const; + // Find the elaborated signal (NetNet) for a static + // property. Search by name. The signal is created by the + // elaborate_sig pass. + NetNet*find_static_property(perm_string name) const; + + // Test if this scope is a method within the class. This is + // used to check scope for handling data protection keywords + // "local" and "protected". + bool test_scope_is_method(const NetScope*scope) const; + void elaborate_sig(Design*des, PClass*pclass); void elaborate(Design*des, PClass*pclass); @@ -75,7 +97,9 @@ class netclass_t : public ivl_type_s { // Vector of properties. struct prop_t { perm_string name; + property_qualifier_t qual; ivl_type_s* type; + mutable bool initialized_flag; }; std::vector property_table_; 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 70eb07bd3..a9230f221 100644 --- a/parse.y +++ b/parse.y @@ -581,7 +581,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector %type struct_data_type %type class_item_qualifier property_qualifier -%type property_qualifier_list property_qualifier_opt +%type class_item_qualifier_list property_qualifier_list +%type class_item_qualifier_opt property_qualifier_opt %type random_qualifier %type range range_opt variable_dimension @@ -673,7 +674,7 @@ class_declaration /* IEEE1800-2005: A.1.2 */ } class_items_opt K_endclass { // Process a class. - pform_end_class_declaration(); + pform_end_class_declaration(@8); } class_declaration_endlabel_opt { // Wrap up the class. @@ -695,6 +696,7 @@ class_identifier // lexor detects the name as a type. perm_string name = lex_strings.make($1); class_type_t*tmp = new class_type_t(name); + FILE_NAME(tmp, @1); pform_set_typedef(name, tmp); delete[]$1; $$ = tmp; @@ -769,7 +771,7 @@ class_item /* IEEE1800-2005: A.1.8 */ { current_function->set_ports($6); pform_set_constructor_return(current_function); pform_set_this_class(@3, current_function); - current_function_set_statement($10? @10 : @3, $10); + current_function_set_statement(@3, $10); pform_pop_scope(); current_function = 0; } @@ -793,6 +795,9 @@ class_item /* IEEE1800-2005: A.1.8 */ | property_qualifier_opt data_type list_of_variable_decl_assignments ';' { pform_class_property(@2, $1, $2, $3); } + | K_const class_item_qualifier_opt data_type list_of_variable_decl_assignments ';' + { pform_class_property(@1, $2 | property_qualifier_t::make_const(), $3, $4); } + /* Class methods... */ | method_qualifier_opt task_declaration @@ -832,9 +837,19 @@ class_item /* IEEE1800-2005: A.1.8 */ ; class_item_qualifier /* IEEE1800-2005 A.1.8 */ - : K_static { $$ = property_qualifier_t::set_static(); } - | K_protected { $$ = property_qualifier_t::set_protected(); } - | K_local { $$ = property_qualifier_t::set_local(); } + : K_static { $$ = property_qualifier_t::make_static(); } + | K_protected { $$ = property_qualifier_t::make_protected(); } + | K_local { $$ = property_qualifier_t::make_local(); } + ; + +class_item_qualifier_list + : class_item_qualifier_list class_item_qualifier { $$ = $1 | $2; } + | class_item_qualifier { $$ = $1; } + ; + +class_item_qualifier_opt + : class_item_qualifier_list { $$ = $1; } + | { $$ = property_qualifier_t::make_none(); } ; class_new /* IEEE1800-2005 A.2.4 */ @@ -1229,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; } ; @@ -1493,7 +1510,7 @@ property_qualifier /* IEEE1800-2005 A.1.8 */ property_qualifier_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */ : property_qualifier_list { $$ = $1; } - | { $$ = property_qualifier_t::set_none(); } + | { $$ = property_qualifier_t::make_none(); } ; property_qualifier_list /* IEEE1800-2005 A.1.8 */ @@ -1502,8 +1519,8 @@ property_qualifier_list /* IEEE1800-2005 A.1.8 */ ; random_qualifier /* IEEE1800-2005 A.1.8 */ - : K_rand { $$ = property_qualifier_t::set_rand(); } - | K_randc { $$ = property_qualifier_t::set_randc(); } + : K_rand { $$ = property_qualifier_t::make_rand(); } + | K_randc { $$ = property_qualifier_t::make_randc(); } ; /* real and realtime are exactly the same so save some code @@ -2056,6 +2073,7 @@ type_declaration // lexor detects the name as a type. perm_string name = lex_strings.make($3); class_type_t*tmp = new class_type_t(name); + FILE_NAME(tmp, @3); pform_set_typedef(name, tmp); delete[]$3; } @@ -2070,6 +2088,7 @@ type_declaration // lexor detects the name as a type. perm_string name = lex_strings.make($2); class_type_t*tmp = new class_type_t(name); + FILE_NAME(tmp, @2); pform_set_typedef(name, tmp); delete[]$2; } diff --git a/pform.h b/pform.h index e8c656fb8..a6f24e439 100644 --- a/pform.h +++ b/pform.h @@ -189,7 +189,7 @@ extern void pform_class_property(const struct vlltype&loc, extern void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net); extern void pform_set_constructor_return(PFunction*net); -extern void pform_end_class_declaration(void); +extern void pform_end_class_declaration(const struct vlltype&loc); extern void pform_make_udp(perm_string name, list*parms, std::vector*decl, list*table, diff --git a/pform_dump.cc b/pform_dump.cc index feb274697..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 @@ -177,13 +177,23 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "class " << name << " {"; - for (map::const_iterator cur = properties.begin() + for (map::const_iterator cur = properties.begin() ; cur != properties.end() ; ++cur) { out << " " << cur->first; } + out << " }" << endl; } +void class_type_t::pform_dump_init(ostream&out, unsigned indent) const +{ + for (vector::const_iterator cur = initialize.begin() + ; cur != initialize.end() ; ++cur) { + Statement*curp = *cur; + curp->dump(out,indent+4); + } +} + void struct_member_t::pform_dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << type; @@ -928,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 "; @@ -1315,6 +1332,7 @@ void PClass::dump(ostream&out, unsigned indent) const { out << setw(indent) << "" << "class " << type->name << ";" << endl; type->pform_dump(out, indent+2); + type->pform_dump_init(out, indent+2); dump_tasks_(out, indent+2); dump_funcs_(out, indent+2); out << setw(indent) << "" << "endclass" << endl; diff --git a/pform_pclass.cc b/pform_pclass.cc index f21479659..663da18a2 100644 --- a/pform_pclass.cc +++ b/pform_pclass.cc @@ -41,15 +41,6 @@ void pform_class_property(const struct vlltype&loc, { assert(pform_cur_class); - if (property_qual.test_static()) { - // I think the thing to do with static properties is to - // make them PWires directly in the PClass scope. They - // are wires like program/modules wires, and not - // instance members. - VLerror(loc, "sorry: static class properties not implemented."); - return; - } - // Add the non-static properties to the class type // object. Unwind the list of names to make a map of name to // type. @@ -64,11 +55,20 @@ void pform_class_property(const struct vlltype&loc, use_type = new uarray_type_t(use_type, pd); } - if (curp->expr.get()) { - VLerror(loc, "sorry: Initialization expressions for properties not implemented."); - } + pform_cur_class->type->properties[curp->name] + = class_type_t::prop_info_t(property_qual,use_type); - pform_cur_class->type->properties[curp->name] = use_type; + if (PExpr*rval = curp->expr.release()) { + PExpr*lval = new PEIdent(curp->name); + FILE_NAME(lval, loc); + PAssign*tmp = new PAssign(lval, rval); + FILE_NAME(tmp, loc); + + if (property_qual.test_static()) + pform_cur_class->type->initialize_static.push_back(tmp); + else + pform_cur_class->type->initialize.push_back(tmp); + } } } @@ -107,9 +107,29 @@ PFunction*pform_push_constructor_scope(const struct vlltype&loc) return func; } -void pform_end_class_declaration(void) +void pform_end_class_declaration(const struct vlltype&loc) { assert(pform_cur_class); + + // If there were initializer statements, then collect them + // into an implicit constructor function. + if (! pform_cur_class->type->initialize.empty()) { + PFunction*func = pform_push_function_scope(loc, "new@", true); + func->set_ports(0); + pform_set_constructor_return(func); + pform_set_this_class(loc, func); + + class_type_t*use_class = pform_cur_class->type; + if (use_class->initialize.size() == 1) { + func->set_statement(use_class->initialize.front()); + } else { + PBlock*tmp = new PBlock(PBlock::BL_SEQ); + tmp->set_statement(use_class->initialize); + func->set_statement(tmp); + } + pform_pop_scope(); + } + pform_cur_class = 0; pform_pop_scope(); } diff --git a/pform_types.h b/pform_types.h index e99b966fc..6598f7d26 100644 --- a/pform_types.h +++ b/pform_types.h @@ -24,9 +24,11 @@ # include "LineInfo.h" # include "verinum.h" # include "named.h" +# include "property_qual.h" # include "ivl_target.h" # include # include +# include # include # include @@ -37,6 +39,7 @@ class Design; class NetScope; class PExpr; +class Statement; class ivl_type_s; typedef named named_number_t; typedef named named_pexpr_t; @@ -212,45 +215,32 @@ struct class_type_t : public data_type_t { : name(n) { } void pform_dump(std::ostream&out, unsigned indent) const; + void pform_dump_init(std::ostream&out, unsigned indent) const; + // This is the name of the class type. perm_string name; - std::map properties; + // This is a map of the properties. Map the name to the type. + struct prop_info_t { + inline prop_info_t() : qual(property_qualifier_t::make_none()), type(0) { } + inline prop_info_t(property_qualifier_t q, data_type_t*t) : qual(q), type(t) { } + property_qualifier_t qual; + data_type_t* type; + }; + std::map properties; + + // This is an ordered list of property initializers. The name + // is the name of the property to be assigned, and the val is + // the expression that is assigned. + std::vector initialize; + + // This is an ordered list of property initializers for static + // properties. These are run in a synthetic "initial" block + // without waiting for any constructor. + std::vector initialize_static; ivl_type_s* elaborate_type(Design*, NetScope*) const; }; -class property_qualifier_t { - public: - static inline property_qualifier_t set_none() - { property_qualifier_t res; res.mask_ = 0; return res; } - - static inline property_qualifier_t set_static() - { property_qualifier_t res; res.mask_ = 1; return res; } - - static inline property_qualifier_t set_protected() - { property_qualifier_t res; res.mask_ = 2; return res; } - - static inline property_qualifier_t set_local() - { property_qualifier_t res; res.mask_ = 4; return res; } - - static inline property_qualifier_t set_rand() - { property_qualifier_t res; res.mask_ = 8; return res; } - - static inline property_qualifier_t set_randc() - { property_qualifier_t res; res.mask_ = 16; return res; } - - inline property_qualifier_t operator | (property_qualifier_t r) - { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } - - public: - inline bool test_static() const { return mask_ & 1; } - inline bool test_protected() const { return mask_ & 2; } - inline bool test_local() const { return mask_ & 4; } - - private: - int mask_; -}; - /* * The pform_name_t is the general form for a hierarchical * identifier. It is an ordered list of name components. Each name diff --git a/property_qual.h b/property_qual.h new file mode 100644 index 000000000..aaaa37b86 --- /dev/null +++ b/property_qual.h @@ -0,0 +1,60 @@ +#ifndef __property_qual_H +#define __property_qual_H +/* + * Copyright (c) 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. + */ + +class property_qualifier_t { + public: + static inline property_qualifier_t make_none() + { property_qualifier_t res; res.mask_ = 0; return res; } + + static inline property_qualifier_t make_static() + { property_qualifier_t res; res.mask_ = 1; return res; } + + static inline property_qualifier_t make_protected() + { property_qualifier_t res; res.mask_ = 2; return res; } + + static inline property_qualifier_t make_local() + { property_qualifier_t res; res.mask_ = 4; return res; } + + static inline property_qualifier_t make_rand() + { property_qualifier_t res; res.mask_ = 8; return res; } + + static inline property_qualifier_t make_randc() + { property_qualifier_t res; res.mask_ = 16; return res; } + + static inline property_qualifier_t make_const() + { property_qualifier_t res; res.mask_ = 32; return res; } + + inline property_qualifier_t operator | (property_qualifier_t r) + { property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; } + + public: + inline bool test_static() const { return mask_ & 1; } + inline bool test_protected() const { return mask_ & 2; } + inline bool test_local() const { return mask_ & 4; } + inline bool test_rand() const { return mask_ & 8; } + inline bool test_randc() const { return mask_ & 16; } + inline bool test_const() const { return mask_ & 32; } + + private: + int mask_; +}; + +#endif 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/tgt-vvp/stmt_assign.c b/tgt-vvp/stmt_assign.c index e98ec1d1f..c4eadd1b6 100644 --- a/tgt-vvp/stmt_assign.c +++ b/tgt-vvp/stmt_assign.c @@ -872,7 +872,23 @@ static int show_stmt_assign_sig_cobject(ivl_statement_t net) struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ); fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); - fprintf(vvp_out, " %%store/prop/v %d, %u, %u;\n", prop_idx, val.base, val.wid); + fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in bool property %s\n", + prop_idx, val.base, val.wid, + ivl_type_prop_name(sig_type, prop_idx)); + fprintf(vvp_out, " %%pop/obj 1;\n"); + clr_vector(val); + + } else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) { + assert(ivl_type_packed_dimensions(prop_type) == 1); + assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0)); + int wid = ivl_type_packed_msb(prop_type,0) - ivl_type_packed_lsb(prop_type,0) + 1; + + struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ); + + fprintf(vvp_out, " %%load/obj v%p_0;\n", sig); + fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in logic property %s\n", + prop_idx, val.base, val.wid, + ivl_type_prop_name(sig_type, prop_idx)); fprintf(vvp_out, " %%pop/obj 1;\n"); clr_vector(val); 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_; } diff --git a/vvp/class_type.cc b/vvp/class_type.cc index 5b6791eb0..38768aa03 100644 --- a/vvp/class_type.cc +++ b/vvp/class_type.cc @@ -141,6 +141,56 @@ template class property_atom : public class_property_t { void copy(char*dst, char*src); }; +class property_bit : public class_property_t { + public: + inline property_bit(size_t wid): wid_(wid) { } + ~property_bit() { } + + size_t instance_size() const { return sizeof(vvp_vector2_t); } + + public: + void construct(char*buf) const + { new (buf+offset_) vvp_vector2_t (0, wid_); } + + void destruct(char*buf) const + { vvp_vector2_t*tmp = reinterpret_cast(buf+offset_); + tmp->~vvp_vector2_t(); + } + + void set_vec4(char*buf, const vvp_vector4_t&val); + void get_vec4(char*buf, vvp_vector4_t&val); + + void copy(char*dst, char*src); + + private: + size_t wid_; +}; + +class property_logic : public class_property_t { + public: + inline property_logic(size_t wid): wid_(wid) { } + ~property_logic() { } + + size_t instance_size() const { return sizeof(vvp_vector4_t); } + + public: + void construct(char*buf) const + { new (buf+offset_) vvp_vector4_t (0, wid_); } + + void destruct(char*buf) const + { vvp_vector4_t*tmp = reinterpret_cast(buf+offset_); + tmp->~vvp_vector4_t(); + } + + void set_vec4(char*buf, const vvp_vector4_t&val); + void get_vec4(char*buf, vvp_vector4_t&val); + + void copy(char*dst, char*src); + + private: + size_t wid_; +}; + template class property_real : public class_property_t { public: inline explicit property_real(void) { } @@ -234,6 +284,44 @@ template void property_atom::copy(char*dst, char*src) *dst_obj = *src_obj; } +void property_bit::set_vec4(char*buf, const vvp_vector4_t&val) +{ + vvp_vector2_t*obj = reinterpret_cast (buf+offset_); + *obj = val; +} + +void property_bit::get_vec4(char*buf, vvp_vector4_t&val) +{ + vvp_vector2_t*obj = reinterpret_cast (buf+offset_); + val = vector2_to_vector4(*obj, obj->size()); +} + +void property_bit::copy(char*dst, char*src) +{ + vvp_vector2_t*dst_obj = reinterpret_cast (dst+offset_); + vvp_vector2_t*src_obj = reinterpret_cast (src+offset_); + *dst_obj = *src_obj; +} + +void property_logic::set_vec4(char*buf, const vvp_vector4_t&val) +{ + vvp_vector4_t*obj = reinterpret_cast (buf+offset_); + *obj = val; +} + +void property_logic::get_vec4(char*buf, vvp_vector4_t&val) +{ + vvp_vector4_t*obj = reinterpret_cast (buf+offset_); + val = *obj; +} + +void property_logic::copy(char*dst, char*src) +{ + vvp_vector4_t*dst_obj = reinterpret_cast (dst+offset_); + vvp_vector4_t*src_obj = reinterpret_cast (src+offset_); + *dst_obj = *src_obj; +} + template void property_real::set_real(char*buf, double val) { T*tmp = reinterpret_cast(buf+offset_); @@ -326,8 +414,15 @@ void class_type::set_property(size_t idx, const string&name, const string&type) properties_[idx].type = new property_string; else if (type == "o") properties_[idx].type = new property_object; - else + else if (type[0] == 'b') { + size_t wid = strtoul(type.c_str()+1, 0, 0); + properties_[idx].type = new property_bit(wid); + } else if (type[0] == 'L') { + size_t wid = strtoul(type.c_str()+1,0,0); + properties_[idx].type = new property_logic(wid); + } else { properties_[idx].type = 0; + } } void class_type::finish_setup(void)