Merge branch 'master' of github.com:steveicarus/iverilog

This commit is contained in:
Cary R 2013-07-04 11:30:02 -07:00
commit e736c022b1
61 changed files with 2175 additions and 382 deletions

View File

@ -387,9 +387,9 @@ class PEIdent : public PExpr {
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*, bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
index_component_t::ctype_t, index_component_t::ctype_t,
bool need_const_idx) const; bool need_const_idx) const;
bool elaborate_lval_net_class_member_(Design*, NetScope*, NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*,
NetAssign_*, NetNet*,
const perm_string&) const; const perm_string&) const;
bool elaborate_lval_net_packed_member_(Design*, NetScope*, bool elaborate_lval_net_packed_member_(Design*, NetScope*,
NetAssign_*, NetAssign_*,
const perm_string&) const; const perm_string&) const;

View File

@ -110,6 +110,8 @@ class PFunction : public PTaskFunc {
void set_statement(Statement *s); void set_statement(Statement *s);
void set_return(const data_type_t*t); void set_return(const data_type_t*t);
inline Statement* get_statement() { return statement_; }
void elaborate_scope(Design*des, NetScope*scope) const; void elaborate_scope(Design*des, NetScope*scope) const;
/* elaborate the ports and return value. */ /* elaborate the ports and return value. */

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -21,6 +21,7 @@
# include "Statement.h" # include "Statement.h"
# include "PExpr.h" # include "PExpr.h"
# include "ivl_assert.h"
Statement::~Statement() Statement::~Statement()
{ {
@ -126,6 +127,17 @@ void PBlock::set_statement(const vector<Statement*>&st)
list_ = 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<PExpr*>&p) PCallTask::PCallTask(const pform_name_t&n, const list<PExpr*>&p)
: package_(0), path_(n), parms_(p.size()) : package_(0), path_(n), parms_(p.size())
{ {
@ -329,6 +341,16 @@ PRepeat::~PRepeat()
delete statement_; delete statement_;
} }
PReturn::PReturn(PExpr*e)
: expr_(e)
{
}
PReturn::~PReturn()
{
delete expr_;
}
PTrigger::PTrigger(const pform_name_t&e) PTrigger::PTrigger(const pform_name_t&e)
: event_(e) : event_(e)
{ {

View File

@ -186,6 +186,10 @@ class PBlock : public PScope, public Statement {
void set_statement(const std::vector<Statement*>&st); void set_statement(const std::vector<Statement*>&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 void dump(ostream&out, unsigned ind) const;
virtual NetProc* elaborate(Design*des, NetScope*scope) const; virtual NetProc* elaborate(Design*des, NetScope*scope) const;
virtual void elaborate_scope(Design*des, NetScope*scope) const; virtual void elaborate_scope(Design*des, NetScope*scope) const;
@ -462,6 +466,19 @@ class PRelease : public Statement {
PExpr*lval_; 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 * The PTrigger statement sends a trigger to a named event. Take the
* name here. * name here.

View File

@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
{ {
perm_string name = peek_tail_name(path_); 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") { if (name=="$signed" || name=="$unsigned") {
PExpr*expr = parms_[0]; PExpr*expr = parms_[0];
if (expr == 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(); 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_path = tmp_path;
use_darray = dynamic_cast<const netdarray_t*> (member_type); use_darray = dynamic_cast<const netdarray_t*> (member_type);
@ -1228,6 +1261,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
{ {
perm_string name = peek_tail_name(path_); 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 /* Catch the special case that the system function is the $signed
function. Its argument will be evaluated as a self-determined function. Its argument will be evaluated as a self-determined
expression. */ expression. */
@ -1755,15 +1801,25 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
return sel; 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, static NetExpr* check_for_class_property(const LineInfo*li,
Design*des, NetScope*, Design*des, NetScope*scope,
NetNet*net, NetNet*net,
const name_component_t&comp) const name_component_t&comp)
{ {
const netclass_t*class_type = net->class_type(); const netclass_t*class_type = net->class_type();
const ivl_type_s*ptype = class_type->get_property(comp.name); int pidx = class_type->property_idx_from_name(comp.name);
if (pidx < 0) {
if (ptype == 0) {
cerr << li->get_fileline() << ": error: " cerr << li->get_fileline() << ": error: "
<< "Class " << class_type->get_name() << "Class " << class_type->get_name()
<< " has no property " << comp.name << "." << endl; << " has no property " << comp.name << "." << endl;
@ -1771,6 +1827,29 @@ static NetExpr* check_for_class_property(const LineInfo*li,
return 0; 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); NetEProperty*tmp = new NetEProperty(net, comp.name);
tmp->set_line(*li); tmp->set_line(*li);
return tmp; return tmp;
@ -1881,6 +1960,23 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds
bool need_const = NEED_CONST & flags; 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(); unsigned parms_count = parms_.size();
if ((parms_count == 1) && (parms_[0] == 0)) if ((parms_count == 1) && (parms_[0] == 0))
parms_count = 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); perm_string method_name = peek_tail_name(use_path);
use_path.pop_back(); 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; NetNet *net = 0;
const NetExpr *par; const NetExpr *par;
NetEvent *eve; 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()) { if (const netclass_t*class_type = net->class_type()) {
const ivl_type_s*ptype = class_type->get_property(method_name); int pidx = class_type->property_idx_from_name(method_name);
if (ptype) { if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
expr_type_ = ptype->base_type(); expr_type_ = ptype->base_type();
expr_width_ = ptype->packed_width(); expr_width_ = ptype->packed_width();
min_width_ = expr_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 * not a method, or the name is not in the parent class, then
* fail. Otherwise, return a NetEProperty. * 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 unsigned, unsigned) const
{ {
if (!gn_system_verilog()) 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: " cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: "
<< "Found member " << member_name << "Found member " << member_name
<< " is a member of class " << class_type->get_name() << " is a member of class " << class_type->get_name()
<< ", context scope=" << scope_path(scope)
<< ", so synthesizing a NetEProperty." << endl; << ", 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); NetEProperty*tmp = new NetEProperty(this_net, member_name);
tmp->set_line(*this); tmp->set_line(*this);
return tmp; return tmp;
@ -4464,13 +4581,35 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&)
NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope, NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope,
ivl_type_t ntype, unsigned) const ivl_type_t ntype, unsigned) const
{ {
NetENew*obj = new NetENew(ntype); NetExpr*obj = new NetENew(ntype);
obj->set_line(*this); obj->set_line(*this);
// Find the constructor for the class. If there is no // Find the constructor for the class. If there is no
// constructor then the result of this expression is the // constructor then the result of this expression is the
// allocation alone. // allocation alone.
const netclass_t*ctype = dynamic_cast<const netclass_t*> (ntype); const netclass_t*ctype = dynamic_cast<const netclass_t*> (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<NetExpr*> 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")); NetScope*new_scope = ctype->method_from_name(perm_string::literal("new"));
if (new_scope == 0) { if (new_scope == 0) {
// No constructor. // No constructor.

View File

@ -256,8 +256,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
} }
if (reg->class_type() && !method_name.nil() && gn_system_verilog()) { if (reg->class_type() && !method_name.nil() && gn_system_verilog()) {
NetAssign_*lv = new NetAssign_(reg); NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, method_name);
elaborate_lval_net_class_member_(des, use_scope, lv, method_name);
return lv; return lv;
} }
@ -316,7 +315,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return lv; return lv;
} }
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*, NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
NetScope*scope) const NetScope*scope) const
{ {
if (!gn_system_verilog()) if (!gn_system_verilog())
@ -343,6 +342,40 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
return 0; 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); NetAssign_*this_lval = new NetAssign_(this_net);
this_lval->set_property(member_name); this_lval->set_property(member_name);
@ -812,31 +845,58 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
return true; return true;
} }
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*, NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
NetAssign_*lv, NetNet*sig, const perm_string&method_name) const
const perm_string&method_name) const
{ {
if (debug_elaborate) { if (debug_elaborate) {
cerr << get_fileline() << ": elaborate_lval_net_class_member_: " cerr << get_fileline() << ": elaborate_lval_net_class_member_: "
<< "l-value is property " << method_name << "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); ivl_assert(*this, class_type);
/* Make sure the property is really present in the class. If /* Make sure the property is really present in the class. If
not, then generate an error message and return an error. */ not, then generate an error message and return an error. */
ivl_type_t ptype = class_type->get_property(method_name); int pidx = class_type->property_idx_from_name(method_name);
if (ptype == 0) { if (pidx < 0) {
cerr << get_fileline() << ": error: Class " << class_type->get_name() cerr << get_fileline() << ": error: Class " << class_type->get_name()
<< " does not have a property " << method_name << "." << endl; << " does not have a property " << method_name << "." << endl;
des->errors += 1; 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); lv->set_property(method_name);
ivl_type_t ptype = class_type->get_prop_type(pidx);
const netdarray_t*mtype = dynamic_cast<const netdarray_t*> (ptype); const netdarray_t*mtype = dynamic_cast<const netdarray_t*> (ptype);
if (mtype) { if (mtype) {
const name_component_t&name_tail = path_.back(); 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;
} }

View File

@ -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<perm_string,PFunction*>::iterator iter_new = pclass->funcs.find(new1);
if (iter_new == pclass->funcs.end())
return;
map<perm_string,PFunction*>::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<PBlock*> (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; class_type_t*use_type = pclass->type;
netclass_t*use_class = new netclass_t(use_type->name); 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 // Collect the properties, elaborate them, and add them to the
// elaborated class definition. // elaborated class definition.
for (map<perm_string, data_type_t*>::iterator cur = use_type->properties.begin() for (map<perm_string, class_type_t::prop_info_t>::iterator cur = use_type->properties.begin()
; cur != use_type->properties.end() ; ++ cur) { ; cur != use_type->properties.end() ; ++ cur) {
if (debug_scopes) { if (debug_scopes) {
cerr << pclass->get_fileline() << ": elaborate_scope_class: " cerr << pclass->get_fileline() << ": elaborate_scope_class: "
<< " Property " << cur->first << endl; << " 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); ivl_assert(*pclass, tmp);
use_class->set_property(cur->first, tmp); use_class->set_property(cur->first, cur->second.qual, tmp);
} }
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin() for (map<perm_string,PTask*>::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, static void elaborate_scope_classes(Design*des, NetScope*scope,
const vector<PClass*>&classes) const vector<PClass*>&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]); elaborate_scope_class(des, scope, classes[idx]);
}
} }
static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc, static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc,

View File

@ -314,6 +314,25 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
void netclass_t::elaborate_sig(Design*des, PClass*pclass) void netclass_t::elaborate_sig(Design*des, PClass*pclass)
{ {
for (map<perm_string,struct class_type_t::prop_info_t>::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<netrange_t> 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<perm_string,PFunction*>::iterator cur = pclass->funcs.begin() for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
; cur != pclass->funcs.end() ; ++ cur) { ; cur != pclass->funcs.end() ; ++ cur) {
if (debug_elaborate) { if (debug_elaborate) {
@ -538,7 +557,7 @@ void PFunction::elaborate_sig(Design*des, NetScope*scope) const
elaborate_sig_wires_(des, scope); elaborate_sig_wires_(des, scope);
NetNet*ret_sig; 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 // Special case: this is a constructor, so the return
// signal is also the first argument. For example, the // signal is also the first argument. For example, the
// source code for the definition may be: // source code for the definition may be:
@ -964,6 +983,10 @@ NetNet* PWire::elaborate_sig(Design*des, NetScope*scope) const
vector<netrange_t> plist, nlist; vector<netrange_t> plist, nlist;
/* If they exist get the port definition MSB and LSB */ /* If they exist get the port definition MSB and LSB */
if (port_set_ && !port_.empty()) { 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_); bad_range |= evaluate_ranges(des, scope, plist, port_);
nlist = plist; nlist = plist;
/* An implicit port can have a range so note that here. */ /* 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 they exist get the net/etc. definition MSB and LSB */
if (net_set_ && !net_.empty() && !bad_range) { if (net_set_ && !net_.empty() && !bad_range) {
nlist.clear(); 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_); bad_range |= evaluate_ranges(des, scope, nlist, net_);
} }
assert(net_set_ || net_.empty()); 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 we find errors here, then give up on this signal. */
if (bad_range) if (bad_range)
return 0; return 0;

View File

@ -2361,11 +2361,17 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
return cur; 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) static bool lval_not_program_variable(const NetAssign_*lv)
{ {
while (lv) { while (lv) {
NetScope*sig_scope = lv->sig()->scope(); NetScope*sig_scope = lv->sig()->scope();
if (! sig_scope->program_block()) if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS)
return true; return true;
lv = lv->more; lv = lv->more;
@ -2793,14 +2799,6 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
if (nscope->calls_sys_task()) if (nscope->calls_sys_task())
scope->calls_sys_task(true); 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); cur->set_line(*this);
return cur; return cur;
} }
@ -4445,6 +4443,69 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
return proc; 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 * A task definition is elaborated by elaborating the statement that
* it contains, and connecting its ports to NetNet objects. The * 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) { ; cur != classes.end() ; ++ cur) {
netclass_t*use_class = scope->find_class(cur->second->pscope_name()); netclass_t*use_class = scope->find_class(cur->second->pscope_name());
use_class->elaborate(des, cur->second); 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) void netclass_t::elaborate(Design*des, PClass*pclass)
{ {
if (! pclass->type->initialize_static.empty()) {
std::vector<Statement*>&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<perm_string,PFunction*>::iterator cur = pclass->funcs.begin() for (map<perm_string,PFunction*>::iterator cur = pclass->funcs.begin()
; cur != pclass->funcs.end() ; ++ cur) { ; cur != pclass->funcs.end() ; ++ cur) {
if (debug_elaborate) { if (debug_elaborate) {

View File

@ -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) if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(re, le, true); return eval_leeq_real_(re, le, true);
const NetEConst*l = dynamic_cast<const NetEConst*>(left_); const NetEConst*l = dynamic_cast<const NetEConst*>(le);
if (l == 0) return 0; if (l == 0) return 0;
verinum lv = l->value(); verinum lv = l->value();

View File

@ -367,6 +367,13 @@ TU [munpf]
\\[^ \t\b\f\r\n]+ { \\[^ \t\b\f\r\n]+ {
yylval.text = strdupnew(yytext+1); 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 (gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylval.text)) { if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
delete[]yylval.text; delete[]yylval.text;

View File

@ -96,9 +96,9 @@ unsigned NetAssign_::lwidth() const
if (member_.nil()) if (member_.nil())
return 1; return 1;
const ivl_type_s*ptype = class_type->get_property(member_); int pidx = class_type->property_idx_from_name(member_);
ivl_assert(*sig_, ptype); ivl_assert(*sig_, pidx >= 0);
ivl_type_t ptype = class_type->get_prop_type(pidx);
return ptype->packed_width(); return ptype->packed_width();
} }
@ -118,7 +118,9 @@ ivl_variable_type_t NetAssign_::expr_type() const
if (member_.nil()) if (member_.nil())
return sig_->data_type(); 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(); return tmp->base_type();
} }
@ -138,8 +140,9 @@ const ivl_type_s* NetAssign_::net_type() const
if (member_.nil()) if (member_.nil())
return sig_->net_type(); return sig_->net_type();
const ivl_type_s*tmp = class_type->get_property(member_); int pidx = class_type->property_idx_from_name(member_);
ivl_assert(*sig_, tmp); ivl_assert(*sig_, pidx >= 0);
ivl_type_t tmp = class_type->get_prop_type(pidx);
return tmp; return tmp;
} }

View File

@ -60,7 +60,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
map<perm_string,LocalVar>context_map; map<perm_string,LocalVar>context_map;
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << loc.get_fileline() << ": debug: " cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "Evaluate function " << scope_->basename() << endl; << "Evaluate function " << scope_->basename() << endl;
} }
@ -78,7 +78,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
input_var.value = fix_assign_value(ports_[idx], args[idx]); input_var.value = fix_assign_value(ports_[idx], args[idx]);
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << loc.get_fileline() << ": debug: " cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< " input " << aname << " = " << *args[idx] << endl; << " input " << aname << " = " << *args[idx] << endl;
} }
} }
@ -87,11 +87,22 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
// fills in the context_map with local variables held by the scope. // fills in the context_map with local variables held by the scope.
scope_->evaluate_function_find_locals(loc, context_map); scope_->evaluate_function_find_locals(loc, context_map);
if (debug_eval_tree && statement_==0) {
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "Function " << scope_path(scope_)
<< " has no statement?" << endl;
}
// Perform the evaluation. Note that if there were errors // Perform the evaluation. Note that if there were errors
// when compiling the function definition, we may not have // when compiling the function definition, we may not have
// a valid statement. // a valid statement.
bool flag = statement_ && statement_->evaluate_function(loc, context_map); bool flag = statement_ && statement_->evaluate_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... // Extract the result...
ptr = context_map.find(scope_->basename()); ptr = context_map.find(scope_->basename());
NetExpr*res = ptr->second.value; NetExpr*res = ptr->second.value;
@ -112,9 +123,32 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
} }
} }
if (disable) {
if (debug_eval_tree)
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "disable of " << scope_path(disable)
<< " trapped in function " << scope_path(scope_)
<< "." << endl;
ivl_assert(loc, disable==scope_);
disable = 0;
}
// Done. // Done.
if (flag) if (flag) {
if (debug_eval_tree) {
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "Evalutated to ";
if (res) cerr << *res;
else cerr << "<nil>";
cerr << endl;
}
return res; return res;
}
if (debug_eval_tree) {
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "Evaluation failed." << endl;
}
delete res; delete res;
return 0; return 0;
@ -181,9 +215,15 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
map<perm_string,LocalVar>::iterator ptr = context_map.find(lval->name()); map<perm_string,LocalVar>::iterator ptr = context_map.find(lval->name());
ivl_assert(*this, ptr != context_map.end()); ivl_assert(*this, ptr != context_map.end());
LocalVar*var = & ptr->second;
while (var->nwords == -1) {
assert(var->ref);
var = var->ref;
}
NetExpr*old_lval; NetExpr*old_lval;
unsigned word = 0; int word = 0;
if (ptr->second.nwords > 0) { if (var->nwords > 0) {
NetExpr*word_result = lval->word()->evaluate_function(loc, context_map); NetExpr*word_result = lval->word()->evaluate_function(loc, context_map);
if (word_result == 0) { if (word_result == 0) {
delete rval_result; delete rval_result;
@ -198,12 +238,13 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
word = word_const->value().as_long(); word = word_const->value().as_long();
if (word >= ptr->second.nwords) if (word >= var->nwords)
return true; return true;
old_lval = ptr->second.array[word]; old_lval = var->array[word];
} else { } else {
old_lval = ptr->second.value; assert(var->nwords == 0);
old_lval = var->value;
} }
if (const NetExpr*base_expr = lval->get_base()) { if (const NetExpr*base_expr = lval->get_base()) {
@ -245,15 +286,16 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
delete old_lval; delete old_lval;
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: " cerr << get_fileline() << ": NetAssign::evaluate_function: "
<< "NetAssign::evaluate_function: " << lval->name() << lval->name() << " = " << *rval_result << endl;
<< " = " << *rval_result << endl;
} }
if (ptr->second.nwords > 0) if (var->nwords > 0) {
ptr->second.array[word] = rval_result; var->array[word] = rval_result;
else } else {
ptr->second.value = rval_result; assert(var->nwords == 0);
var->value = rval_result;
}
return true; return true;
} }
@ -303,16 +345,56 @@ bool NetAssign::evaluate_function(const LineInfo&loc,
bool NetBlock::evaluate_function(const LineInfo&loc, bool NetBlock::evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&context_map) const map<perm_string,LocalVar>&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.
map<perm_string,LocalVar>local_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<perm_string,LocalVar>::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<perm_string,LocalVar>&use_context_map = use_local_context_map? local_context_map : context_map;
bool flag = true; bool flag = true;
NetProc*cur = last_; NetProc*cur = last_;
if (cur == 0) return true;
do { do {
cur = cur->next_; 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; flag = flag && cur_flag;
} while (cur != last_ && !disable); } 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; if (disable == subscope_) disable = 0;
return flag; return flag;
@ -437,8 +519,13 @@ bool NetCondit::evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&context_map) const map<perm_string,LocalVar>&context_map) const
{ {
NetExpr*cond = expr_->evaluate_function(loc, context_map); 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; return false;
}
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond); NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
ivl_assert(loc, cond_const); ivl_assert(loc, cond_const);
@ -446,18 +533,32 @@ bool NetCondit::evaluate_function(const LineInfo&loc,
long val = cond_const->value().as_long(); long val = cond_const->value().as_long();
delete cond; delete cond;
bool flag;
if (val) if (val)
// The condition is true, so evaluate the if clause // 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 else
// The condition is false, so evaluate the else clause // 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&, bool NetDisable::evaluate_function(const LineInfo&,
map<perm_string,LocalVar>&) const map<perm_string,LocalVar>&) const
{ {
disable = target_; disable = target_;
if (debug_eval_tree) {
cerr << get_fileline() << ": NetDisable::evaluate_function: "
<< "disable " << scope_path(disable) << endl;
}
return true; return true;
} }
@ -530,7 +631,7 @@ bool NetWhile::evaluate_function(const LineInfo&loc,
bool flag = true; bool flag = true;
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " cerr << get_fileline() << ": NetWhile::evaluate_function: "
<< "Start loop" << endl; << "Start loop" << endl;
} }
@ -561,8 +662,8 @@ bool NetWhile::evaluate_function(const LineInfo&loc,
} }
if (debug_eval_tree) { if (debug_eval_tree) {
cerr << get_fileline() << ": debug: NetWhile::evaluate_function: " cerr << get_fileline() << ": NetWhile::evaluate_function: "
<< "Done loop" << endl; << "Done loop, flag=" << (flag?"true":"false") << endl;
} }
return flag; return flag;
@ -674,8 +775,15 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
return 0; 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; NetExpr*value = 0;
if (ptr->second.nwords > 0) { if (var->nwords > 0) {
ivl_assert(loc, word_); ivl_assert(loc, word_);
NetExpr*word_result = word_->evaluate_function(loc, context_map); NetExpr*word_result = word_->evaluate_function(loc, context_map);
if (word_result == 0) if (word_result == 0)
@ -684,12 +792,12 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
NetEConst*word_const = dynamic_cast<NetEConst*>(word_result); NetEConst*word_const = dynamic_cast<NetEConst*>(word_result);
ivl_assert(loc, word_const); 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)) if (word_const->value().is_defined() && (word < var->nwords))
value = ptr->second.array[word]; value = var->array[word];
} else { } else {
value = ptr->second.value; value = var->value;
} }
if (value == 0) { if (value == 0) {

View File

@ -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<perm_string,size_t>::const_iterator cur; map<perm_string,size_t>::const_iterator cur;
cur = properties_.find(pname); cur = properties_.find(pname);
@ -41,7 +41,9 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype)
prop_t tmp; prop_t tmp;
tmp.name = pname; tmp.name = pname;
tmp.qual = qual;
tmp.type = ptype; tmp.type = ptype;
tmp.initialized_flag = false;
property_table_.push_back(tmp); property_table_.push_back(tmp);
properties_[pname] = property_table_.size()-1; properties_[pname] = property_table_.size()-1;
@ -59,17 +61,6 @@ ivl_variable_type_t netclass_t::base_type() const
return IVL_VT_CLASS; return IVL_VT_CLASS;
} }
const ivl_type_s* netclass_t::get_property(perm_string pname) const
{
map<perm_string,size_t>::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 int netclass_t::property_idx_from_name(perm_string pname) const
{ {
map<perm_string,size_t>::const_iterator cur; map<perm_string,size_t>::const_iterator cur;
@ -86,12 +77,43 @@ const char*netclass_t::get_prop_name(size_t idx) const
return property_table_[idx].name; 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 ivl_type_t netclass_t::get_prop_type(size_t idx) const
{ {
assert(idx < property_table_.size()); assert(idx < property_table_.size());
return property_table_[idx].type; 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*netclass_t::method_from_name(perm_string name) const
{ {
NetScope*task = class_scope_->child( hname_t(name) ); NetScope*task = class_scope_->child( hname_t(name) );
@ -99,3 +121,21 @@ NetScope*netclass_t::method_from_name(perm_string name) const
return task; 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;
}

View File

@ -22,10 +22,12 @@
# include "LineInfo.h" # include "LineInfo.h"
# include "ivl_target.h" # include "ivl_target.h"
# include "nettypes.h" # include "nettypes.h"
# include "property_qual.h"
# include <iostream> # include <iostream>
# include <map> # include <map>
class Design; class Design;
class NetNet;
class NetScope; class NetScope;
class PClass; class PClass;
@ -37,7 +39,7 @@ class netclass_t : public ivl_type_s {
// Set the property of the class during elaboration. Set the // Set the property of the class during elaboration. Set the
// name and type, and return true. If the name is already // name and type, and return true. If the name is already
// present, then return false. // 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 // Set the scope for the class. The scope has no parents and
// is used for the elaboration of methods (tasks/functions). // 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 // This is the name of the class type
inline perm_string get_name() const { return name_; } 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(); } inline size_t get_properties(void) const { return properties_.size(); }
// Get information about each property.
const char*get_prop_name(size_t idx) const; 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; 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; int property_idx_from_name(perm_string pname) const;
// The task method scopes from the method name. // The task method scopes from the method name.
NetScope*method_from_name(perm_string mname) const; 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_sig(Design*des, PClass*pclass);
void elaborate(Design*des, PClass*pclass); void elaborate(Design*des, PClass*pclass);
@ -75,7 +97,9 @@ class netclass_t : public ivl_type_s {
// Vector of properties. // Vector of properties.
struct prop_t { struct prop_t {
perm_string name; perm_string name;
property_qualifier_t qual;
ivl_type_s* type; ivl_type_s* type;
mutable bool initialized_flag;
}; };
std::vector<prop_t> property_table_; std::vector<prop_t> property_table_;

View File

@ -760,10 +760,11 @@ class NetNet : public NetObj, public PortType {
* evaluating constant user functions. * evaluating constant user functions.
*/ */
struct LocalVar { struct LocalVar {
unsigned nwords; // zero for a simple variable int nwords; // zero for a simple variable, -1 for reference
union { union {
NetExpr* value; // a simple variable NetExpr* value; // a simple variable
NetExpr** array; // an array variable NetExpr** array; // an array variable
LocalVar* ref; // A reference to a previous scope
}; };
}; };

45
parse.y
View File

@ -581,7 +581,8 @@ static void current_function_set_statement(const YYLTYPE&loc, vector<Statement*>
%type <struct_type> struct_data_type %type <struct_type> struct_data_type
%type <property_qualifier> class_item_qualifier property_qualifier %type <property_qualifier> class_item_qualifier property_qualifier
%type <property_qualifier> property_qualifier_list property_qualifier_opt %type <property_qualifier> class_item_qualifier_list property_qualifier_list
%type <property_qualifier> class_item_qualifier_opt property_qualifier_opt
%type <property_qualifier> random_qualifier %type <property_qualifier> random_qualifier
%type <ranges> range range_opt variable_dimension %type <ranges> range range_opt variable_dimension
@ -673,7 +674,7 @@ class_declaration /* IEEE1800-2005: A.1.2 */
} }
class_items_opt K_endclass class_items_opt K_endclass
{ // Process a class. { // Process a class.
pform_end_class_declaration(); pform_end_class_declaration(@8);
} }
class_declaration_endlabel_opt class_declaration_endlabel_opt
{ // Wrap up the class. { // Wrap up the class.
@ -695,6 +696,7 @@ class_identifier
// lexor detects the name as a type. // lexor detects the name as a type.
perm_string name = lex_strings.make($1); perm_string name = lex_strings.make($1);
class_type_t*tmp = new class_type_t(name); class_type_t*tmp = new class_type_t(name);
FILE_NAME(tmp, @1);
pform_set_typedef(name, tmp); pform_set_typedef(name, tmp);
delete[]$1; delete[]$1;
$$ = tmp; $$ = tmp;
@ -769,7 +771,7 @@ class_item /* IEEE1800-2005: A.1.8 */
{ current_function->set_ports($6); { current_function->set_ports($6);
pform_set_constructor_return(current_function); pform_set_constructor_return(current_function);
pform_set_this_class(@3, 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(); pform_pop_scope();
current_function = 0; current_function = 0;
} }
@ -793,6 +795,9 @@ class_item /* IEEE1800-2005: A.1.8 */
| property_qualifier_opt data_type list_of_variable_decl_assignments ';' | property_qualifier_opt data_type list_of_variable_decl_assignments ';'
{ pform_class_property(@2, $1, $2, $3); } { 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... */ /* Class methods... */
| method_qualifier_opt task_declaration | method_qualifier_opt task_declaration
@ -832,9 +837,19 @@ class_item /* IEEE1800-2005: A.1.8 */
; ;
class_item_qualifier /* IEEE1800-2005 A.1.8 */ class_item_qualifier /* IEEE1800-2005 A.1.8 */
: K_static { $$ = property_qualifier_t::set_static(); } : K_static { $$ = property_qualifier_t::make_static(); }
| K_protected { $$ = property_qualifier_t::set_protected(); } | K_protected { $$ = property_qualifier_t::make_protected(); }
| K_local { $$ = property_qualifier_t::set_local(); } | 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 */ class_new /* IEEE1800-2005 A.2.4 */
@ -1229,12 +1244,14 @@ jump_statement /* IEEE1800-2005: A.6.5 */
$$ = 0; $$ = 0;
} }
| K_return ';' | K_return ';'
{ yyerror(@1, "sorry: return statements not supported."); { PReturn*tmp = new PReturn(0);
$$ = 0; FILE_NAME(tmp, @1);
$$ = tmp;
} }
| K_return expression ';' | K_return expression ';'
{ yyerror(@1, "sorry: return statements not supported."); { PReturn*tmp = new PReturn($2);
$$ = 0; 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_opt /* IEEE1800-2005 A.1.8: ... { property_qualifier } */
: property_qualifier_list { $$ = $1; } : property_qualifier_list { $$ = $1; }
| { $$ = property_qualifier_t::set_none(); } | { $$ = property_qualifier_t::make_none(); }
; ;
property_qualifier_list /* IEEE1800-2005 A.1.8 */ 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 */ random_qualifier /* IEEE1800-2005 A.1.8 */
: K_rand { $$ = property_qualifier_t::set_rand(); } : K_rand { $$ = property_qualifier_t::make_rand(); }
| K_randc { $$ = property_qualifier_t::set_randc(); } | K_randc { $$ = property_qualifier_t::make_randc(); }
; ;
/* real and realtime are exactly the same so save some code /* real and realtime are exactly the same so save some code
@ -2056,6 +2073,7 @@ type_declaration
// lexor detects the name as a type. // lexor detects the name as a type.
perm_string name = lex_strings.make($3); perm_string name = lex_strings.make($3);
class_type_t*tmp = new class_type_t(name); class_type_t*tmp = new class_type_t(name);
FILE_NAME(tmp, @3);
pform_set_typedef(name, tmp); pform_set_typedef(name, tmp);
delete[]$3; delete[]$3;
} }
@ -2070,6 +2088,7 @@ type_declaration
// lexor detects the name as a type. // lexor detects the name as a type.
perm_string name = lex_strings.make($2); perm_string name = lex_strings.make($2);
class_type_t*tmp = new class_type_t(name); class_type_t*tmp = new class_type_t(name);
FILE_NAME(tmp, @2);
pform_set_typedef(name, tmp); pform_set_typedef(name, tmp);
delete[]$2; delete[]$2;
} }

View File

@ -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_this_class(const struct vlltype&loc, PTaskFunc*net);
extern void pform_set_constructor_return(PFunction*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<perm_string>*parms, extern void pform_make_udp(perm_string name, list<perm_string>*parms,
std::vector<PWire*>*decl, list<string>*table, std::vector<PWire*>*decl, list<string>*table,

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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 << " {"; out << setw(indent) << "" << "class " << name << " {";
for (map<perm_string,data_type_t*>::const_iterator cur = properties.begin() for (map<perm_string,prop_info_t>::const_iterator cur = properties.begin()
; cur != properties.end() ; ++cur) { ; cur != properties.end() ; ++cur) {
out << " " << cur->first; out << " " << cur->first;
} }
out << " }" << endl; out << " }" << endl;
} }
void class_type_t::pform_dump_init(ostream&out, unsigned indent) const
{
for (vector<Statement*>::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 void struct_member_t::pform_dump(ostream&out, unsigned indent) const
{ {
out << setw(indent) << "" << type; out << setw(indent) << "" << type;
@ -928,6 +938,13 @@ void PRepeat::dump(ostream&out, unsigned ind) const
statement_->dump(out, ind+3); 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 void PTask::dump(ostream&out, unsigned ind) const
{ {
out << setw(ind) << "" << "task "; out << setw(ind) << "" << "task ";
@ -1315,6 +1332,7 @@ void PClass::dump(ostream&out, unsigned indent) const
{ {
out << setw(indent) << "" << "class " << type->name << ";" << endl; out << setw(indent) << "" << "class " << type->name << ";" << endl;
type->pform_dump(out, indent+2); type->pform_dump(out, indent+2);
type->pform_dump_init(out, indent+2);
dump_tasks_(out, indent+2); dump_tasks_(out, indent+2);
dump_funcs_(out, indent+2); dump_funcs_(out, indent+2);
out << setw(indent) << "" << "endclass" << endl; out << setw(indent) << "" << "endclass" << endl;

View File

@ -41,15 +41,6 @@ void pform_class_property(const struct vlltype&loc,
{ {
assert(pform_cur_class); 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 // Add the non-static properties to the class type
// object. Unwind the list of names to make a map of name to // object. Unwind the list of names to make a map of name to
// type. // type.
@ -64,11 +55,20 @@ void pform_class_property(const struct vlltype&loc,
use_type = new uarray_type_t(use_type, pd); use_type = new uarray_type_t(use_type, pd);
} }
if (curp->expr.get()) { pform_cur_class->type->properties[curp->name]
VLerror(loc, "sorry: Initialization expressions for properties not implemented."); = 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; return func;
} }
void pform_end_class_declaration(void) void pform_end_class_declaration(const struct vlltype&loc)
{ {
assert(pform_cur_class); 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_cur_class = 0;
pform_pop_scope(); pform_pop_scope();
} }

View File

@ -24,9 +24,11 @@
# include "LineInfo.h" # include "LineInfo.h"
# include "verinum.h" # include "verinum.h"
# include "named.h" # include "named.h"
# include "property_qual.h"
# include "ivl_target.h" # include "ivl_target.h"
# include <iostream> # include <iostream>
# include <list> # include <list>
# include <vector>
# include <map> # include <map>
# include <memory> # include <memory>
@ -37,6 +39,7 @@
class Design; class Design;
class NetScope; class NetScope;
class PExpr; class PExpr;
class Statement;
class ivl_type_s; class ivl_type_s;
typedef named<verinum> named_number_t; typedef named<verinum> named_number_t;
typedef named<PExpr*> named_pexpr_t; typedef named<PExpr*> named_pexpr_t;
@ -212,45 +215,32 @@ struct class_type_t : public data_type_t {
: name(n) { } : name(n) { }
void pform_dump(std::ostream&out, unsigned indent) const; 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; perm_string name;
std::map<perm_string, data_type_t*> 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<perm_string, struct prop_info_t> 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<Statement*> 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<Statement*> initialize_static;
ivl_type_s* elaborate_type(Design*, NetScope*) const; 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 * The pform_name_t is the general form for a hierarchical
* identifier. It is an ordered list of name components. Each name * identifier. It is an ordered list of name components. Each name

60
property_qual.h Normal file
View File

@ -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

View File

@ -65,6 +65,8 @@ bool symbol_search(const LineInfo*li, Design*des, NetScope*scope,
assert(scope); assert(scope);
bool prefix_scope = false; bool prefix_scope = false;
bool recurse_flag = false; bool recurse_flag = false;
ivl_assert(*li, ! path.empty());
name_component_t path_tail = path.back(); name_component_t path_tail = path.back();
path.pop_back(); path.pop_back();

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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); 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) static void show_stmt_force(ivl_statement_t net, unsigned ind)
{ {
unsigned idx; unsigned idx;
@ -378,6 +384,10 @@ void show_statement(ivl_statement_t net, unsigned ind)
show_stmt_delayx(net, ind); show_stmt_delayx(net, ind);
break; break;
case IVL_ST_DISABLE:
show_stmt_disable(net, ind);
break;
case IVL_ST_FORCE: case IVL_ST_FORCE:
show_stmt_force(net, ind); show_stmt_force(net, ind);
break; break;

View File

@ -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); 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, " %%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"); fprintf(vvp_out, " %%pop/obj 1;\n");
clr_vector(val); clr_vector(val);

View File

@ -59,14 +59,17 @@ LIBS = @LIBS@ @EXTRALIBS@
M = StringHeap.o LineInfo.o M = StringHeap.o LineInfo.o
O = main.o architec.o compiler.o entity.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 \ architec_elaborate.o entity_elaborate.o expression_elaborate.o \
expression_evaluate.o \ expression_evaluate.o \
sequential_elaborate.o \ sequential_elaborate.o \
vtype_elaborate.o \
entity_stream.o expression_stream.o vtype_stream.o \ entity_stream.o expression_stream.o vtype_stream.o \
lexor.o lexor_keyword.o parse.o \ lexor.o lexor_keyword.o parse.o \
parse_misc.o library.o vhdlreal.o vhdlint.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 \ debug.o architec_debug.o expression_debug.o sequential_debug.o \
$M $M

View File

@ -26,7 +26,7 @@
using namespace std; using namespace std;
Architecture::Architecture(perm_string name, const ScopeBase&ref, Architecture::Architecture(perm_string name, const ActiveScope&ref,
list<Architecture::Statement*>&s) list<Architecture::Statement*>&s)
: Scope(ref), name_(name) : Scope(ref), name_(name)
{ {

View File

@ -63,7 +63,7 @@ class Architecture : public Scope, public LineInfo {
public: public:
// Create an architecture from its name and its statements. // Create an architecture from its name and its statements.
// NOTE: The statement list passed in is emptied. // NOTE: The statement list passed in is emptied.
Architecture(perm_string name, const ScopeBase&ref, Architecture(perm_string name, const ActiveScope&ref,
std::list<Architecture::Statement*>&s); std::list<Architecture::Statement*>&s);
~Architecture(); ~Architecture();

View File

@ -32,12 +32,12 @@ int Architecture::elaborate(Entity*entity)
// from the constant declaration itself. Elaborate the value // from the constant declaration itself. Elaborate the value
// expression with the declared type. // expression with the declared type.
for (map<perm_string,struct const_t*>::iterator cur = old_constants_.begin() for (map<perm_string,struct const_t*>::iterator cur = use_constants_.begin()
; cur != old_constants_.end() ; ++cur) { ; cur != use_constants_.end() ; ++cur) {
cur->second->val->elaborate_expr(entity, this, cur->second->typ); cur->second->val->elaborate_expr(entity, this, cur->second->typ);
} }
for (map<perm_string,struct const_t*>::iterator cur = new_constants_.begin() for (map<perm_string,struct const_t*>::iterator cur = cur_constants_.begin()
; cur != new_constants_.end() ; ++cur) { ; cur != cur_constants_.end() ; ++cur) {
cur->second->val->elaborate_expr(entity, this, cur->second->typ); cur->second->val->elaborate_expr(entity, this, cur->second->typ);
} }
@ -174,9 +174,54 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
return -1; return -1;
const Expression*ce_raw = stmt->peek_condition(); const Expression*ce_raw = stmt->peek_condition();
// Now we have matched this pattern:
// process(<expr>) begin if <ce_raw>...
// The <ce_raw> is the condition.
// We expect the condition to be <name>'event AND <name>='1'. if (const ExpFunc*ce_func = dynamic_cast<const ExpFunc*>(ce_raw)) {
// If it's not a logical AND, I give up. 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(<se>) if (rising_edge(<se>)) then ...
// and we can convert it to:
// always @(posedge <se>) ...
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
// <name>'event AND <name>='1'.
// So if ce_raw is not a logical AND, I give up.
const ExpLogical*ce = dynamic_cast<const ExpLogical*> (ce_raw); const ExpLogical*ce = dynamic_cast<const ExpLogical*> (ce_raw);
if (ce == 0) if (ce == 0)
return -1; return -1;

View File

@ -69,8 +69,8 @@ int Architecture::emit(ostream&out, Entity*entity)
// of the full definition. // of the full definition.
typedef_context_t typedef_ctx; typedef_context_t typedef_ctx;
for (map<perm_string,const VType*>::iterator cur = old_types_.begin() for (map<perm_string,const VType*>::iterator cur = cur_types_.begin()
; cur != old_types_.end() ; ++cur) { ; cur != cur_types_.end() ; ++cur) {
const VTypeDef*def = dynamic_cast<const VTypeDef*>(cur->second); const VTypeDef*def = dynamic_cast<const VTypeDef*>(cur->second);
if (def == 0) if (def == 0)
@ -79,15 +79,15 @@ int Architecture::emit(ostream&out, Entity*entity)
errors += def->emit_typedef(out, typedef_ctx); errors += def->emit_typedef(out, typedef_ctx);
} }
for (map<perm_string,struct const_t*>::iterator cur = old_constants_.begin() for (map<perm_string,struct const_t*>::iterator cur = use_constants_.begin()
; cur != old_constants_.end() ; ++cur) { ; cur != use_constants_.end() ; ++cur) {
out << "localparam " << cur->first << " = "; out << "localparam " << cur->first << " = ";
errors += cur->second->val->emit(out, entity, this); errors += cur->second->val->emit(out, entity, this);
out << ";" << endl; out << ";" << endl;
} }
for (map<perm_string,struct const_t*>::iterator cur = new_constants_.begin() for (map<perm_string,struct const_t*>::iterator cur = cur_constants_.begin()
; cur != new_constants_.end() ; ++cur) { ; cur != cur_constants_.end() ; ++cur) {
out << "localparam " << cur->first << " = "; out << "localparam " << cur->first << " = ";
errors += cur->second->val->emit(out, entity, this); errors += cur->second->val->emit(out, entity, this);

View File

@ -36,5 +36,6 @@ extern StringHeapLex filename_strings;
extern void library_set_work_path(const char*work_path); extern void library_set_work_path(const char*work_path);
extern void library_add_directory(const char*directory); extern void library_add_directory(const char*directory);
extern int emit_packages(void);
#endif #endif

View File

@ -22,6 +22,7 @@
# include "architec.h" # include "architec.h"
# include "expression.h" # include "expression.h"
# include "parse_types.h" # include "parse_types.h"
# include "sequential.h"
# include "vsignal.h" # include "vsignal.h"
# include "vtype.h" # include "vtype.h"
# include <fstream> # include <fstream>
@ -100,31 +101,36 @@ void ComponentBase::dump_ports(ostream&out, int indent) const
void Scope::dump_scope(ostream&out) const void Scope::dump_scope(ostream&out) const
{ {
// Dump types // Dump types
for (map<perm_string,const VType*>::const_iterator cur = old_types_.begin() out << " -- imported types" << endl;
; cur != old_types_.end() ; ++cur) { for (map<perm_string,const VType*>::const_iterator cur = use_types_.begin()
; cur != use_types_.end() ; ++cur) {
out << " " << cur->first << ": "; out << " " << cur->first << ": ";
cur->second->show(out); cur->second->show(out);
out << endl; out << endl;
} }
for (map<perm_string,const VType*>::const_iterator cur = new_types_.begin() out << " -- Types from this scope" << endl;
; cur != new_types_.end() ; ++cur) { for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++cur) {
out << " " << cur->first << ": "; out << " " << cur->first << ": ";
cur->second->show(out); cur->second->show(out);
out << endl; out << endl;
} }
// Dump constants // Dump constants
for (map<perm_string,const_t*>::const_iterator cur = old_constants_.begin() out << " -- imported constants" << endl;
; cur != old_constants_.end() ; ++cur) { for (map<perm_string,const_t*>::const_iterator cur = use_constants_.begin()
; cur != use_constants_.end() ; ++cur) {
out << " constant " << cur->first << " = "; out << " constant " << cur->first << " = ";
out << endl; out << endl;
} }
for (map<perm_string,const_t*>::const_iterator cur = new_constants_.begin() out << " -- Constants from this scope" << endl;
; cur != new_constants_.end() ; ++cur) { for (map<perm_string,const_t*>::const_iterator cur = cur_constants_.begin()
; cur != cur_constants_.end() ; ++cur) {
out << " constant " << cur->first << " = "; out << " constant " << cur->first << " = ";
out << endl; out << endl;
} }
// Dump signal declarations // Dump signal declarations
out << " -- Signals" << endl;
for (map<perm_string,Signal*>::const_iterator cur = old_signals_.begin() for (map<perm_string,Signal*>::const_iterator cur = old_signals_.begin()
; cur != old_signals_.end() ; ++cur) { ; cur != old_signals_.end() ; ++cur) {
if (cur->second) if (cur->second)
@ -138,8 +144,24 @@ void Scope::dump_scope(ostream&out) const
cur->second->dump(out, 3); cur->second->dump(out, 3);
else else
out << " signal " << cur->first.str() << ": ???" << endl; out << " signal " << cur->first.str() << ": ???" << endl;
}
// Dump subprograms
out << " -- Imported Subprograms" << endl;
for (map<perm_string,Subprogram*>::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<perm_string,Subprogram*>::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 // Dump component declarations
out << " -- Components" << endl;
for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin() for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin()
; cur != old_components_.end() ; ++cur) { ; cur != old_components_.end() ; ++cur) {
out << " component " << cur->first << " is" << endl; out << " component " << cur->first << " is" << endl;
@ -148,10 +170,11 @@ void Scope::dump_scope(ostream&out) const
out << " end component " << cur->first << endl; out << " end component " << cur->first << endl;
} }
for (map<perm_string,ComponentBase*>::const_iterator cur = new_components_.begin() for (map<perm_string,ComponentBase*>::const_iterator cur = new_components_.begin()
; cur != new_components_.end() ; ++cur) { ; cur != new_components_.end() ; ++cur) {
out << " component " << cur->first << " is" << endl; out << " component " << cur->first << " is" << endl;
cur->second->dump_ports(out); cur->second->dump_generics(out);
out << " end component " << cur->first << endl; cur->second->dump_ports(out);
out << " end component " << cur->first << endl;
} }
} }
@ -436,3 +459,41 @@ ostream& ExpInteger::dump_inline(ostream&out) const
out << value_; out << value_;
return out; return out;
} }
void Subprogram::dump(ostream&fd) const
{
fd << " " << name_;
if (ports_->empty()) {
fd << "()";
} else {
fd << "(";
list<InterfacePort*>::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 << " <no definition>" << endl;
} else {
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
; cur != statements_->end() ; ++cur) {
SequentialStmt*curp = *cur;
curp->dump(fd, 8);
}
}
}

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -113,6 +114,10 @@ int Entity::elaborate_ports_(void)
continue; 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; VType::decl_t cur_decl;
cur_decl.type = type; cur_decl.type = type;
declarations_[cur_port->name] = cur_decl; declarations_[cur_port->name] = cur_decl;

View File

@ -1,5 +1,6 @@
/* /*
* Copyright (c) 2011-2013 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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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) void Expression::set_type(const VType*typ)
{ {
assert(type_ == 0); assert(type_==0 || type_==typ);
type_ = typ; type_ = typ;
} }
@ -260,12 +261,12 @@ ExpEdge::~ExpEdge()
} }
ExpFunc::ExpFunc(perm_string nn) ExpFunc::ExpFunc(perm_string nn)
: name_(nn), argv_(0) : name_(nn), def_(0)
{ {
} }
ExpFunc::ExpFunc(perm_string nn, list<Expression*>*args) ExpFunc::ExpFunc(perm_string nn, list<Expression*>*args)
: name_(nn), argv_(args->size()) : name_(nn), argv_(args->size()), def_(0)
{ {
for (size_t idx = 0; idx < argv_.size() ; idx += 1) { for (size_t idx = 0; idx < argv_.size() ; idx += 1) {
ivl_assert(*this, !args->empty()); ivl_assert(*this, !args->empty());

View File

@ -1,7 +1,8 @@
#ifndef __expression_H #ifndef __expression_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -31,6 +32,7 @@ class prange_t;
class Entity; class Entity;
class Architecture; class Architecture;
class ScopeBase; class ScopeBase;
class Subprogram;
class VType; class VType;
class VTypeArray; class VTypeArray;
class VTypePrimitive; class VTypePrimitive;
@ -90,6 +92,10 @@ class Expression : public LineInfo {
// class fills in the details of what exactly happened. // class fills in the details of what exactly happened.
virtual int emit(ostream&out, Entity*ent, Architecture*arc) =0; 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 // The evaluate virtual method tries to evaluate expressions
// to constant literal values. Return true and set the val // to constant literal values. Return true and set the val
// argument if the evaluation works, or return false if it // 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; void dump_operands(ostream&out, int indent = 0) const;
private:
virtual const VType*resolve_operand_types_(const VType*t1, const VType*t2) const;
private: private:
Expression*operand1_; Expression*operand1_;
Expression*operand2_; Expression*operand2_;
@ -299,6 +308,9 @@ class ExpArithmetic : public ExpBinary {
virtual bool evaluate(ScopeBase*scope, int64_t&val) const; virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const; void dump(ostream&out, int indent = 0) const;
private:
const VType* resolve_operand_types_(const VType*t1, const VType*t2) const;
private: private:
fun_t fun_; fun_t fun_;
}; };
@ -457,6 +469,10 @@ class ExpFunc : public Expression {
ExpFunc(perm_string nn, std::list<Expression*>*args); ExpFunc(perm_string nn, std::list<Expression*>*args);
~ExpFunc(); ~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 public: // Base methods
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd); void write_to_stream(std::ostream&fd);
@ -466,6 +482,7 @@ class ExpFunc : public Expression {
private: private:
perm_string name_; perm_string name_;
std::vector<Expression*> argv_; std::vector<Expression*> argv_;
Subprogram*def_;
}; };
class ExpInteger : public Expression { class ExpInteger : public Expression {
@ -478,6 +495,7 @@ class ExpInteger : public Expression {
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype); int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd); void write_to_stream(std::ostream&fd);
int emit(ostream&out, Entity*ent, Architecture*arc); int emit(ostream&out, Entity*ent, Architecture*arc);
int emit_package(std::ostream&out);
bool is_primary(void) const; bool is_primary(void) const;
bool evaluate(ScopeBase*scope, int64_t&val) const; bool evaluate(ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const; void dump(ostream&out, int indent = 0) const;

View File

@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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) if (t1 == t2)
return t1; return t1;
if (const VType*tb = resolve_operand_types_(t1, t2))
return tb;
// FIXME: I should at this point try harder to find an // FIXME: I should at this point try harder to find an
// operator that has the proper argument list and use this // operator that has the proper argument list and use this
// here, but for now we leave it for the back-end to figure out. // 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; 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 ExpBinary::elaborate_exprs(Entity*ent, Architecture*arc, const VType*ltype)
{ {
int errors = 0; int errors = 0;
@ -491,6 +499,21 @@ int ExpArithmetic::elaborate_expr(Entity*ent, Architecture*arc, const VType*ltyp
return errors; return errors;
} }
const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t2) const
{
while (const VTypeRange*tmp = dynamic_cast<const VTypeRange*> (t1))
t1 = tmp->base_type();
while (const VTypeRange*tmp = dynamic_cast<const VTypeRange*> (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 const VType* ExpAttribute::probe_type(Entity*ent, Architecture*arc) const
{ {
base_->probe_type(ent, arc); base_->probe_type(ent, arc);
@ -637,6 +660,12 @@ int ExpFunc::elaborate_expr(Entity*ent, Architecture*arc, const VType*)
{ {
int errors = 0; 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) { for (size_t idx = 0 ; idx < argv_.size() ; idx += 1) {
const VType*tmp = argv_[idx]->probe_type(ent, arc); const VType*tmp = argv_[idx]->probe_type(ent, arc);
errors += argv_[idx]->elaborate_expr(ent, arc, tmp); errors += argv_[idx]->elaborate_expr(ent, arc, tmp);

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -20,10 +21,12 @@
# include "expression.h" # include "expression.h"
# include "vtype.h" # include "vtype.h"
# include "architec.h" # include "architec.h"
# include "package.h"
# include "parse_types.h" # include "parse_types.h"
# include <typeinfo> # include <typeinfo>
# include <iostream> # include <iostream>
# include <cstdlib> # include <cstdlib>
# include <cstring>
# include "ivl_assert.h" # include "ivl_assert.h"
# include <cassert> # include <cassert>
@ -37,6 +40,14 @@ int Expression::emit(ostream&out, Entity*, Architecture*)
return 1; 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 bool Expression::is_primary(void) const
{ {
return false; 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 the down to a literal integer at compile time, and all it
needs is the type of the base expression. (The base needs is the type of the base expression. (The base
expression doesn't even need to be evaluated.) */ expression doesn't even need to be evaluated.) */
if (name_ == "length") { if (name_=="length") {
int64_t val; out << "$bits(";
bool rc = evaluate(ent, arc, val); errors += base_->emit(out, ent, arc);
out << val; out << ")";
if (rc) return errors;
return errors;
else
return errors + 1;
} }
out << "$ivl_attribute("; out << "$ivl_attribute(";
errors += base_->emit(out, ent, arc); errors += base_->emit(out, ent, arc);
out << ", \"" << name_ << "\")"; out << ", \"" << name_ << "\")";
@ -531,13 +540,12 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc)
out << ")"; out << ")";
} else if (name_ == "to_unsigned" && argv_.size() == 2) { } 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); 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) { } else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) {
int64_t use_size; int64_t use_size;
@ -547,7 +555,28 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc)
errors += argv_[0]->emit(out, ent, arc); errors += argv_[0]->emit(out, ent, arc);
out << ")"; 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 { } 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<const Package*> (def_->get_parent());
if (pkg != 0)
out << "\\" << pkg->name() << " ::";
}
out << "\\" << name_ << " ("; out << "\\" << name_ << " (";
for (size_t idx = 0; idx < argv_.size() ; idx += 1) { for (size_t idx = 0; idx < argv_.size() ; idx += 1) {
if (idx > 0) out << ", "; if (idx > 0) out << ", ";
@ -565,6 +594,12 @@ int ExpInteger::emit(ostream&out, Entity*, Architecture*)
return 0; return 0;
} }
int ExpInteger::emit_package(ostream&out)
{
out << value_;
return 0;
}
bool ExpInteger::is_primary(void) const bool ExpInteger::is_primary(void) const
{ {
return true; return true;
@ -713,6 +748,18 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA
const VTypePrimitive*etype = dynamic_cast<const VTypePrimitive*> (arr->element_type()); const VTypePrimitive*etype = dynamic_cast<const VTypePrimitive*> (arr->element_type());
assert(etype); 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<char> 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); assert(etype->type() != VTypePrimitive::INTEGER);
out << value_.size() << "'b"; out << value_.size() << "'b";
for (size_t idx = 0 ; idx < value_.size() ; idx += 1) { 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"; out << "z";
break; break;
default: 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); assert(etype->type() == VTypePrimitive::STDLOGIC);
out << "x"; out << "x";
break; break;

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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 * 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) 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. // library right now, then store it in the work library.
if (parse_library_name.str() == 0) if (parse_library_name.str() == 0)
store_package_in_work(pack); 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<perm_string,struct library_contents>::iterator lib = libraries.find(use_libname);
if (lib == libraries.end())
return 0;
map<perm_string,Package*>::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) 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") { if (all_flag || name == "std_logic_vector") {
vector<VTypeArray::range_t> dims (1); vector<VTypeArray::range_t> 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)); 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") { if (all_flag || name == "signed") {
vector<VTypeArray::range_t> dims (1); vector<VTypeArray::range_t> dims (1);
res->bind_name(perm_string::literal("signed"), res->use_name(perm_string::literal("signed"),
new VTypeArray(primitive_STDLOGIC, dims, true)); new VTypeArray(primitive_STDLOGIC, dims, true));
} }
if (all_flag || name == "unsigned") { if (all_flag || name == "unsigned") {
vector<VTypeArray::range_t> dims (1); vector<VTypeArray::range_t> dims (1);
res->bind_name(perm_string::literal("unsigned"), res->use_name(perm_string::literal("unsigned"),
new VTypeArray(primitive_BIT, dims, false)); 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") { if (all_flag || name == "signed") {
vector<VTypeArray::range_t> dims (1); vector<VTypeArray::range_t> dims (1);
res->bind_name(perm_string::literal("signed"), res->use_name(perm_string::literal("signed"),
new VTypeArray(primitive_STDLOGIC, dims, true)); new VTypeArray(primitive_STDLOGIC, dims, true));
} }
if (all_flag || name == "unsigned") { if (all_flag || name == "unsigned") {
vector<VTypeArray::range_t> dims (1); vector<VTypeArray::range_t> dims (1);
res->bind_name(perm_string::literal("unsigned"), res->use_name(perm_string::literal("unsigned"),
new VTypeArray(primitive_STDLOGIC, dims, false)); 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_BIT = new VTypePrimitive(VTypePrimitive::BIT);
const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER); const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER);
const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC); 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 VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0);
const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector<VTypeArray::range_t> (1)); static const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector<VTypeArray::range_t> (1));
const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector<VTypeArray::range_t> (1)); static const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector<VTypeArray::range_t> (1));
static const VTypeArray* primitive_STRING = new VTypeArray(primitive_CHARACTER, vector<VTypeArray::range_t> (1));
void generate_global_types(ActiveScope*res) void generate_global_types(ActiveScope*res)
{ {
res->bind_name(perm_string::literal("boolean"), primitive_BOOLEAN); res->use_name(perm_string::literal("boolean"), primitive_BOOLEAN);
res->bind_name(perm_string::literal("bit"), primitive_BIT); res->use_name(perm_string::literal("bit"), primitive_BIT);
res->bind_name(perm_string::literal("integer"), primitive_INTEGER); res->use_name(perm_string::literal("integer"), primitive_INTEGER);
res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC); res->use_name(perm_string::literal("std_logic"), primitive_STDLOGIC);
res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR); res->use_name(perm_string::literal("character"), primitive_CHARACTER);
res->bind_name(perm_string::literal("natural"), primitive_NATURAL); 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) 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 == "bit") return true;
if (name == "integer") return true; if (name == "integer") return true;
if (name == "std_logic") return true; if (name == "std_logic") return true;
if (name == "character") return true;
if (name == "bit_vector") return true; if (name == "bit_vector") return true;
if (name == "string") return true;
if (name == "natural") return true; if (name == "natural") return true;
return false; return false;
} }
@ -363,3 +394,25 @@ static void store_package_in_work(const Package*pack)
pack->write_to_stream(file); pack->write_to_stream(file);
} }
static int emit_packages(perm_string lib_name, const map<perm_string,Package*>&packages)
{
int errors = 0;
for (map<perm_string,Package*>::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<perm_string,struct library_contents>::iterator cur = libraries.begin()
; cur != libraries.end() ; ++cur) {
errors += emit_packages(cur->first, cur->second.packages);
}
return 0;
}

View File

@ -218,17 +218,24 @@ int main(int argc, char*argv[])
} }
if (errors > 0) { if (errors > 0) {
parser_cleanup(); parser_cleanup();
return 2; return 2;
} }
errors = elaborate_entities(); errors = elaborate_entities();
if (errors > 0) { if (errors > 0) {
fprintf(stderr, "%d errors elaborating design.\n", errors); fprintf(stderr, "%d errors elaborating design.\n", errors);
parser_cleanup(); parser_cleanup();
return 3; return 3;
} }
errors = emit_packages();
if (errors > 0) {
fprintf(stderr, "%d errors emitting packages.\n", errors);
parser_cleanup();
return 4;
}
errors = emit_entities(); errors = emit_entities();
if (errors > 0) { if (errors > 0) {
fprintf(stderr, "%d errors emitting design.\n", errors); fprintf(stderr, "%d errors emitting design.\n", errors);

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -20,8 +21,9 @@
# include "package.h" # include "package.h"
# include "entity.h" # include "entity.h"
# include "parse_misc.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) : Scope(ref), name_(n)
{ {
} }
@ -31,6 +33,12 @@ Package::~Package()
ScopeBase::cleanup(); 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 * The Package::write_to_stream is used to write the package to the
* work space (or library) so writes proper VHDL that the library * 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 // Start out pre-declaring all the type definitions so that
// there is no confusion later in the package between types // there is no confusion later in the package between types
// and identifiers. // and identifiers.
for (map<perm_string,const VType*>::const_iterator cur = old_types_.begin() for (map<perm_string,const VType*>::const_iterator cur = use_types_.begin()
; cur != old_types_.end() ; ++cur) { ; cur != use_types_.end() ; ++cur) {
const VTypeDef*def = dynamic_cast<const VTypeDef*> (cur->second);
if (def == 0)
continue;
fd << "type " << cur->first << ";" << endl;
}
for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++cur) {
const VTypeDef*def = dynamic_cast<const VTypeDef*> (cur->second); const VTypeDef*def = dynamic_cast<const VTypeDef*> (cur->second);
if (def == 0) if (def == 0)
continue; continue;
fd << "type " << cur->first << ";" << endl; fd << "type " << cur->first << ";" << endl;
} }
for (map<perm_string,const VType*>::const_iterator cur = new_types_.begin() for (map<perm_string,struct const_t*>::const_iterator cur = cur_constants_.begin()
; cur != new_types_.end() ; ++cur) { ; cur != cur_constants_.end() ; ++ cur) {
const VTypeDef*def = dynamic_cast<const VTypeDef*> (cur->second); if (cur->second==0 || cur->second->typ==0) {
if (def == 0) fd << "-- const " << cur->first
<< " has errors." << endl;
continue; continue;
fd << "type " << cur->first << ";" << endl; }
}
for (map<perm_string,struct const_t*>::const_iterator cur = old_constants_.begin()
; cur != old_constants_.end() ; ++ cur) {
fd << "constant " << cur->first << ": "; fd << "constant " << cur->first << ": ";
cur->second->typ->write_to_stream(fd); cur->second->typ->write_to_stream(fd);
fd << " := "; fd << " := ";
@ -68,17 +81,21 @@ void Package::write_to_stream(ostream&fd) const
fd << ";" << endl; fd << ";" << endl;
} }
for (map<perm_string,struct const_t*>::const_iterator cur = new_constants_.begin() for (map<perm_string,const VType*>::const_iterator cur = use_types_.begin()
; cur != new_constants_.end() ; ++ cur) { ; cur != use_types_.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<perm_string,const VType*>::const_iterator cur = old_types_.begin() // Do not include global types in types dump
; cur != old_types_.end() ; ++cur) { 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<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++cur) {
// Do not include global types in types dump // Do not include global types in types dump
if (is_global_type(cur->first)) 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); cur->second->write_type_to_stream(fd);
fd << ";" << endl; fd << ";" << endl;
} }
for (map<perm_string,const VType*>::const_iterator cur = new_types_.begin()
; cur != new_types_.end() ; ++cur) {
// Do not include primitive types in type dump for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
if (is_global_type(cur->first)) ; cur != cur_subprograms_.end() ; ++cur) {
continue; cur->second->write_to_stream(fd);
if (cur->first == "std_logic_vector")
continue;
fd << "type " << cur->first << " is ";
cur->second->write_type_to_stream(fd);
fd << ";" << endl;
} }
for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin() for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin()

View File

@ -1,7 +1,8 @@
#ifndef __package_H #ifndef __package_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -26,15 +27,24 @@
class Package : public Scope, public LineInfo { class Package : public Scope, public LineInfo {
public: public:
Package(perm_string name, const ScopeBase&ref); Package(perm_string name, const ActiveScope&ref);
~Package(); ~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_; } perm_string name() const { return name_; }
Subprogram* recall_subprogram(perm_string name) const;
// This method writes a package header to a library file. // This method writes a package header to a library file.
void write_to_stream(std::ostream&fd) const; void write_to_stream(std::ostream&fd) const;
int emit_package(std::ostream&fd) const;
private: private:
perm_string from_library_;
perm_string name_; perm_string name_;
}; };

76
vhdlpp/package_emit.cc Normal file
View File

@ -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 <iostream>
# 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<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++ cur) {
fd << "typedef ";
errors += cur->second->emit_def(fd);
fd << " \\" << cur->first << " ;" << endl;
}
for (map<perm_string,struct const_t*>::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<perm_string,struct const_t*>::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<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
errors += cur->second->emit_package(fd);
}
fd << "endpackage" << endl;
return errors;
}

View File

@ -6,8 +6,8 @@
%parse-param {perm_string parse_library_name} %parse-param {perm_string parse_library_name}
%{ %{
/* /*
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com) * Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com) * Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
* *
* This source code is free software; you can redistribute it * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -34,7 +34,8 @@
# include "architec.h" # include "architec.h"
# include "expression.h" # include "expression.h"
# include "sequential.h" # include "sequential.h"
# include "package.h" # include "subprogram.h"
# include "package.h"
# include "vsignal.h" # include "vsignal.h"
# include "vtype.h" # include "vtype.h"
# include <cstdarg> # include <cstdarg>
@ -181,6 +182,16 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
return res; return res;
} }
static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
{
for (list<InterfacePort*>::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<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
std::list<prange_t*>*range_list; std::list<prange_t*>*range_list;
ExpArithmetic::fun_t arithmetic_op; ExpArithmetic::fun_t arithmetic_op;
std::list<struct adding_term>*adding_terms;
ExpAggregate::choice_t*choice; ExpAggregate::choice_t*choice;
std::list<ExpAggregate::choice_t*>*choice_list; std::list<ExpAggregate::choice_t*>*choice_list;
@ -234,6 +246,8 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
Architecture::Statement* arch_statement; Architecture::Statement* arch_statement;
std::list<Architecture::Statement*>* arch_statement_list; std::list<Architecture::Statement*>* arch_statement_list;
Subprogram*subprogram;
}; };
/* The keywords are all tokens. */ /* The keywords are all tokens. */
@ -274,6 +288,7 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <flag> direction %type <flag> direction
%type <arithmetic_op> adding_operator %type <arithmetic_op> adding_operator
%type <adding_terms> simple_expression_terms
%type <interface_list> interface_element interface_list %type <interface_list> interface_element interface_list
%type <interface_list> port_clause port_clause_opt %type <interface_list> port_clause port_clause_opt
@ -301,7 +316,7 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <expr> expression_logical_xnor expression_logical_xor %type <expr> expression_logical_xnor expression_logical_xor
%type <expr> name prefix selected_name %type <expr> name prefix selected_name
%type <expr> shift_expression signal_declaration_assign_opt %type <expr> shift_expression signal_declaration_assign_opt
%type <expr> simple_expression term waveform_element %type <expr> simple_expression simple_expression_2 term waveform_element
%type <expr> interface_element_expression %type <expr> interface_element_expression
%type <expr_list> waveform waveform_elements %type <expr_list> waveform waveform_elements
@ -319,11 +334,12 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <record_elements> element_declaration element_declaration_list %type <record_elements> element_declaration element_declaration_list
%type <text> architecture_body_start package_declaration_start %type <text> architecture_body_start package_declaration_start
%type <text> package_body_start
%type <text> identifier_opt identifier_colon_opt logical_name suffix %type <text> identifier_opt identifier_colon_opt logical_name suffix
%type <name_list> logical_name_list identifier_list %type <name_list> logical_name_list identifier_list
%type <name_list> enumeration_literal_list enumeration_literal %type <name_list> enumeration_literal_list enumeration_literal
%type <sequ_list> sequence_of_statements if_statement_else %type <sequ_list> if_statement_else sequence_of_statements subprogram_statement_part
%type <sequ> sequential_statement if_statement signal_assignment_statement %type <sequ> sequential_statement if_statement signal_assignment_statement
%type <sequ> case_statement procedure_call procedure_call_statement %type <sequ> case_statement procedure_call procedure_call_statement
%type <sequ> loop_statement variable_assignment_statement %type <sequ> loop_statement variable_assignment_statement
@ -341,6 +357,8 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <exp_else> else_when_waveform %type <exp_else> else_when_waveform
%type <exp_else_list> else_when_waveforms %type <exp_else_list> else_when_waveforms
%type <subprogram> function_specification subprogram_specification
%% %%
/* The design_file is the root for the VHDL parse. This rule is also /* The design_file is the root for the VHDL parse. This rule is also
@ -658,6 +676,15 @@ composite_type_definition
delete $2; delete $2;
$$ = tmp; $$ = 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<prange_t*> r;
VTypeArray*tmp = new VTypeArray($6, &r);
$$ = tmp;
}
| record_type_definition | record_type_definition
{ $$ = $1; } { $$ = $1; }
; ;
@ -1143,6 +1170,16 @@ for_generate_statement
function_specification /* IEEE 1076-2008 P4.2.1 */ function_specification /* IEEE 1076-2008 P4.2.1 */
: K_function IDENTIFIER '(' interface_list ')' K_return IDENTIFIER : 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 */ 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 instantiation_list
: identifier_list : identifier_list
{ {
@ -1599,20 +1646,40 @@ package_declarative_part_opt
| |
; ;
package_body package_body /* IEEE 1076-2008 P4.8 */
: K_package K_body IDENTIFIER K_is : package_body_start K_is
package_body_declarative_part_opt package_body_declarative_part_opt
K_end K_package_opt identifier_opt ';' K_end K_package_opt identifier_opt ';'
{ sorrymsg(@1, "Package body is not yet supported.\n"); { perm_string name = lex_strings.make($1);
delete[] $3; if ($6 && name != $6)
if($8) delete[] $8; 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 | package_body_start K_is error K_end K_package_opt identifier_opt ';'
error { errormsg(@1, "Errors in package %s body.\n", $1);
K_end K_package_opt identifier_opt ';'
{ errormsg(@1, "Errors in package body.\n");
yyerrok; 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; $$ = tmp;
} }
| IDENTIFIER '(' error ')' | IDENTIFIER '(' error ')'
{ { errormsg(@1, "Errors in procedure call.\n");
errormsg(@1, "Errors in procedure call.\n"); yyerrok;
yyerrok; delete[]$1;
delete[]$1; $$ = 0;
$$ = 0; }
}; ;
procedure_call_statement procedure_call_statement
: IDENTIFIER ':' procedure_call { $$ = $3; } : IDENTIFIER ':' procedure_call { $$ = $3; }
@ -2002,6 +2069,11 @@ sequential_statement
shift_expression : simple_expression { $$ = $1; } ; shift_expression : simple_expression { $$ = $1; } ;
sign
: '+'
| '-'
;
signal_declaration_assign_opt signal_declaration_assign_opt
: VASSIGN expression { $$ = $2; } : VASSIGN expression { $$ = $2; }
| { $$ = 0; } | { $$ = 0; }
@ -2020,18 +2092,55 @@ signal_declaration_assign_opt
* Note that although the concatenation operator '&' is syntactically * Note that although the concatenation operator '&' is syntactically
* an addition operator, it is handled differently during elaboration * an addition operator, it is handled differently during elaboration
* so detect it and create a different expression type. * 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 simple_expression
: sign simple_expression_2
{ sorrymsg(@1, "Unary expression +- not supported.\n");
$$ = $2;
}
| simple_expression_2
{ $$ = $1; }
;
simple_expression_2
: term : term
{ $$ = $1; } { $$ = $1; }
| simple_expression adding_operator term | term simple_expression_terms
{ Expression*tmp; { Expression*tmp = $1;
if ($2 == ExpArithmetic::xCONCAT) { list<struct adding_term>*lst = $2;
tmp = new ExpConcat($1, $3); while (! lst->empty()) {
} else { struct adding_term item = lst->front();
tmp = new ExpArithmetic($2, $1, $3); 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<adding_term>*tmp = new list<adding_term>;
tmp->push_back(item);
$$ = tmp;
}
| simple_expression_terms adding_operator term
{ list<adding_term>*tmp = $1;
struct adding_term item;
item.op = $2;
item.term = $3;
tmp->push_back(item);
$$ = tmp; $$ = 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_body /* IEEE 1076-2008 P4.3 */
: subprogram_specification K_is : subprogram_specification K_is
subprogram_declarative_part subprogram_declarative_part
K_begin subprogram_statement_part K_end K_begin subprogram_statement_part K_end
subprogram_kind_opt identifier_opt ';' subprogram_kind_opt identifier_opt ';'
{ sorrymsg(@2, "Subprogram bodies not supported.\n"); { Subprogram*prog = $1;
if ($8) delete[]$8; 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 | subprogram_specification K_is
@ -2066,14 +2186,14 @@ subprogram_body /* IEEE 1076-2008 P4.3 */
subprogram_kind_opt identifier_opt ';' subprogram_kind_opt identifier_opt ';'
{ errormsg(@2, "Syntax errors in subprogram body.\n"); { errormsg(@2, "Syntax errors in subprogram body.\n");
yyerrok; yyerrok;
if ($1) delete $1;
if ($8) delete[]$8; if ($8) delete[]$8;
} }
; ;
subprogram_declaration subprogram_declaration
: subprogram_specification ';' : 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 */ 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_kind_opt : subprogram_kind | ;
subprogram_specification subprogram_specification
: function_specification : function_specification { $$ = $1; }
; ;
/* This is an implementation of the rule: /* This is an implementation of the rule:
@ -2107,8 +2227,8 @@ subprogram_specification
sequential_statement. Also handle the special case of an empty sequential_statement. Also handle the special case of an empty
list here. */ list here. */
subprogram_statement_part subprogram_statement_part
: sequence_of_statements : sequence_of_statements { $$ = $1; }
| | { $$ = 0; }
; ;
subtype_declaration subtype_declaration
@ -2132,12 +2252,13 @@ subtype_indication
delete[]$1; delete[]$1;
$$ = tmp; $$ = tmp;
} }
| IDENTIFIER '(' simple_expression direction simple_expression ')' | IDENTIFIER index_constraint
{ const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $3, $4, $5); { const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $2);
if (tmp == 0) { if (tmp == 0) {
errormsg(@1, "Unable to calculate bounds for array of %s.\n", $1); errormsg(@1, "Unable to calculate bounds for array of %s.\n", $1);
} }
delete[]$1; delete[]$1;
delete $2;
$$ = tmp; $$ = tmp;
} }
| IDENTIFIER K_range simple_expression direction simple_expression | IDENTIFIER K_range simple_expression direction simple_expression
@ -2148,11 +2269,6 @@ subtype_indication
delete[]$1; delete[]$1;
$$ = tmp; $$ = tmp;
} }
| IDENTIFIER '(' error ')'
{ errormsg(@1, "Syntax error in subtype indication.\n");
yyerrok;
$$ = new VTypeERROR;
}
; ;
suffix suffix

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -19,6 +20,7 @@
*/ */
# include "parse_misc.h" # include "parse_misc.h"
# include "parse_types.h"
# include "parse_api.h" # include "parse_api.h"
# include "entity.h" # include "entity.h"
# include "architec.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, static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase* /* scope */, ScopeBase* /* scope */,
Expression*array_left, Expression*array_left,
bool /* downto*/ , bool /* downto*/ ,
Expression*array_right) Expression*array_right)
{ {
const VType*base_type = parse_type_by_name(lex_strings.make(base_name)); 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; return base_type;
} }
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope, list<prange_t*>*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, const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope, ScopeBase*scope,
Expression*range_left, Expression*range_left,

View File

@ -1,7 +1,8 @@
#ifndef __parse_misc_H #ifndef __parse_misc_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -25,6 +26,7 @@ class ActiveScope;
class Architecture; class Architecture;
class Expression; class Expression;
class Package; class Package;
class prange_t;
class ScopeBase; class ScopeBase;
class VType; 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, extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope, ScopeBase*scope,
Expression*array_left, std::list<prange_t*>*ranges);
bool downto,
Expression*array_right);
extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name, extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope, ScopeBase*scope,
Expression*range_left, 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 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<perm_string>*names); extern void library_import(const YYLTYPE&loc, const std::list<perm_string>*names);
extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident); extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident);

View File

@ -1,7 +1,8 @@
#ifndef __parse_types_H #ifndef __parse_types_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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_; } ~prange_t() { delete left_; delete right_; }
void dump(ostream&out, int indent) const; void dump(ostream&out, int indent) const;
Expression*msb() { return direction_? left_ : right_; } inline Expression*msb() { return direction_? left_ : right_; }
Expression*lsb() { return direction_? right_: left_; } inline Expression*lsb() { return direction_? right_: left_; }
inline bool is_downto() const { return direction_; } inline bool is_downto() const { return direction_; }
inline Expression*expr_left() { return left_; }
inline Expression*expr_right() { return right_; }
private: private:
Expression *left_, *right_; Expression *left_, *right_;
@ -87,4 +90,10 @@ class prange_t {
prange_t(const prange_t&); prange_t(const prange_t&);
prange_t operator=(const prange_t&); prange_t operator=(const prange_t&);
}; };
struct adding_term {
ExpArithmetic::fun_t op;
Expression*term;
};
#endif #endif

View File

@ -31,6 +31,7 @@
# include "architec.h" # include "architec.h"
# include "expression.h" # include "expression.h"
# include "sequential.h" # include "sequential.h"
# include "subprogram.h"
# include "parse_types.h" # include "parse_types.h"
class VType; class VType;

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -18,9 +19,11 @@
*/ */
# include "scope.h" # include "scope.h"
# include "package.h"
# include <algorithm> # include <algorithm>
# include <iostream> # include <iostream>
# include <iterator> # include <iterator>
# include <cassert>
using namespace std; using namespace std;
@ -30,13 +33,11 @@ using namespace std;
* "old_*_" variables. This clears up the "new_*_" variables to * "old_*_" variables. This clears up the "new_*_" variables to
* accumulate new scope values. * accumulate new scope values.
*/ */
ScopeBase::ScopeBase(const ScopeBase&ref) ScopeBase::ScopeBase(const ActiveScope&ref)
{ {
merge(ref.old_constants_.begin(), ref.old_constants_.end(), use_constants_ = ref.use_constants_;
ref.new_constants_.begin(), ref.new_constants_.end(), cur_constants_ = ref.cur_constants_;
insert_iterator<map<perm_string, struct const_t*> >(
old_constants_, old_constants_.end())
);
merge(ref.old_signals_.begin(), ref.old_signals_.end(), merge(ref.old_signals_.begin(), ref.old_signals_.end(),
ref.new_signals_.begin(), ref.new_signals_.end(), ref.new_signals_.begin(), ref.new_signals_.end(),
insert_iterator<map<perm_string, Signal*> >( insert_iterator<map<perm_string, Signal*> >(
@ -52,11 +53,20 @@ ScopeBase::ScopeBase(const ScopeBase&ref)
insert_iterator<map<perm_string, ComponentBase*> >( insert_iterator<map<perm_string, ComponentBase*> >(
old_components_, old_components_.end()) old_components_, old_components_.end())
); );
merge(ref.old_types_.begin(), ref.old_types_.end(), use_types_ = ref.use_types_;
ref.new_types_.begin(), ref.new_types_.end(), cur_types_ = ref.cur_types_;
insert_iterator<map<perm_string, const VType*> >(
old_types_, old_types_.end()) 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<perm_string,Subprogram*>::iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
cur->second->set_parent(this);
}
} }
ScopeBase::~ScopeBase() ScopeBase::~ScopeBase()
@ -74,16 +84,17 @@ void ScopeBase::cleanup()
*/ */
delete_all(new_signals_); delete_all(new_signals_);
delete_all(new_components_); delete_all(new_components_);
delete_all(new_types_); delete_all(cur_types_);
delete_all(new_constants_); delete_all(cur_constants_);
delete_all(cur_subprograms_);
} }
const VType*ScopeBase::find_type(perm_string by_name) const VType*ScopeBase::find_type(perm_string by_name)
{ {
map<perm_string,const VType*>::const_iterator cur = new_types_.find(by_name); map<perm_string,const VType*>::const_iterator cur = cur_types_.find(by_name);
if (cur == new_types_.end()) { if (cur == cur_types_.end()) {
cur = old_types_.find(by_name); cur = use_types_.find(by_name);
if (cur == old_types_.end()) if (cur == use_types_.end())
return 0; return 0;
else else
return cur->second; 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) bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp)
{ {
map<perm_string,struct const_t*>::const_iterator cur = new_constants_.find(by_name); map<perm_string,struct const_t*>::const_iterator cur = cur_constants_.find(by_name);
if (cur == new_constants_.end()) { if (cur == cur_constants_.end()) {
cur = old_constants_.find(by_name); cur = use_constants_.find(by_name);
if (cur == old_constants_.end()) if (cur == use_constants_.end())
return false; return false;
else { else {
typ = cur->second->typ; 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<perm_string,Subprogram*>::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) void ScopeBase::do_use_from(const ScopeBase*that)
{ {
for (map<perm_string,ComponentBase*>::const_iterator cur = that->old_components_.begin() for (map<perm_string,ComponentBase*>::const_iterator cur = that->old_components_.begin()
@ -146,36 +176,51 @@ void ScopeBase::do_use_from(const ScopeBase*that)
continue; continue;
old_components_[cur->first] = cur->second; old_components_[cur->first] = cur->second;
} }
for (map<perm_string,ComponentBase*>::const_iterator cur = that->new_components_.begin() for (map<perm_string,ComponentBase*>::const_iterator cur = that->new_components_.begin()
; cur != that->new_components_.end() ; ++ cur) { ; cur != that->new_components_.end() ; ++ cur) {
if (cur->second == 0) if (cur->second == 0)
continue; continue;
old_components_[cur->first] = cur->second; old_components_[cur->first] = cur->second;
} }
for (map<perm_string,const VType*>::const_iterator cur = that->old_types_.begin() for (map<perm_string,Subprogram*>::const_iterator cur = that->cur_subprograms_.begin()
; cur != that->old_types_.end() ; ++ cur) { ; cur != that->cur_subprograms_.end() ; ++ cur) {
if (cur->second == 0) if (cur->second == 0)
continue; continue;
old_types_[cur->first] = cur->second; use_subprograms_[cur->first] = cur->second;
}
for (map<perm_string,const VType*>::const_iterator cur = that->new_types_.begin()
; cur != that->new_types_.end() ; ++ cur) {
if (cur->second == 0)
continue;
old_types_[cur->first] = cur->second;
} }
for (map<perm_string,const_t*>::const_iterator cur = that->old_constants_.begin()
; cur != that->old_constants_.end() ; ++ cur) { for (map<perm_string,const VType*>::const_iterator cur = that->cur_types_.begin()
old_constants_[cur->first] = cur->second; ; cur != that->cur_types_.end() ; ++ cur) {
if (cur->second == 0)
continue;
use_types_[cur->first] = cur->second;
} }
for (map<perm_string,const_t*>::const_iterator cur = that->new_constants_.begin()
; cur != that->new_constants_.end() ; ++ cur) { for (map<perm_string,const_t*>::const_iterator cur = that->cur_constants_.begin()
old_constants_[cur->first] = cur->second; ; 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 bool ActiveScope::is_vector_name(perm_string name) const
{ {
if (find_signal(name)) if (find_signal(name))
@ -189,7 +234,7 @@ bool ActiveScope::is_vector_name(perm_string name) const
return false; return false;
} }
Scope::Scope(const ScopeBase&ref) Scope::Scope(const ActiveScope&ref)
: ScopeBase(ref) : ScopeBase(ref)
{ {
} }

View File

@ -1,7 +1,8 @@
#ifndef __scope_H #ifndef __scope_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -23,12 +24,16 @@
# include <list> # include <list>
# include <map> # include <map>
# include "StringHeap.h" # include "StringHeap.h"
# include "entity.h" # include "entity.h"
# include "expression.h" # include "expression.h"
# include "vsignal.h" # include "subprogram.h"
# include "vsignal.h"
class ActiveScope;
class Architecture; class Architecture;
class ComponentBase; class ComponentBase;
class Package;
class Subprogram;
class VType; class VType;
template<typename T> template<typename T>
@ -45,13 +50,14 @@ class ScopeBase {
public: public:
ScopeBase() { } ScopeBase() { }
explicit ScopeBase(const ScopeBase&ref); explicit ScopeBase(const ActiveScope&ref);
virtual ~ScopeBase() =0; virtual ~ScopeBase() =0;
const VType* find_type(perm_string by_name); const VType* find_type(perm_string by_name);
bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp); bool find_constant(perm_string by_name, const VType*&typ, Expression*&exp);
Signal* find_signal(perm_string by_name) const; Signal* find_signal(perm_string by_name) const;
Variable* find_variable(perm_string by_name) const; Variable* find_variable(perm_string by_name) const;
Subprogram* find_subprogram(perm_string by_name) const;
protected: protected:
void cleanup(); void cleanup();
@ -66,6 +72,12 @@ class ScopeBase {
for_each(c.begin(), c.end(), ::delete_pair_second<T>()); for_each(c.begin(), c.end(), ::delete_pair_second<T>());
} }
// 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... // Signal declarations...
std::map<perm_string,Signal*> old_signals_; //previous scopes std::map<perm_string,Signal*> old_signals_; //previous scopes
std::map<perm_string,Signal*> new_signals_; //current scope std::map<perm_string,Signal*> new_signals_; //current scope
@ -76,8 +88,8 @@ class ScopeBase {
std::map<perm_string,ComponentBase*> old_components_; //previous scopes std::map<perm_string,ComponentBase*> old_components_; //previous scopes
std::map<perm_string,ComponentBase*> new_components_; //current scope std::map<perm_string,ComponentBase*> new_components_; //current scope
// Type declarations... // Type declarations...
std::map<perm_string,const VType*> old_types_; //previous scopes std::map<perm_string,const VType*> use_types_; //imported types
std::map<perm_string,const VType*> new_types_; //current scope std::map<perm_string,const VType*> cur_types_; //current types
// Constant declarations... // Constant declarations...
struct const_t { struct const_t {
~const_t() {delete typ; delete val;} ~const_t() {delete typ; delete val;}
@ -86,8 +98,11 @@ class ScopeBase {
const VType*typ; const VType*typ;
Expression*val; Expression*val;
}; };
std::map<perm_string, struct const_t*> old_constants_; //previous scopes std::map<perm_string, struct const_t*> use_constants_; //imported constants
std::map<perm_string, struct const_t*> new_constants_; //current scope std::map<perm_string, struct const_t*> cur_constants_; //current constants
std::map<perm_string, Subprogram*> use_subprograms_; //imported
std::map<perm_string, Subprogram*> cur_subprograms_; //current
void do_use_from(const ScopeBase*that); void do_use_from(const ScopeBase*that);
}; };
@ -95,7 +110,7 @@ class ScopeBase {
class Scope : public ScopeBase { class Scope : public ScopeBase {
public: public:
explicit Scope(const ScopeBase&ref); explicit Scope(const ActiveScope&ref);
~Scope(); ~Scope();
ComponentBase* find_component(perm_string by_name); ComponentBase* find_component(perm_string by_name);
@ -118,18 +133,28 @@ class Scope : public ScopeBase {
class ActiveScope : public ScopeBase { class ActiveScope : public ScopeBase {
public: public:
ActiveScope() : context_entity_(0) { } ActiveScope() : package_header_(0), context_entity_(0) { }
ActiveScope(ActiveScope*par) : ScopeBase(*par), context_entity_(0) { } ActiveScope(ActiveScope*par) : ScopeBase(*par), package_header_(0), context_entity_(0) { }
~ActiveScope() { } ~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 <pkg>::*" directive.
void use_from(const Scope*that) { do_use_from(that); }
// This function returns true if the name is a vectorable // This function returns true if the name is a vectorable
// name. The parser uses this to distinguish between function // name. The parser uses this to distinguish between function
// calls and array index operations. // calls and array index operations.
bool is_vector_name(perm_string name) const; 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 /* All bind_name function check if the given name was present
* in previous scopes. If it is found, it is erased (but the pointer * in previous scopes. If it is found, it is erased (but the pointer
* is not freed), in order to implement name shadowing. 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) void bind_name(perm_string name, const VType* t)
{ map<perm_string, const VType*>::iterator it; { map<perm_string, const VType*>::iterator it;
if((it = old_types_.find(name)) != old_types_.end() ) if((it = use_types_.find(name)) != use_types_.end() )
old_types_.erase(it); use_types_.erase(it);
new_types_[name] = t; 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) void bind_name(perm_string name, const VType*obj, Expression*val)
{ map<perm_string, const_t*>::iterator it; { map<perm_string, const_t*>::iterator it;
if((it = old_constants_.find(name)) != old_constants_.end() ) if((it = use_constants_.find(name)) != use_constants_.end() )
old_constants_.erase(it); use_constants_.erase(it);
new_constants_[name] = new const_t(obj, val); cur_constants_[name] = new const_t(obj, val);
}
inline void bind_name(perm_string name, Subprogram*obj)
{ map<perm_string, Subprogram*>::iterator it;
if((it = use_subprograms_.find(name)) != use_subprograms_.end() )
use_subprograms_.erase(it);
cur_subprograms_[name] = obj;;
} }
void bind(Entity*ent) void bind(Entity*ent)
@ -184,6 +219,10 @@ class ActiveScope : public ScopeBase {
std::map<perm_string,VTypeDef*> incomplete_types; std::map<perm_string,VTypeDef*> incomplete_types;
private: private:
// If this is a package body, then there is a Package header
// already declared.
Package*package_header_;
Entity*context_entity_; Entity*context_entity_;
}; };

View File

@ -1,7 +1,8 @@
#ifndef __sequential_H #ifndef __sequential_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -116,6 +117,7 @@ class ReturnStmt : public SequentialStmt {
~ReturnStmt(); ~ReturnStmt();
public: public:
int emit(ostream&out, Entity*entity, Architecture*arc);
void dump(ostream&out, int indent) const; void dump(ostream&out, int indent) const;
private: private:

View File

@ -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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * 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; 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) 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, start_rc);
ivl_assert(*this, finish_rc); ivl_assert(*this, finish_rc);
if (range_->is_downto() && start_val < finish_val) { if (! range_->is_downto()) {
out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl; 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; return errors;
} }
if (!range_->is_downto() && start_val > finish_val) { 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; return errors;
} }

98
vhdlpp/subprogram.cc Normal file
View File

@ -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<InterfacePort*>*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<SequentialStmt*>*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<InterfacePort*>::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;
}

65
vhdlpp/subprogram.h Normal file
View File

@ -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 <iostream>
# include <list>
class InterfacePort;
class ScopeBase;
class SequentialStmt;
class VType;
class Subprogram : public LineInfo {
public:
Subprogram(perm_string name, std::list<InterfacePort*>*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<SequentialStmt*>*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<InterfacePort*>*ports_;
const VType*return_type_;
std::list<SequentialStmt*>*statements_;
};
#endif

79
vhdlpp/subprogram_emit.cc Normal file
View File

@ -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 <iostream>
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<InterfacePort*>::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<SequentialStmt*>::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;
}

View File

@ -32,7 +32,7 @@ VType::~VType()
void VType::show(ostream&out) const void VType::show(ostream&out) const
{ {
out << typeid(*this).name(); write_to_stream(out);
} }
VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt) VTypePrimitive::VTypePrimitive(VTypePrimitive::type_t tt)
@ -53,6 +53,9 @@ void VTypePrimitive::show(ostream&out) const
case BIT: case BIT:
out << "BIT"; out << "BIT";
break; break;
case CHARACTER:
out << "CHARACTER";
break;
case INTEGER: case INTEGER:
out << "INTEGER"; out << "INTEGER";
break; break;

View File

@ -1,7 +1,8 @@
#ifndef __vtype_H #ifndef __vtype_H
#define __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 * This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU * and/or modify it in source code form under the terms of the GNU
@ -27,6 +28,8 @@
# include <inttypes.h> # include <inttypes.h>
# include "StringHeap.h" # include "StringHeap.h"
class Architecture;
class Entity;
class Expression; class Expression;
class prange_t; class prange_t;
class VTypeDef; class VTypeDef;
@ -45,6 +48,15 @@ class VType {
VType() { } VType() { }
virtual ~VType() =0; 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 // This virtual method writes a VHDL-accurate representation
// of this type to the designated stream. This is used for // of this type to the designated stream. This is used for
// writing parsed types to library files. // writing parsed types to library files.
@ -112,7 +124,7 @@ class VTypeERROR : public VType {
class VTypePrimitive : public VType { class VTypePrimitive : public VType {
public: public:
enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC }; enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC, CHARACTER };
public: public:
VTypePrimitive(type_t); VTypePrimitive(type_t);
@ -134,6 +146,7 @@ extern const VTypePrimitive* primitive_BOOLEAN;
extern const VTypePrimitive* primitive_BIT; extern const VTypePrimitive* primitive_BIT;
extern const VTypePrimitive* primitive_INTEGER; extern const VTypePrimitive* primitive_INTEGER;
extern const VTypePrimitive* primitive_STDLOGIC; extern const VTypePrimitive* primitive_STDLOGIC;
extern const VTypePrimitive* primitive_CHARACTER;
/* /*
* An array is a compound N-dimensional array of element type. The * 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<prange_t*>*r, bool signed_vector =false); VTypeArray(const VType*etype, std::list<prange_t*>*r, bool signed_vector =false);
~VTypeArray(); ~VTypeArray();
int elaborate(Entity*ent, Architecture*arc) const;
void write_to_stream(std::ostream&fd) const; void write_to_stream(std::ostream&fd) const;
void show(std::ostream&) 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(const VType*base, int64_t max_val, int64_t min_val);
~VTypeRange(); ~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; void write_to_stream(std::ostream&fd) const;
int emit_def(std::ostream&out) const; int emit_def(std::ostream&out) const;

45
vhdlpp/vtype_elaborate.cc Normal file
View File

@ -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<range_t>::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;
}

View File

@ -88,9 +88,15 @@ int VTypeArray::emit_def(ostream&out) const
cur = dims.front(); cur = dims.front();
dims.pop_front(); dims.pop_front();
out << "["; 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 << ":"; 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 << "]"; out << "]";
} }
@ -130,6 +136,9 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
case INTEGER: case INTEGER:
out << "bool [31:0]"; out << "bool [31:0]";
break; break;
case CHARACTER:
out << "char";
break;
default: default:
assert(0); assert(0);
break; break;

26
vhdlpp/vtype_match.cc Normal file
View File

@ -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;
}

View File

@ -17,9 +17,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
# define __STDC_LIMIT_MACROS
# include "vtype.h" # include "vtype.h"
# include "expression.h" # include "expression.h"
# include <typeinfo> # include <typeinfo>
# include <stdint.h>
# include <cassert> # include <cassert>
using namespace std; using namespace std;
@ -115,6 +117,15 @@ void VTypePrimitive::write_to_stream(ostream&fd) const
void VTypeRange::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<const VTypePrimitive*> (base_)) {
if (min_==0 && max_==INT64_MAX && tmp->type()==VTypePrimitive::INTEGER) {
fd << "natural";
return;
}
}
base_->write_to_stream(fd); base_->write_to_stream(fd);
fd << " range " << min_ << " to " << max_; fd << " range " << min_ << " to " << max_;
} }

View File

@ -141,6 +141,56 @@ template <class T> class property_atom : public class_property_t {
void copy(char*dst, char*src); 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<vvp_vector2_t*>(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<vvp_vector4_t*>(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 T> class property_real : public class_property_t { template <class T> class property_real : public class_property_t {
public: public:
inline explicit property_real(void) { } inline explicit property_real(void) { }
@ -234,6 +284,44 @@ template <class T> void property_atom<T>::copy(char*dst, char*src)
*dst_obj = *src_obj; *dst_obj = *src_obj;
} }
void property_bit::set_vec4(char*buf, const vvp_vector4_t&val)
{
vvp_vector2_t*obj = reinterpret_cast<vvp_vector2_t*> (buf+offset_);
*obj = val;
}
void property_bit::get_vec4(char*buf, vvp_vector4_t&val)
{
vvp_vector2_t*obj = reinterpret_cast<vvp_vector2_t*> (buf+offset_);
val = vector2_to_vector4(*obj, obj->size());
}
void property_bit::copy(char*dst, char*src)
{
vvp_vector2_t*dst_obj = reinterpret_cast<vvp_vector2_t*> (dst+offset_);
vvp_vector2_t*src_obj = reinterpret_cast<vvp_vector2_t*> (src+offset_);
*dst_obj = *src_obj;
}
void property_logic::set_vec4(char*buf, const vvp_vector4_t&val)
{
vvp_vector4_t*obj = reinterpret_cast<vvp_vector4_t*> (buf+offset_);
*obj = val;
}
void property_logic::get_vec4(char*buf, vvp_vector4_t&val)
{
vvp_vector4_t*obj = reinterpret_cast<vvp_vector4_t*> (buf+offset_);
val = *obj;
}
void property_logic::copy(char*dst, char*src)
{
vvp_vector4_t*dst_obj = reinterpret_cast<vvp_vector4_t*> (dst+offset_);
vvp_vector4_t*src_obj = reinterpret_cast<vvp_vector4_t*> (src+offset_);
*dst_obj = *src_obj;
}
template <class T> void property_real<T>::set_real(char*buf, double val) template <class T> void property_real<T>::set_real(char*buf, double val)
{ {
T*tmp = reinterpret_cast<T*>(buf+offset_); T*tmp = reinterpret_cast<T*>(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; properties_[idx].type = new property_string;
else if (type == "o") else if (type == "o")
properties_[idx].type = new property_object; 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; properties_[idx].type = 0;
}
} }
void class_type::finish_setup(void) void class_type::finish_setup(void)