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,8 +387,8 @@ 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_*,

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,9 +419,11 @@ 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,
const Module::replace_t&replacements) const Module::replace_t&replacements)

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;
@ -150,6 +172,7 @@ void Scope::dump_scope(ostream&out) const
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_generics(out);
cur->second->dump_ports(out); cur->second->dump_ports(out);
out << " end component " << cur->first << endl; 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;
@ -271,15 +282,13 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
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

@ -229,6 +229,13 @@ int main(int argc, char*argv[])
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,6 +34,7 @@
# include "architec.h" # include "architec.h"
# include "expression.h" # include "expression.h"
# include "sequential.h" # include "sequential.h"
# include "subprogram.h"
# include "package.h" # include "package.h"
# include "vsignal.h" # include "vsignal.h"
# include "vtype.h" # include "vtype.h"
@ -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,7 +67,7 @@ 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*/ ,
@ -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()
@ -153,29 +183,44 @@ void ScopeBase::do_use_from(const ScopeBase*that)
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
@ -25,10 +26,14 @@
# include "StringHeap.h" # include "StringHeap.h"
# include "entity.h" # include "entity.h"
# include "expression.h" # include "expression.h"
# include "subprogram.h"
# include "vsignal.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 << "[";
if (cur->dimension(0).msb())
errors += cur->dimension(0).msb()->emit(out, 0, 0); errors += cur->dimension(0).msb()->emit(out, 0, 0);
else
out << "?error?";
out << ":"; out << ":";
if (cur->dimension(0).lsb())
errors += cur->dimension(0).lsb()->emit(out, 0, 0); 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,9 +414,16 @@ 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)
{ {