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

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

View File

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

View File

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

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

View File

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

View File

@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
{
perm_string name = peek_tail_name(path_);
if (name=="$ivlh_to_unsigned") {
ivl_assert(*this, parms_.size() == 2);
// The Icarus Verilog specific $ivl_unsigned() system
// task takes a second argument which is the output
// size. This can be an arbitrary constant function.
PExpr*pexpr = parms_[1];
if (pexpr == 0) {
cerr << get_fileline() << ": error: "
<< "Missing $ivlh_to_unsigned width." << endl;
return 0;
}
NetExpr*nexpr = elab_and_eval(des, scope, pexpr, -1, true);
if (nexpr == 0) {
cerr << get_fileline() << ": error: "
<< "Unable to evaluate " << name
<< " width argument: " << *pexpr << endl;
return 0;
}
long value = 0;
bool rc = eval_as_long(value, nexpr);
ivl_assert(*this, rc && value>=0);
expr_width_ = value;
signed_flag_= false;
return expr_width_;
}
if (name=="$signed" || name=="$unsigned") {
PExpr*expr = parms_[0];
if (expr == 0)
@ -1135,7 +1164,11 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
}
const netclass_t* class_type = net->class_type();
member_type = class_type->get_property(member_name);
int midx = class_type->property_idx_from_name(member_name);
if (midx >= 0)
member_type = class_type->get_prop_type(midx);
else
member_type = 0;
use_path = tmp_path;
use_darray = dynamic_cast<const netdarray_t*> (member_type);
@ -1228,6 +1261,19 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope,
{
perm_string name = peek_tail_name(path_);
/* Catch the special case that the system function is the
$ivl_unsigned function. In this case the second argument is
the size of the expression, but should already be accounted
for so treat this very much like the $unsigned() function. */
if (name=="$ivlh_to_unsigned") {
ivl_assert(*this, parms_.size()==2);
PExpr*expr = parms_[0];
ivl_assert(*this, expr);
NetExpr*sub = expr->elaborate_expr(des, scope, expr_width_, flags);
return cast_to_width_(sub, expr_wid);
}
/* Catch the special case that the system function is the $signed
function. Its argument will be evaluated as a self-determined
expression. */
@ -1755,15 +1801,25 @@ static NetExpr* check_for_struct_members(const LineInfo*li,
return sel;
}
static NetExpr* class_static_property_expression(const LineInfo*li,
const netclass_t*class_type,
perm_string name)
{
NetNet*sig = class_type->find_static_property(name);
ivl_assert(*li, sig);
NetESignal*expr = new NetESignal(sig);
expr->set_line(*li);
return expr;
}
static NetExpr* check_for_class_property(const LineInfo*li,
Design*des, NetScope*,
Design*des, NetScope*scope,
NetNet*net,
const name_component_t&comp)
{
const netclass_t*class_type = net->class_type();
const ivl_type_s*ptype = class_type->get_property(comp.name);
if (ptype == 0) {
int pidx = class_type->property_idx_from_name(comp.name);
if (pidx < 0) {
cerr << li->get_fileline() << ": error: "
<< "Class " << class_type->get_name()
<< " has no property " << comp.name << "." << endl;
@ -1771,6 +1827,29 @@ static NetExpr* check_for_class_property(const LineInfo*li,
return 0;
}
if (debug_elaborate) {
cerr << li->get_fileline() << ": check_for_class_property: "
<< "Property " << comp.name
<< " of net " << net->name()
<< ", context scope=" << scope_path(scope)
<< endl;
}
property_qualifier_t qual = class_type->get_prop_qual(pidx);
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
cerr << li->get_fileline() << ": error: "
<< "Local property " << class_type->get_prop_name(pidx)
<< " is not accessible in this context."
<< " (scope=" << scope_path(scope) << ")" << endl;
des->errors += 1;
}
if (qual.test_static()) {
perm_string prop_name = lex_strings.make(class_type->get_prop_name(pidx));
return class_static_property_expression(li, class_type,
prop_name);
}
NetEProperty*tmp = new NetEProperty(net, comp.name);
tmp->set_line(*li);
return tmp;
@ -1881,6 +1960,23 @@ NetExpr* PECallFunction::elaborate_base_(Design*des, NetScope*scope, NetScope*ds
bool need_const = NEED_CONST & flags;
// If this is a constant expression, it is possible that we
// are being elaborated before the function definition. If
// that's the case, try to elaborate the function as a const
// function.
if (need_const && ! def->proc()) {
if (debug_elaborate) {
cerr << get_fileline() << ": PECallFunction::elaborate_base_: "
<< "Try to elaborate " << scope_path(dscope)
<< " as constant function." << endl;
}
dscope->set_elab_stage(2);
dscope->need_const_func(true);
const PFunction*pfunc = dscope->func_pform();
ivl_assert(*this, pfunc);
pfunc->elaborate(des, dscope);
}
unsigned parms_count = parms_.size();
if ((parms_count == 1) && (parms_[0] == 0))
parms_count = 0;
@ -2012,6 +2108,12 @@ NetExpr* PECallFunction::elaborate_expr_method_(Design*des, NetScope*scope,
perm_string method_name = peek_tail_name(use_path);
use_path.pop_back();
// If there is no object to the left of the method name, then
// give up on the idea of looking for an object method.
if (use_path.empty()) {
return 0;
}
NetNet *net = 0;
const NetExpr *par;
NetEvent *eve;
@ -2715,8 +2817,9 @@ unsigned PEIdent::test_width(Design*des, NetScope*scope, width_mode_t&mode)
}
if (const netclass_t*class_type = net->class_type()) {
const ivl_type_s*ptype = class_type->get_property(method_name);
if (ptype) {
int pidx = class_type->property_idx_from_name(method_name);
if (pidx >= 0) {
ivl_type_t ptype = class_type->get_prop_type(pidx);
expr_type_ = ptype->base_type();
expr_width_ = ptype->packed_width();
min_width_ = expr_width_;
@ -2823,7 +2926,7 @@ NetExpr* PEIdent::elaborate_expr(Design*des, NetScope*scope,
* not a method, or the name is not in the parent class, then
* fail. Otherwise, return a NetEProperty.
*/
NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope,
NetExpr* PEIdent::elaborate_expr_class_member_(Design*des, NetScope*scope,
unsigned, unsigned) const
{
if (!gn_system_verilog())
@ -2854,9 +2957,23 @@ NetExpr* PEIdent::elaborate_expr_class_member_(Design*, NetScope*scope,
cerr << get_fileline() << ": PEIdent::elaborate_expr_class_member: "
<< "Found member " << member_name
<< " is a member of class " << class_type->get_name()
<< ", context scope=" << scope_path(scope)
<< ", so synthesizing a NetEProperty." << endl;
}
property_qualifier_t qual = class_type->get_prop_qual(pidx);
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
cerr << get_fileline() << ": error: "
<< "Local property " << class_type->get_prop_name(pidx)
<< " is not accessible in this context."
<< " (scope=" << scope_path(scope) << ")" << endl;
des->errors += 1;
}
if (qual.test_static()) {
return class_static_property_expression(this, class_type, member_name);
}
NetEProperty*tmp = new NetEProperty(this_net, member_name);
tmp->set_line(*this);
return tmp;
@ -4464,13 +4581,35 @@ unsigned PENewClass::test_width(Design*, NetScope*, width_mode_t&)
NetExpr* PENewClass::elaborate_expr(Design*des, NetScope*scope,
ivl_type_t ntype, unsigned) const
{
NetENew*obj = new NetENew(ntype);
NetExpr*obj = new NetENew(ntype);
obj->set_line(*this);
// Find the constructor for the class. If there is no
// constructor then the result of this expression is the
// allocation alone.
const netclass_t*ctype = dynamic_cast<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"));
if (new_scope == 0) {
// No constructor.

View File

@ -256,8 +256,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
}
if (reg->class_type() && !method_name.nil() && gn_system_verilog()) {
NetAssign_*lv = new NetAssign_(reg);
elaborate_lval_net_class_member_(des, use_scope, lv, method_name);
NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, method_name);
return lv;
}
@ -316,7 +315,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
return lv;
}
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
NetScope*scope) const
{
if (!gn_system_verilog())
@ -343,6 +342,40 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
return 0;
}
// Detect assignment to constant properties. Note that the
// initializer constructor MAY assign to constant properties,
// as this is how the property gets its value.
property_qualifier_t qual = class_type->get_prop_qual(pidx);
if (qual.test_const()) {
if (class_type->get_prop_initialized(pidx)) {
cerr << get_fileline() << ": error: "
<< "Property " << class_type->get_prop_name(pidx)
<< " is constant in this method."
<< " (scope=" << scope_path(scope) << ")" << endl;
des->errors += 1;
} else if (scope->basename()!="new" && scope->basename()!="new@") {
cerr << get_fileline() << ": error: "
<< "Property " << class_type->get_prop_name(pidx)
<< " is constant in this method."
<< " (scope=" << scope_path(scope) << ")" << endl;
des->errors += 1;
} else {
// Mark this property as initilized. This is used
// to know that we have initialized the constant
// object so the next assignment will be marked as
// illegal.
class_type->set_prop_initialized(pidx);
if (debug_elaborate) {
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
<< "Found initilzers for property " << class_type->get_prop_name(pidx) << endl;
}
}
}
NetAssign_*this_lval = new NetAssign_(this_net);
this_lval->set_property(member_name);
@ -812,31 +845,58 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
return true;
}
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*,
NetAssign_*lv,
const perm_string&method_name) const
NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
NetNet*sig, const perm_string&method_name) const
{
if (debug_elaborate) {
cerr << get_fileline() << ": elaborate_lval_net_class_member_: "
<< "l-value is property " << method_name
<< " of " << lv->sig()->name() << "." << endl;
<< " of " << sig->name() << "." << endl;
}
const netclass_t*class_type = lv->sig()->class_type();
const netclass_t*class_type = sig->class_type();
ivl_assert(*this, class_type);
/* Make sure the property is really present in the class. If
not, then generate an error message and return an error. */
ivl_type_t ptype = class_type->get_property(method_name);
if (ptype == 0) {
int pidx = class_type->property_idx_from_name(method_name);
if (pidx < 0) {
cerr << get_fileline() << ": error: Class " << class_type->get_name()
<< " does not have a property " << method_name << "." << endl;
des->errors += 1;
return false;
return 0;
}
property_qualifier_t qual = class_type->get_prop_qual(pidx);
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
cerr << get_fileline() << ": error: "
<< "Local property " << class_type->get_prop_name(pidx)
<< " is not accessible (l-value) in this context."
<< " (scope=" << scope_path(scope) << ")" << endl;
des->errors += 1;
} else if (qual.test_static()) {
// Special case: this is a static property. Ignore the
// "this" sig and use the property itself, which is not
// part of the sig, as the l-value.
NetNet*psig = class_type->find_static_property(method_name);
ivl_assert(*this, psig);
NetAssign_*lv = new NetAssign_(psig);
return lv;
} else if (qual.test_const()) {
cerr << get_fileline() << ": error: "
<< "Property " << class_type->get_prop_name(pidx)
<< " is constant in this context." << endl;
des->errors += 1;
}
NetAssign_*lv = new NetAssign_(sig);
lv->set_property(method_name);
ivl_type_t ptype = class_type->get_prop_type(pidx);
const netdarray_t*mtype = dynamic_cast<const netdarray_t*> (ptype);
if (mtype) {
const name_component_t&name_tail = path_.back();
@ -848,7 +908,7 @@ bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*,
}
}
return true;
return lv;
}

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;
netclass_t*use_class = new netclass_t(use_type->name);
@ -314,15 +366,15 @@ static void elaborate_scope_class(Design*des, NetScope*scope,
// Collect the properties, elaborate them, and add them to the
// elaborated class definition.
for (map<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) {
if (debug_scopes) {
cerr << pclass->get_fileline() << ": elaborate_scope_class: "
<< " Property " << cur->first << endl;
}
ivl_type_s*tmp = cur->second->elaborate_type(des, scope);
ivl_type_s*tmp = cur->second.type->elaborate_type(des, scope);
ivl_assert(*pclass, tmp);
use_class->set_property(cur->first, tmp);
use_class->set_property(cur->first, cur->second.qual, tmp);
}
for (map<perm_string,PTask*>::iterator cur = pclass->tasks.begin()
@ -367,8 +419,10 @@ static void elaborate_scope_class(Design*des, NetScope*scope,
static void elaborate_scope_classes(Design*des, NetScope*scope,
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]);
}
}
static void replace_scope_parameters_(NetScope*scope, const LineInfo&loc,

View File

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

View File

@ -2361,11 +2361,17 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
return cur;
}
/*
* Assignments within program blocks can only write to certain types
* of variables. We can only write to:
* - variables in a program block
* - static properties of a class
*/
static bool lval_not_program_variable(const NetAssign_*lv)
{
while (lv) {
NetScope*sig_scope = lv->sig()->scope();
if (! sig_scope->program_block())
if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS)
return true;
lv = lv->more;
@ -2793,14 +2799,6 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
if (nscope->calls_sys_task())
scope->calls_sys_task(true);
if (!wires.empty()) {
if (scope->need_const_func()) {
cerr << get_fileline() << ": sorry: Block variables inside "
"a constant function are not yet supported." << endl;
}
scope->is_const_func(false);
}
cur->set_line(*this);
return cur;
}
@ -4445,6 +4443,69 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
return proc;
}
NetProc* PReturn::elaborate(Design*des, NetScope*scope) const
{
NetScope*target = scope;
for (;;) {
if (target == 0) {
cerr << get_fileline() << ": error: "
<< "Return statement is not in a function." << endl;
des->errors += 1;
return 0;
}
if (target->type() == NetScope::FUNC)
break;
if (target->type() == NetScope::TASK) {
cerr << get_fileline() << ": error: "
<< "Cannot \"return\" from tasks." << endl;
des->errors += 1;
return 0;
}
if (target->type()==NetScope::BEGIN_END) {
target = target->parent();
continue;
}
cerr << get_fileline() << ": error: "
<< "Cannot \"return\" from this scope: " << scope_path(target) << endl;
des->errors += 1;
return 0;
}
// We don't yet support void functions, so require an
// expression for the return statement.
if (expr_ == 0) {
cerr << get_fileline() << ": error: "
<< "Return from " << scope_path(target)
<< " requires a return value expression." << endl;
des->errors += 1;
return 0;
}
NetNet*res = target->find_signal(target->basename());
ivl_variable_type_t lv_type = res->data_type();
unsigned long wid = res->vector_width();
NetAssign_*lv = new NetAssign_(res);
NetExpr*val = elaborate_rval_expr(des, scope, lv_type, wid, expr_);
NetBlock*proc = new NetBlock(NetBlock::SEQU, 0);
proc->set_line( *this );
NetAssign*assn = new NetAssign(lv, val);
assn->set_line( *this );
proc->append(assn);
NetDisable*disa = new NetDisable(target);
disa->set_line( *this );
proc->append( disa );
return proc;
}
/*
* A task definition is elaborated by elaborating the statement that
* it contains, and connecting its ports to NetNet objects. The
@ -4883,6 +4944,13 @@ static void elaborate_classes(Design*des, NetScope*scope,
; cur != classes.end() ; ++ cur) {
netclass_t*use_class = scope->find_class(cur->second->pscope_name());
use_class->elaborate(des, cur->second);
if (use_class->test_for_missing_initializers()) {
cerr << cur->second->get_fileline() << ": error: "
<< "Const properties of class " << use_class->get_name()
<< " are missing initialization." << endl;
des->errors += 1;
}
}
}
@ -4962,6 +5030,19 @@ bool Module::elaborate(Design*des, NetScope*scope) const
*/
void netclass_t::elaborate(Design*des, PClass*pclass)
{
if (! pclass->type->initialize_static.empty()) {
std::vector<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()
; cur != pclass->funcs.end() ; ++ cur) {
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)
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;
verinum lv = l->value();

View File

@ -367,6 +367,13 @@ TU [munpf]
\\[^ \t\b\f\r\n]+ {
yylval.text = strdupnew(yytext+1);
if (gn_system_verilog()) {
if (PPackage*pkg = pform_test_package_identifier(yylval.text)) {
delete[]yylval.text;
yylval.package = pkg;
return PACKAGE_IDENTIFIER;
}
}
if (gn_system_verilog()) {
if (data_type_t*type = pform_test_type_identifier(yylval.text)) {
delete[]yylval.text;

View File

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

View File

@ -60,7 +60,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
map<perm_string,LocalVar>context_map;
if (debug_eval_tree) {
cerr << loc.get_fileline() << ": debug: "
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "Evaluate function " << scope_->basename() << endl;
}
@ -78,7 +78,7 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<Net
input_var.value = fix_assign_value(ports_[idx], args[idx]);
if (debug_eval_tree) {
cerr << loc.get_fileline() << ": debug: "
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< " 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.
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
// when compiling the function definition, we may not have
// a valid statement.
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...
ptr = context_map.find(scope_->basename());
NetExpr*res = ptr->second.value;
@ -112,9 +123,32 @@ NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector<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.
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;
}
if (debug_eval_tree) {
cerr << loc.get_fileline() << ": NetFuncDef::evaluate_function: "
<< "Evaluation failed." << endl;
}
delete res;
return 0;
@ -181,9 +215,15 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
map<perm_string,LocalVar>::iterator ptr = context_map.find(lval->name());
ivl_assert(*this, ptr != context_map.end());
LocalVar*var = & ptr->second;
while (var->nwords == -1) {
assert(var->ref);
var = var->ref;
}
NetExpr*old_lval;
unsigned word = 0;
if (ptr->second.nwords > 0) {
int word = 0;
if (var->nwords > 0) {
NetExpr*word_result = lval->word()->evaluate_function(loc, context_map);
if (word_result == 0) {
delete rval_result;
@ -198,12 +238,13 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
word = word_const->value().as_long();
if (word >= ptr->second.nwords)
if (word >= var->nwords)
return true;
old_lval = ptr->second.array[word];
old_lval = var->array[word];
} else {
old_lval = ptr->second.value;
assert(var->nwords == 0);
old_lval = var->value;
}
if (const NetExpr*base_expr = lval->get_base()) {
@ -245,15 +286,16 @@ bool NetAssign::eval_func_lval_(const LineInfo&loc,
delete old_lval;
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: "
<< "NetAssign::evaluate_function: " << lval->name()
<< " = " << *rval_result << endl;
cerr << get_fileline() << ": NetAssign::evaluate_function: "
<< lval->name() << " = " << *rval_result << endl;
}
if (ptr->second.nwords > 0)
ptr->second.array[word] = rval_result;
else
ptr->second.value = rval_result;
if (var->nwords > 0) {
var->array[word] = rval_result;
} else {
assert(var->nwords == 0);
var->value = rval_result;
}
return true;
}
@ -303,16 +345,56 @@ bool NetAssign::evaluate_function(const LineInfo&loc,
bool NetBlock::evaluate_function(const LineInfo&loc,
map<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;
NetProc*cur = last_;
if (cur == 0) return true;
do {
cur = cur->next_;
bool cur_flag = cur->evaluate_function(loc, context_map);
if (debug_eval_tree) {
cerr << get_fileline() << ": NetBlock::evaluate_function: "
<< "Execute statement (" << typeid(*cur).name()
<< ") at " << cur->get_fileline() << "." << endl;
}
bool cur_flag = cur->evaluate_function(loc, use_context_map);
flag = flag && cur_flag;
} while (cur != last_ && !disable);
if (debug_eval_tree) {
cerr << get_fileline() << ": NetBlock::evaluate_function: "
<< "subscope_=" << subscope_
<< ", disable=" << disable
<< ", flag=" << (flag?"true":"false") << endl;
}
if (disable == subscope_) disable = 0;
return flag;
@ -437,8 +519,13 @@ bool NetCondit::evaluate_function(const LineInfo&loc,
map<perm_string,LocalVar>&context_map) const
{
NetExpr*cond = expr_->evaluate_function(loc, context_map);
if (cond == 0)
if (cond == 0) {
if (debug_eval_tree) {
cerr << get_fileline() << ": NetCondit::evaluate_function: "
<< "Unable to evaluate condition (" << *expr_ <<")" << endl;
}
return false;
}
NetEConst*cond_const = dynamic_cast<NetEConst*> (cond);
ivl_assert(loc, cond_const);
@ -446,18 +533,32 @@ bool NetCondit::evaluate_function(const LineInfo&loc,
long val = cond_const->value().as_long();
delete cond;
bool flag;
if (val)
// The condition is true, so evaluate the if clause
return (if_ == 0) || if_->evaluate_function(loc, context_map);
flag = (if_ == 0) || if_->evaluate_function(loc, context_map);
else
// The condition is false, so evaluate the else clause
return (else_ == 0) || else_->evaluate_function(loc, context_map);
flag = (else_ == 0) || else_->evaluate_function(loc, context_map);
if (debug_eval_tree) {
cerr << get_fileline() << ": NetCondit::evaluate_function: "
<< "Finished, flag=" << (flag?"true":"false") << endl;
}
return flag;
}
bool NetDisable::evaluate_function(const LineInfo&,
map<perm_string,LocalVar>&) const
{
disable = target_;
if (debug_eval_tree) {
cerr << get_fileline() << ": NetDisable::evaluate_function: "
<< "disable " << scope_path(disable) << endl;
}
return true;
}
@ -530,7 +631,7 @@ bool NetWhile::evaluate_function(const LineInfo&loc,
bool flag = true;
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: NetWhile::evaluate_function: "
cerr << get_fileline() << ": NetWhile::evaluate_function: "
<< "Start loop" << endl;
}
@ -561,8 +662,8 @@ bool NetWhile::evaluate_function(const LineInfo&loc,
}
if (debug_eval_tree) {
cerr << get_fileline() << ": debug: NetWhile::evaluate_function: "
<< "Done loop" << endl;
cerr << get_fileline() << ": NetWhile::evaluate_function: "
<< "Done loop, flag=" << (flag?"true":"false") << endl;
}
return flag;
@ -674,8 +775,15 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
return 0;
}
// Follow indirect references to the actual variable.
LocalVar*var = & ptr->second;
while (var->nwords == -1) {
assert(var->ref);
var = var->ref;
}
NetExpr*value = 0;
if (ptr->second.nwords > 0) {
if (var->nwords > 0) {
ivl_assert(loc, word_);
NetExpr*word_result = word_->evaluate_function(loc, context_map);
if (word_result == 0)
@ -684,12 +792,12 @@ NetExpr* NetESignal::evaluate_function(const LineInfo&loc,
NetEConst*word_const = dynamic_cast<NetEConst*>(word_result);
ivl_assert(loc, word_const);
unsigned word = word_const->value().as_long();
int word = word_const->value().as_long();
if (word_const->value().is_defined() && (word < ptr->second.nwords))
value = ptr->second.array[word];
if (word_const->value().is_defined() && (word < var->nwords))
value = var->array[word];
} else {
value = ptr->second.value;
value = var->value;
}
if (value == 0) {

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;
cur = properties_.find(pname);
@ -41,7 +41,9 @@ bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype)
prop_t tmp;
tmp.name = pname;
tmp.qual = qual;
tmp.type = ptype;
tmp.initialized_flag = false;
property_table_.push_back(tmp);
properties_[pname] = property_table_.size()-1;
@ -59,17 +61,6 @@ ivl_variable_type_t netclass_t::base_type() const
return IVL_VT_CLASS;
}
const ivl_type_s* netclass_t::get_property(perm_string pname) const
{
map<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
{
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;
}
property_qualifier_t netclass_t::get_prop_qual(size_t idx) const
{
assert(idx < property_table_.size());
return property_table_[idx].qual;
}
ivl_type_t netclass_t::get_prop_type(size_t idx) const
{
assert(idx < property_table_.size());
return property_table_[idx].type;
}
bool netclass_t::get_prop_initialized(size_t idx) const
{
assert(idx < property_table_.size());
return property_table_[idx].initialized_flag;
}
void netclass_t::set_prop_initialized(size_t idx) const
{
assert(idx < property_table_.size());
assert(! property_table_[idx].initialized_flag);
property_table_[idx].initialized_flag = true;
}
bool netclass_t::test_for_missing_initializers() const
{
for (size_t idx = 0 ; idx < property_table_.size() ; idx += 1) {
if (property_table_[idx].initialized_flag)
continue;
if (property_table_[idx].qual.test_const())
return true;
}
return false;
}
NetScope*netclass_t::method_from_name(perm_string name) const
{
NetScope*task = class_scope_->child( hname_t(name) );
@ -99,3 +121,21 @@ NetScope*netclass_t::method_from_name(perm_string name) const
return task;
}
NetNet* netclass_t::find_static_property(perm_string name) const
{
NetNet*tmp = class_scope_->find_signal(name);
return tmp;
}
bool netclass_t::test_scope_is_method(const NetScope*scope) const
{
while (scope && scope != class_scope_) {
scope = scope->parent();
}
if (scope == 0)
return false;
else
return true;
}

View File

@ -22,10 +22,12 @@
# include "LineInfo.h"
# include "ivl_target.h"
# include "nettypes.h"
# include "property_qual.h"
# include <iostream>
# include <map>
class Design;
class NetNet;
class NetScope;
class PClass;
@ -37,7 +39,7 @@ class netclass_t : public ivl_type_s {
// Set the property of the class during elaboration. Set the
// name and type, and return true. If the name is already
// present, then return false.
bool set_property(perm_string pname, ivl_type_s*ptype);
bool set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype);
// Set the scope for the class. The scope has no parents and
// is used for the elaboration of methods (tasks/functions).
@ -50,17 +52,37 @@ class netclass_t : public ivl_type_s {
// This is the name of the class type
inline perm_string get_name() const { return name_; }
const ivl_type_s* get_property(perm_string pname) const;
inline size_t get_properties(void) const { return properties_.size(); }
// Get information about each property.
const char*get_prop_name(size_t idx) const;
property_qualifier_t get_prop_qual(size_t idx) const;
ivl_type_t get_prop_type(size_t idx) const;
// These methods are used by the elaborator to note the
// initializer for constant properties. Properties start out
// as not initialized, and when elaboration detects an
// assignment to the property, it is marked initialized.
bool get_prop_initialized(size_t idx) const;
void set_prop_initialized(size_t idx) const;
bool test_for_missing_initializers(void) const;
// Map the name of a property to its index.
int property_idx_from_name(perm_string pname) const;
// The task method scopes from the method name.
NetScope*method_from_name(perm_string mname) const;
// Find the elaborated signal (NetNet) for a static
// property. Search by name. The signal is created by the
// elaborate_sig pass.
NetNet*find_static_property(perm_string name) const;
// Test if this scope is a method within the class. This is
// used to check scope for handling data protection keywords
// "local" and "protected".
bool test_scope_is_method(const NetScope*scope) const;
void elaborate_sig(Design*des, PClass*pclass);
void elaborate(Design*des, PClass*pclass);
@ -75,7 +97,9 @@ class netclass_t : public ivl_type_s {
// Vector of properties.
struct prop_t {
perm_string name;
property_qualifier_t qual;
ivl_type_s* type;
mutable bool initialized_flag;
};
std::vector<prop_t> property_table_;

View File

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

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

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_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,
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
* and/or modify it in source code form under the terms of the GNU
@ -177,13 +177,23 @@ void class_type_t::pform_dump(ostream&out, unsigned indent) const
{
out << setw(indent) << "" << "class " << name << " {";
for (map<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) {
out << " " << cur->first;
}
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
{
out << setw(indent) << "" << type;
@ -928,6 +938,13 @@ void PRepeat::dump(ostream&out, unsigned ind) const
statement_->dump(out, ind+3);
}
void PReturn::dump(ostream&fd, unsigned ind) const
{
fd << setw(ind) << "" << "return (";
if (expr_) fd << *expr_;
fd << ")" << endl;
}
void PTask::dump(ostream&out, unsigned ind) const
{
out << setw(ind) << "" << "task ";
@ -1315,6 +1332,7 @@ void PClass::dump(ostream&out, unsigned indent) const
{
out << setw(indent) << "" << "class " << type->name << ";" << endl;
type->pform_dump(out, indent+2);
type->pform_dump_init(out, indent+2);
dump_tasks_(out, indent+2);
dump_funcs_(out, indent+2);
out << setw(indent) << "" << "endclass" << endl;

View File

@ -41,15 +41,6 @@ void pform_class_property(const struct vlltype&loc,
{
assert(pform_cur_class);
if (property_qual.test_static()) {
// I think the thing to do with static properties is to
// make them PWires directly in the PClass scope. They
// are wires like program/modules wires, and not
// instance members.
VLerror(loc, "sorry: static class properties not implemented.");
return;
}
// Add the non-static properties to the class type
// object. Unwind the list of names to make a map of name to
// type.
@ -64,11 +55,20 @@ void pform_class_property(const struct vlltype&loc,
use_type = new uarray_type_t(use_type, pd);
}
if (curp->expr.get()) {
VLerror(loc, "sorry: Initialization expressions for properties not implemented.");
}
pform_cur_class->type->properties[curp->name]
= class_type_t::prop_info_t(property_qual,use_type);
pform_cur_class->type->properties[curp->name] = use_type;
if (PExpr*rval = curp->expr.release()) {
PExpr*lval = new PEIdent(curp->name);
FILE_NAME(lval, loc);
PAssign*tmp = new PAssign(lval, rval);
FILE_NAME(tmp, loc);
if (property_qual.test_static())
pform_cur_class->type->initialize_static.push_back(tmp);
else
pform_cur_class->type->initialize.push_back(tmp);
}
}
}
@ -107,9 +107,29 @@ PFunction*pform_push_constructor_scope(const struct vlltype&loc)
return func;
}
void pform_end_class_declaration(void)
void pform_end_class_declaration(const struct vlltype&loc)
{
assert(pform_cur_class);
// If there were initializer statements, then collect them
// into an implicit constructor function.
if (! pform_cur_class->type->initialize.empty()) {
PFunction*func = pform_push_function_scope(loc, "new@", true);
func->set_ports(0);
pform_set_constructor_return(func);
pform_set_this_class(loc, func);
class_type_t*use_class = pform_cur_class->type;
if (use_class->initialize.size() == 1) {
func->set_statement(use_class->initialize.front());
} else {
PBlock*tmp = new PBlock(PBlock::BL_SEQ);
tmp->set_statement(use_class->initialize);
func->set_statement(tmp);
}
pform_pop_scope();
}
pform_cur_class = 0;
pform_pop_scope();
}

View File

@ -24,9 +24,11 @@
# include "LineInfo.h"
# include "verinum.h"
# include "named.h"
# include "property_qual.h"
# include "ivl_target.h"
# include <iostream>
# include <list>
# include <vector>
# include <map>
# include <memory>
@ -37,6 +39,7 @@
class Design;
class NetScope;
class PExpr;
class Statement;
class ivl_type_s;
typedef named<verinum> named_number_t;
typedef named<PExpr*> named_pexpr_t;
@ -212,45 +215,32 @@ struct class_type_t : public data_type_t {
: name(n) { }
void pform_dump(std::ostream&out, unsigned indent) const;
void pform_dump_init(std::ostream&out, unsigned indent) const;
// This is the name of the class type.
perm_string name;
std::map<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;
};
class property_qualifier_t {
public:
static inline property_qualifier_t set_none()
{ property_qualifier_t res; res.mask_ = 0; return res; }
static inline property_qualifier_t set_static()
{ property_qualifier_t res; res.mask_ = 1; return res; }
static inline property_qualifier_t set_protected()
{ property_qualifier_t res; res.mask_ = 2; return res; }
static inline property_qualifier_t set_local()
{ property_qualifier_t res; res.mask_ = 4; return res; }
static inline property_qualifier_t set_rand()
{ property_qualifier_t res; res.mask_ = 8; return res; }
static inline property_qualifier_t set_randc()
{ property_qualifier_t res; res.mask_ = 16; return res; }
inline property_qualifier_t operator | (property_qualifier_t r)
{ property_qualifier_t res; res.mask_ = mask_ | r.mask_; return res; }
public:
inline bool test_static() const { return mask_ & 1; }
inline bool test_protected() const { return mask_ & 2; }
inline bool test_local() const { return mask_ & 4; }
private:
int mask_;
};
/*
* The pform_name_t is the general form for a hierarchical
* identifier. It is an ordered list of name components. Each name

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);
bool prefix_scope = false;
bool recurse_flag = false;
ivl_assert(*li, ! path.empty());
name_component_t path_tail = path.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
* and/or modify it in source code form under the terms of the GNU
@ -153,6 +153,12 @@ static void show_stmt_delayx(ivl_statement_t net, unsigned ind)
show_statement(ivl_stmt_sub_stmt(net), ind+2);
}
static void show_stmt_disable(ivl_statement_t net, unsigned ind)
{
ivl_scope_t scope = ivl_stmt_call(net);
fprintf(out, "%*sdisable %s\n", ind, "", ivl_scope_basename(scope));
}
static void show_stmt_force(ivl_statement_t net, unsigned ind)
{
unsigned idx;
@ -378,6 +384,10 @@ void show_statement(ivl_statement_t net, unsigned ind)
show_stmt_delayx(net, ind);
break;
case IVL_ST_DISABLE:
show_stmt_disable(net, ind);
break;
case IVL_ST_FORCE:
show_stmt_force(net, ind);
break;

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);
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%store/prop/v %d, %u, %u;\n", prop_idx, val.base, val.wid);
fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in bool property %s\n",
prop_idx, val.base, val.wid,
ivl_type_prop_name(sig_type, prop_idx));
fprintf(vvp_out, " %%pop/obj 1;\n");
clr_vector(val);
} else if (ivl_type_base(prop_type) == IVL_VT_LOGIC) {
assert(ivl_type_packed_dimensions(prop_type) == 1);
assert(ivl_type_packed_msb(prop_type,0) >= ivl_type_packed_lsb(prop_type, 0));
int wid = ivl_type_packed_msb(prop_type,0) - ivl_type_packed_lsb(prop_type,0) + 1;
struct vector_info val = draw_eval_expr_wid(rval, wid, STUFF_OK_XZ);
fprintf(vvp_out, " %%load/obj v%p_0;\n", sig);
fprintf(vvp_out, " %%store/prop/v %d, %u, %u; Store in logic property %s\n",
prop_idx, val.base, val.wid,
ivl_type_prop_name(sig_type, prop_idx));
fprintf(vvp_out, " %%pop/obj 1;\n");
clr_vector(val);

View File

@ -59,14 +59,17 @@ LIBS = @LIBS@ @EXTRALIBS@
M = StringHeap.o LineInfo.o
O = main.o architec.o compiler.o entity.o \
expression.o package.o scope.o sequential.o vsignal.o vtype.o \
expression.o package.o scope.o sequential.o subprogram.o vsignal.o vtype.o \
vtype_match.o \
architec_elaborate.o entity_elaborate.o expression_elaborate.o \
expression_evaluate.o \
sequential_elaborate.o \
vtype_elaborate.o \
entity_stream.o expression_stream.o vtype_stream.o \
lexor.o lexor_keyword.o parse.o \
parse_misc.o library.o vhdlreal.o vhdlint.o \
architec_emit.o entity_emit.o expression_emit.o sequential_emit.o vtype_emit.o \
architec_emit.o entity_emit.o expression_emit.o package_emit.o \
sequential_emit.o subprogram_emit.o vtype_emit.o \
debug.o architec_debug.o expression_debug.o sequential_debug.o \
$M

View File

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

View File

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

View File

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

View File

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

View File

@ -22,6 +22,7 @@
# include "architec.h"
# include "expression.h"
# include "parse_types.h"
# include "sequential.h"
# include "vsignal.h"
# include "vtype.h"
# include <fstream>
@ -100,31 +101,36 @@ void ComponentBase::dump_ports(ostream&out, int indent) const
void Scope::dump_scope(ostream&out) const
{
// Dump types
for (map<perm_string,const VType*>::const_iterator cur = old_types_.begin()
; cur != old_types_.end() ; ++cur) {
out << " -- imported types" << endl;
for (map<perm_string,const VType*>::const_iterator cur = use_types_.begin()
; cur != use_types_.end() ; ++cur) {
out << " " << cur->first << ": ";
cur->second->show(out);
out << endl;
}
for (map<perm_string,const VType*>::const_iterator cur = new_types_.begin()
; cur != new_types_.end() ; ++cur) {
out << " -- Types from this scope" << endl;
for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++cur) {
out << " " << cur->first << ": ";
cur->second->show(out);
out << endl;
}
// Dump constants
for (map<perm_string,const_t*>::const_iterator cur = old_constants_.begin()
; cur != old_constants_.end() ; ++cur) {
out << " -- imported constants" << endl;
for (map<perm_string,const_t*>::const_iterator cur = use_constants_.begin()
; cur != use_constants_.end() ; ++cur) {
out << " constant " << cur->first << " = ";
out << endl;
}
for (map<perm_string,const_t*>::const_iterator cur = new_constants_.begin()
; cur != new_constants_.end() ; ++cur) {
out << " -- Constants from this scope" << endl;
for (map<perm_string,const_t*>::const_iterator cur = cur_constants_.begin()
; cur != cur_constants_.end() ; ++cur) {
out << " constant " << cur->first << " = ";
out << endl;
}
// Dump signal declarations
out << " -- Signals" << endl;
for (map<perm_string,Signal*>::const_iterator cur = old_signals_.begin()
; cur != old_signals_.end() ; ++cur) {
if (cur->second)
@ -138,8 +144,24 @@ void Scope::dump_scope(ostream&out) const
cur->second->dump(out, 3);
else
out << " signal " << cur->first.str() << ": ???" << endl;
}
// Dump subprograms
out << " -- Imported Subprograms" << endl;
for (map<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
out << " -- Components" << endl;
for (map<perm_string,ComponentBase*>::const_iterator cur = old_components_.begin()
; cur != old_components_.end() ; ++cur) {
out << " component " << cur->first << " is" << endl;
@ -148,10 +170,11 @@ void Scope::dump_scope(ostream&out) const
out << " end component " << cur->first << endl;
}
for (map<perm_string,ComponentBase*>::const_iterator cur = new_components_.begin()
; cur != new_components_.end() ; ++cur) {
out << " component " << cur->first << " is" << endl;
cur->second->dump_ports(out);
out << " end component " << cur->first << endl;
; cur != new_components_.end() ; ++cur) {
out << " component " << cur->first << " is" << endl;
cur->second->dump_generics(out);
cur->second->dump_ports(out);
out << " end component " << cur->first << endl;
}
}
@ -436,3 +459,41 @@ ostream& ExpInteger::dump_inline(ostream&out) const
out << value_;
return out;
}
void Subprogram::dump(ostream&fd) const
{
fd << " " << name_;
if (ports_->empty()) {
fd << "()";
} else {
fd << "(";
list<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
* and/or modify it in source code form under the terms of the GNU
@ -113,6 +114,10 @@ int Entity::elaborate_ports_(void)
continue;
}
// Elaborate the type to elaborate any expressions that
// are used by the types.
errors += type->elaborate(this, bind_arch_);
VType::decl_t cur_decl;
cur_decl.type = type;
declarations_[cur_port->name] = cur_decl;

View File

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

View File

@ -1,7 +1,8 @@
#ifndef __expression_H
#define __expression_H
/*
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -31,6 +32,7 @@ class prange_t;
class Entity;
class Architecture;
class ScopeBase;
class Subprogram;
class VType;
class VTypeArray;
class VTypePrimitive;
@ -90,6 +92,10 @@ class Expression : public LineInfo {
// class fills in the details of what exactly happened.
virtual int emit(ostream&out, Entity*ent, Architecture*arc) =0;
// The emit_package virtual message is similar, but is called
// in a package context and to emit SV packages.
virtual int emit_package(std::ostream&out);
// The evaluate virtual method tries to evaluate expressions
// to constant literal values. Return true and set the val
// argument if the evaluation works, or return false if it
@ -187,6 +193,9 @@ class ExpBinary : public Expression {
void dump_operands(ostream&out, int indent = 0) const;
private:
virtual const VType*resolve_operand_types_(const VType*t1, const VType*t2) const;
private:
Expression*operand1_;
Expression*operand2_;
@ -299,6 +308,9 @@ class ExpArithmetic : public ExpBinary {
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;
private:
const VType* resolve_operand_types_(const VType*t1, const VType*t2) const;
private:
fun_t fun_;
};
@ -457,6 +469,10 @@ class ExpFunc : public Expression {
ExpFunc(perm_string nn, std::list<Expression*>*args);
~ExpFunc();
inline perm_string func_name() const { return name_; }
inline size_t func_args() const { return argv_.size(); }
inline const Expression*func_arg(size_t idx) const { return argv_[idx]; }
public: // Base methods
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd);
@ -466,6 +482,7 @@ class ExpFunc : public Expression {
private:
perm_string name_;
std::vector<Expression*> argv_;
Subprogram*def_;
};
class ExpInteger : public Expression {
@ -478,6 +495,7 @@ class ExpInteger : public Expression {
int elaborate_expr(Entity*ent, Architecture*arc, const VType*ltype);
void write_to_stream(std::ostream&fd);
int emit(ostream&out, Entity*ent, Architecture*arc);
int emit_package(std::ostream&out);
bool is_primary(void) const;
bool evaluate(ScopeBase*scope, int64_t&val) const;
void dump(ostream&out, int indent = 0) const;

View File

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

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
* and/or modify it in source code form under the terms of the GNU
@ -20,10 +21,12 @@
# include "expression.h"
# include "vtype.h"
# include "architec.h"
# include "package.h"
# include "parse_types.h"
# include <typeinfo>
# include <iostream>
# include <cstdlib>
# include <cstring>
# include "ivl_assert.h"
# include <cassert>
@ -37,6 +40,14 @@ int Expression::emit(ostream&out, Entity*, Architecture*)
return 1;
}
int Expression::emit_package(ostream&out)
{
out << " /* " << get_fileline() << ": internal error: "
<< "I don't know how to emit_package this expression! "
<< "type=" << typeid(*this).name() << " */ ";
return 1;
}
bool Expression::is_primary(void) const
{
return false;
@ -270,16 +281,14 @@ int ExpAttribute::emit(ostream&out, Entity*ent, Architecture*arc)
the down to a literal integer at compile time, and all it
needs is the type of the base expression. (The base
expression doesn't even need to be evaluated.) */
if (name_ == "length") {
int64_t val;
bool rc = evaluate(ent, arc, val);
out << val;
if (rc)
return errors;
else
return errors + 1;
if (name_=="length") {
out << "$bits(";
errors += base_->emit(out, ent, arc);
out << ")";
return errors;
}
out << "$ivl_attribute(";
errors += base_->emit(out, ent, arc);
out << ", \"" << name_ << "\")";
@ -531,13 +540,12 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc)
out << ")";
} else if (name_ == "to_unsigned" && argv_.size() == 2) {
int64_t use_size;
bool rc = argv_[1]->evaluate(ent, arc, use_size);
ivl_assert(*this, rc);
out << "$unsigned(" << use_size << "'(";
out << "$ivlh_to_unsigned(";
errors += argv_[0]->emit(out, ent, arc);
out << "))";
out << ", ";
errors += argv_[1]->emit(out, ent, arc);
out << ")";
} else if (name_ == "conv_std_logic_vector" && argv_.size() == 2) {
int64_t use_size;
@ -547,7 +555,28 @@ int ExpFunc::emit(ostream&out, Entity*ent, Architecture*arc)
errors += argv_[0]->emit(out, ent, arc);
out << ")";
} else if (name_ == "rising_edge" && argv_.size()==1) {
out << "$ivlh_rising_edge(";
errors += argv_[0]->emit(out, ent, arc);
out << ")";
} else if (name_ == "falling_edge" && argv_.size()==1) {
out << "$ivlh_falling_edge(";
errors += argv_[0]->emit(out, ent, arc);
out << ")";
} else {
// If this function has an elaborated defintion, and if
// that definition is in a package, then include the
// package name as a scope qualifier. This assures that
// the SV elaborator finds the correct VHDL elaborated
// definition.
if (def_) {
const Package*pkg = dynamic_cast<const Package*> (def_->get_parent());
if (pkg != 0)
out << "\\" << pkg->name() << " ::";
}
out << "\\" << name_ << " (";
for (size_t idx = 0; idx < argv_.size() ; idx += 1) {
if (idx > 0) out << ", ";
@ -565,6 +594,12 @@ int ExpInteger::emit(ostream&out, Entity*, Architecture*)
return 0;
}
int ExpInteger::emit_package(ostream&out)
{
out << value_;
return 0;
}
bool ExpInteger::is_primary(void) const
{
return true;
@ -713,6 +748,18 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA
const VTypePrimitive*etype = dynamic_cast<const VTypePrimitive*> (arr->element_type());
assert(etype);
// Detect the special case that this is an array of
// CHARACTER. In this case, emit at a Verilog string.
if (etype->type()==VTypePrimitive::CHARACTER) {
vector<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);
out << value_.size() << "'b";
for (size_t idx = 0 ; idx < value_.size() ; idx += 1) {
@ -728,6 +775,9 @@ int ExpString::emit_as_array_(ostream& out, Entity*, Architecture*, const VTypeA
out << "z";
break;
default:
cerr << get_fileline() << ": internal error: "
<< "Don't know how to handle bit " << value_[idx]
<< " with etype==" << etype->type() << endl;
assert(etype->type() == VTypePrimitive::STDLOGIC);
out << "x";
break;

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
* and/or modify it in source code form under the terms of the GNU
@ -119,7 +120,8 @@ void dump_libraries(ostream&file)
/*
* This function saves a package into the named library. Create the
* library if necessary.
* library if necessary. The parser uses this when it is finished with
* a package declaration.
*/
void library_save_package(perm_string parse_library_name, Package*pack)
{
@ -134,6 +136,29 @@ void library_save_package(perm_string parse_library_name, Package*pack)
// library right now, then store it in the work library.
if (parse_library_name.str() == 0)
store_package_in_work(pack);
else
pack->set_library(parse_library_name);
}
/*
* The parser uses this function in the package body rule to recall
* the package that was declared earlier.
*/
Package*library_recall_package(perm_string parse_library_name, perm_string package_name)
{
perm_string use_libname = parse_library_name.str()
? parse_library_name
: perm_string::literal("work");
map<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)
@ -254,7 +279,7 @@ static void import_ieee_use_std_logic_1164(ActiveScope*res, perm_string name)
if (all_flag || name == "std_logic_vector") {
vector<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));
}
}
@ -269,12 +294,12 @@ static void import_ieee_use_numeric_bit(ActiveScope*res, perm_string name)
if (all_flag || name == "signed") {
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));
}
if (all_flag || name == "unsigned") {
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));
}
}
@ -285,12 +310,12 @@ static void import_ieee_use_numeric_std(ActiveScope*res, perm_string name)
if (all_flag || name == "signed") {
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));
}
if (all_flag || name == "unsigned") {
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));
}
}
@ -322,20 +347,24 @@ const VTypePrimitive* primitive_BOOLEAN = new VTypePrimitive(VTypePrimitive::BO
const VTypePrimitive* primitive_BIT = new VTypePrimitive(VTypePrimitive::BIT);
const VTypePrimitive* primitive_INTEGER = new VTypePrimitive(VTypePrimitive::INTEGER);
const VTypePrimitive* primitive_STDLOGIC = new VTypePrimitive(VTypePrimitive::STDLOGIC);
const VTypePrimitive* primitive_CHARACTER= new VTypePrimitive(VTypePrimitive::CHARACTER);
const VTypeRange* primitive_NATURAL = new VTypeRange(primitive_INTEGER, INT64_MAX, 0);
const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, vector<VTypeArray::range_t> (1));
const VTypeArray* primitive_BOOL_VECTOR = new VTypeArray(primitive_BOOLEAN, vector<VTypeArray::range_t> (1));
static const VTypeArray* primitive_BIT_VECTOR = new VTypeArray(primitive_BIT, 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)
{
res->bind_name(perm_string::literal("boolean"), primitive_BOOLEAN);
res->bind_name(perm_string::literal("bit"), primitive_BIT);
res->bind_name(perm_string::literal("integer"), primitive_INTEGER);
res->bind_name(perm_string::literal("std_logic"), primitive_STDLOGIC);
res->bind_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR);
res->bind_name(perm_string::literal("natural"), primitive_NATURAL);
res->use_name(perm_string::literal("boolean"), primitive_BOOLEAN);
res->use_name(perm_string::literal("bit"), primitive_BIT);
res->use_name(perm_string::literal("integer"), primitive_INTEGER);
res->use_name(perm_string::literal("std_logic"), primitive_STDLOGIC);
res->use_name(perm_string::literal("character"), primitive_CHARACTER);
res->use_name(perm_string::literal("bit_vector"),primitive_BOOL_VECTOR);
res->use_name(perm_string::literal("string"), primitive_STRING);
res->use_name(perm_string::literal("natural"), primitive_NATURAL);
}
bool is_global_type(perm_string name)
@ -344,7 +373,9 @@ bool is_global_type(perm_string name)
if (name == "bit") return true;
if (name == "integer") return true;
if (name == "std_logic") return true;
if (name == "character") return true;
if (name == "bit_vector") return true;
if (name == "string") return true;
if (name == "natural") return true;
return false;
}
@ -363,3 +394,25 @@ static void store_package_in_work(const Package*pack)
pack->write_to_stream(file);
}
static int emit_packages(perm_string lib_name, const map<perm_string,Package*>&packages)
{
int errors = 0;
for (map<perm_string,Package*>::const_iterator cur = packages.begin()
; cur != packages.end() ; ++cur) {
errors += cur->second->emit_package(cout);
}
return errors;
}
int emit_packages(void)
{
int errors = 0;
for (map<perm_string,struct library_contents>::iterator cur = libraries.begin()
; cur != libraries.end() ; ++cur) {
errors += emit_packages(cur->first, cur->second.packages);
}
return 0;
}

View File

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

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

View File

@ -1,7 +1,8 @@
#ifndef __package_H
#define __package_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -26,15 +27,24 @@
class Package : public Scope, public LineInfo {
public:
Package(perm_string name, const ScopeBase&ref);
Package(perm_string name, const ActiveScope&ref);
~Package();
// The the library from which this package came. Having a
// source library influences the emit_package() method.
void set_library(perm_string);
perm_string name() const { return name_; }
Subprogram* recall_subprogram(perm_string name) const;
// This method writes a package header to a library file.
void write_to_stream(std::ostream&fd) const;
int emit_package(std::ostream&fd) const;
private:
perm_string from_library_;
perm_string name_;
};

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}
%{
/*
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -34,7 +34,8 @@
# include "architec.h"
# include "expression.h"
# include "sequential.h"
# include "package.h"
# include "subprogram.h"
# include "package.h"
# include "vsignal.h"
# include "vtype.h"
# include <cstdarg>
@ -181,6 +182,16 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
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;
ExpArithmetic::fun_t arithmetic_op;
std::list<struct adding_term>*adding_terms;
ExpAggregate::choice_t*choice;
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;
std::list<Architecture::Statement*>* arch_statement_list;
Subprogram*subprogram;
};
/* The keywords are all tokens. */
@ -274,6 +288,7 @@ static list<VTypeRecord::element_t*>* record_elements(list<perm_string>*names,
%type <flag> direction
%type <arithmetic_op> adding_operator
%type <adding_terms> simple_expression_terms
%type <interface_list> interface_element interface_list
%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> name prefix selected_name
%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_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 <text> architecture_body_start package_declaration_start
%type <text> package_body_start
%type <text> identifier_opt identifier_colon_opt logical_name suffix
%type <name_list> logical_name_list identifier_list
%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> case_statement procedure_call procedure_call_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_list> else_when_waveforms
%type <subprogram> function_specification subprogram_specification
%%
/* The design_file is the root for the VHDL parse. This rule is also
@ -658,6 +676,15 @@ composite_type_definition
delete $2;
$$ = tmp;
}
/* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */
| K_array '(' index_subtype_definition_list ')' K_of subtype_indication
{ sorrymsg(@1, "unbounded_array_definition not supported.\n");
std::list<prange_t*> r;
VTypeArray*tmp = new VTypeArray($6, &r);
$$ = tmp;
}
| record_type_definition
{ $$ = $1; }
;
@ -1143,6 +1170,16 @@ for_generate_statement
function_specification /* IEEE 1076-2008 P4.2.1 */
: K_function IDENTIFIER '(' interface_list ')' K_return IDENTIFIER
{ perm_string type_name = lex_strings.make($7);
perm_string name = lex_strings.make($2);
const VType*type_mark = active_scope->find_type(type_name);
touchup_interface_for_functions($4);
Subprogram*tmp = new Subprogram(name, $4, type_mark);
FILE_NAME(tmp,@1);
delete[]$2;
delete[]$7;
$$ = tmp;
}
;
generate_statement /* IEEE 1076-2008 P11.8 */
@ -1316,6 +1353,16 @@ index_constraint
}
;
/* The identifier should be a type name */
index_subtype_definition /* IEEE 1076-2008 P5.3.2.1 */
: IDENTIFIER K_range BOX
;
index_subtype_definition_list
: index_subtype_definition_list ',' index_subtype_definition
| index_subtype_definition
;
instantiation_list
: identifier_list
{
@ -1599,20 +1646,40 @@ package_declarative_part_opt
|
;
package_body
: K_package K_body IDENTIFIER K_is
package_body /* IEEE 1076-2008 P4.8 */
: package_body_start K_is
package_body_declarative_part_opt
K_end K_package_opt identifier_opt ';'
{ sorrymsg(@1, "Package body is not yet supported.\n");
delete[] $3;
if($8) delete[] $8;
{ perm_string name = lex_strings.make($1);
if ($6 && name != $6)
errormsg(@6, "Package name (%s) doesn't match closing name (%s).\n", $1, $6);
delete[] $1;
if($6) delete[]$6;
pop_scope();
}
| K_package K_body IDENTIFIER K_is
error
K_end K_package_opt identifier_opt ';'
{ errormsg(@1, "Errors in package body.\n");
| package_body_start K_is error K_end K_package_opt identifier_opt ';'
{ errormsg(@1, "Errors in package %s body.\n", $1);
yyerrok;
pop_scope();
}
;
/*
* This is a portion of the package_body rule that we factor out so
* that we can use this rule to start the scope.
*/
package_body_start
: K_package K_body IDENTIFIER
{ perm_string name = lex_strings.make($3);
push_scope();
Package*pkg = library_recall_package(parse_library_name, name);
if (pkg != 0) {
active_scope->set_package_header(pkg);
} else {
errormsg(@1, "Package body for %s has no matching header.\n", $3);
}
$$ = $3;
}
;
@ -1723,12 +1790,12 @@ procedure_call
$$ = tmp;
}
| IDENTIFIER '(' error ')'
{
errormsg(@1, "Errors in procedure call.\n");
yyerrok;
delete[]$1;
$$ = 0;
};
{ errormsg(@1, "Errors in procedure call.\n");
yyerrok;
delete[]$1;
$$ = 0;
}
;
procedure_call_statement
: IDENTIFIER ':' procedure_call { $$ = $3; }
@ -2002,6 +2069,11 @@ sequential_statement
shift_expression : simple_expression { $$ = $1; } ;
sign
: '+'
| '-'
;
signal_declaration_assign_opt
: VASSIGN expression { $$ = $2; }
| { $$ = 0; }
@ -2020,18 +2092,55 @@ signal_declaration_assign_opt
* Note that although the concatenation operator '&' is syntactically
* an addition operator, it is handled differently during elaboration
* so detect it and create a different expression type.
*
* Note too that I'm using *right* recursion to implement the {...}
* part of the rule. This is normally bad, but expression lists aren't
* normally that long, and the while loop going through the formed
* list fixes up the associations.
*/
simple_expression
: sign simple_expression_2
{ sorrymsg(@1, "Unary expression +- not supported.\n");
$$ = $2;
}
| simple_expression_2
{ $$ = $1; }
;
simple_expression_2
: term
{ $$ = $1; }
| simple_expression adding_operator term
{ Expression*tmp;
if ($2 == ExpArithmetic::xCONCAT) {
tmp = new ExpConcat($1, $3);
} else {
tmp = new ExpArithmetic($2, $1, $3);
| term simple_expression_terms
{ Expression*tmp = $1;
list<struct adding_term>*lst = $2;
while (! lst->empty()) {
struct adding_term item = lst->front();
lst->pop_front();
if (item.op == ExpArithmetic::xCONCAT)
tmp = new ExpConcat(tmp, item.term);
else
tmp = new ExpArithmetic(item.op, tmp, item.term);
}
FILE_NAME(tmp, @2);
delete lst;
$$ = tmp;
}
;
simple_expression_terms
: adding_operator term
{ struct adding_term item;
item.op = $1;
item.term = $2;
list<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;
}
;
@ -2051,13 +2160,24 @@ signal_assignment_statement
}
;
/* This is a function/task body. This may have a matching subprogram
declaration, and if so it will be in the active scope. */
subprogram_body /* IEEE 1076-2008 P4.3 */
: subprogram_specification K_is
subprogram_declarative_part
K_begin subprogram_statement_part K_end
subprogram_kind_opt identifier_opt ';'
{ sorrymsg(@2, "Subprogram bodies not supported.\n");
if ($8) delete[]$8;
{ Subprogram*prog = $1;
Subprogram*tmp = active_scope->recall_subprogram(prog->name());
if (tmp && prog->compare_specification(tmp)) {
delete prog;
prog = tmp;
} else if (tmp) {
errormsg(@1, "Subprogram specification for %s doesn't match specification in package header.\n", prog->name().str());
}
prog->set_program_body($5);
active_scope->bind_name(prog->name(), prog);
}
| subprogram_specification K_is
@ -2066,14 +2186,14 @@ subprogram_body /* IEEE 1076-2008 P4.3 */
subprogram_kind_opt identifier_opt ';'
{ errormsg(@2, "Syntax errors in subprogram body.\n");
yyerrok;
if ($1) delete $1;
if ($8) delete[]$8;
}
;
subprogram_declaration
: subprogram_specification ';'
{ sorrymsg(@1, "Subprogram specifications not supported.\n");
}
{ if ($1) active_scope->bind_name($1->name(), $1); }
;
subprogram_declarative_item /* IEEE 1079-2008 P4.3 */
@ -2098,7 +2218,7 @@ subprogram_kind /* IEEE 1076-2008 P4.3 */
subprogram_kind_opt : subprogram_kind | ;
subprogram_specification
: function_specification
: function_specification { $$ = $1; }
;
/* This is an implementation of the rule:
@ -2107,8 +2227,8 @@ subprogram_specification
sequential_statement. Also handle the special case of an empty
list here. */
subprogram_statement_part
: sequence_of_statements
|
: sequence_of_statements { $$ = $1; }
| { $$ = 0; }
;
subtype_declaration
@ -2132,12 +2252,13 @@ subtype_indication
delete[]$1;
$$ = tmp;
}
| IDENTIFIER '(' simple_expression direction simple_expression ')'
{ const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $3, $4, $5);
| IDENTIFIER index_constraint
{ const VType*tmp = calculate_subtype_array(@1, $1, active_scope, $2);
if (tmp == 0) {
errormsg(@1, "Unable to calculate bounds for array of %s.\n", $1);
}
delete[]$1;
delete $2;
$$ = tmp;
}
| IDENTIFIER K_range simple_expression direction simple_expression
@ -2148,11 +2269,6 @@ subtype_indication
delete[]$1;
$$ = tmp;
}
| IDENTIFIER '(' error ')'
{ errormsg(@1, "Syntax error in subtype indication.\n");
yyerrok;
$$ = new VTypeERROR;
}
;
suffix

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
* and/or modify it in source code form under the terms of the GNU
@ -19,6 +20,7 @@
*/
# include "parse_misc.h"
# include "parse_types.h"
# include "parse_api.h"
# include "entity.h"
# include "architec.h"
@ -65,11 +67,11 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch)
}
}
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase* /* scope */,
Expression*array_left,
bool /* downto*/ ,
Expression*array_right)
static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase* /* scope */,
Expression*array_left,
bool /* downto*/ ,
Expression*array_right)
{
const VType*base_type = parse_type_by_name(lex_strings.make(base_name));
@ -98,6 +100,21 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
return base_type;
}
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope, list<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,
ScopeBase*scope,
Expression*range_left,

View File

@ -1,7 +1,8 @@
#ifndef __parse_misc_H
#define __parse_misc_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -25,6 +26,7 @@ class ActiveScope;
class Architecture;
class Expression;
class Package;
class prange_t;
class ScopeBase;
class VType;
@ -33,9 +35,7 @@ extern void bind_architecture_to_entity(const char*ename, Architecture*arch);
extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope,
Expression*array_left,
bool downto,
Expression*array_right);
std::list<prange_t*>*ranges);
extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope,
Expression*range_left,
@ -57,6 +57,8 @@ extern const VType* parse_type_by_name(perm_string name);
*/
extern void library_save_package(perm_string library_parse_name, Package*pack);
extern Package*library_recall_package(perm_string library_parse_name, perm_string name);
extern void library_import(const YYLTYPE&loc, const std::list<perm_string>*names);
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
#define __parse_types_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -74,10 +75,12 @@ class prange_t {
~prange_t() { delete left_; delete right_; }
void dump(ostream&out, int indent) const;
Expression*msb() { return direction_? left_ : right_; }
Expression*lsb() { return direction_? right_: left_; }
inline Expression*msb() { return direction_? left_ : right_; }
inline Expression*lsb() { return direction_? right_: left_; }
inline bool is_downto() const { return direction_; }
inline Expression*expr_left() { return left_; }
inline Expression*expr_right() { return right_; }
private:
Expression *left_, *right_;
@ -87,4 +90,10 @@ class prange_t {
prange_t(const prange_t&);
prange_t operator=(const prange_t&);
};
struct adding_term {
ExpArithmetic::fun_t op;
Expression*term;
};
#endif

View File

@ -31,6 +31,7 @@
# include "architec.h"
# include "expression.h"
# include "sequential.h"
# include "subprogram.h"
# include "parse_types.h"
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
* and/or modify it in source code form under the terms of the GNU
@ -18,9 +19,11 @@
*/
# include "scope.h"
# include "package.h"
# include <algorithm>
# include <iostream>
# include <iterator>
# include <cassert>
using namespace std;
@ -30,13 +33,11 @@ using namespace std;
* "old_*_" variables. This clears up the "new_*_" variables to
* accumulate new scope values.
*/
ScopeBase::ScopeBase(const ScopeBase&ref)
ScopeBase::ScopeBase(const ActiveScope&ref)
{
merge(ref.old_constants_.begin(), ref.old_constants_.end(),
ref.new_constants_.begin(), ref.new_constants_.end(),
insert_iterator<map<perm_string, struct const_t*> >(
old_constants_, old_constants_.end())
);
use_constants_ = ref.use_constants_;
cur_constants_ = ref.cur_constants_;
merge(ref.old_signals_.begin(), ref.old_signals_.end(),
ref.new_signals_.begin(), ref.new_signals_.end(),
insert_iterator<map<perm_string, Signal*> >(
@ -52,11 +53,20 @@ ScopeBase::ScopeBase(const ScopeBase&ref)
insert_iterator<map<perm_string, ComponentBase*> >(
old_components_, old_components_.end())
);
merge(ref.old_types_.begin(), ref.old_types_.end(),
ref.new_types_.begin(), ref.new_types_.end(),
insert_iterator<map<perm_string, const VType*> >(
old_types_, old_types_.end())
);
use_types_ = ref.use_types_;
cur_types_ = ref.cur_types_;
use_subprograms_ = ref.use_subprograms_;
cur_subprograms_ = ref.cur_subprograms_;
// This constructor is invoked when the parser is finished with
// an active scope and is making the actual scope. At this point
// we know that "this" is the parent scope for the subprograms,
// so set it now.
for (map<perm_string,Subprogram*>::iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
cur->second->set_parent(this);
}
}
ScopeBase::~ScopeBase()
@ -74,16 +84,17 @@ void ScopeBase::cleanup()
*/
delete_all(new_signals_);
delete_all(new_components_);
delete_all(new_types_);
delete_all(new_constants_);
delete_all(cur_types_);
delete_all(cur_constants_);
delete_all(cur_subprograms_);
}
const VType*ScopeBase::find_type(perm_string by_name)
{
map<perm_string,const VType*>::const_iterator cur = new_types_.find(by_name);
if (cur == new_types_.end()) {
cur = old_types_.find(by_name);
if (cur == old_types_.end())
map<perm_string,const VType*>::const_iterator cur = cur_types_.find(by_name);
if (cur == cur_types_.end()) {
cur = use_types_.find(by_name);
if (cur == use_types_.end())
return 0;
else
return cur->second;
@ -93,10 +104,10 @@ const VType*ScopeBase::find_type(perm_string by_name)
bool ScopeBase::find_constant(perm_string by_name, const VType*&typ, Expression*&exp)
{
map<perm_string,struct const_t*>::const_iterator cur = new_constants_.find(by_name);
if (cur == new_constants_.end()) {
cur = old_constants_.find(by_name);
if (cur == old_constants_.end())
map<perm_string,struct const_t*>::const_iterator cur = cur_constants_.find(by_name);
if (cur == cur_constants_.end()) {
cur = use_constants_.find(by_name);
if (cur == use_constants_.end())
return false;
else {
typ = cur->second->typ;
@ -138,6 +149,25 @@ Variable* ScopeBase::find_variable(perm_string by_name) const
}
}
Subprogram* ScopeBase::find_subprogram(perm_string name) const
{
map<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)
{
for (map<perm_string,ComponentBase*>::const_iterator cur = that->old_components_.begin()
@ -146,36 +176,51 @@ void ScopeBase::do_use_from(const ScopeBase*that)
continue;
old_components_[cur->first] = cur->second;
}
for (map<perm_string,ComponentBase*>::const_iterator cur = that->new_components_.begin()
for (map<perm_string,ComponentBase*>::const_iterator cur = that->new_components_.begin()
; cur != that->new_components_.end() ; ++ cur) {
if (cur->second == 0)
continue;
old_components_[cur->first] = cur->second;
}
for (map<perm_string,const VType*>::const_iterator cur = that->old_types_.begin()
; cur != that->old_types_.end() ; ++ cur) {
for (map<perm_string,Subprogram*>::const_iterator cur = that->cur_subprograms_.begin()
; cur != that->cur_subprograms_.end() ; ++ cur) {
if (cur->second == 0)
continue;
old_types_[cur->first] = cur->second;
}
for (map<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;
use_subprograms_[cur->first] = cur->second;
}
for (map<perm_string,const_t*>::const_iterator cur = that->old_constants_.begin()
; cur != that->old_constants_.end() ; ++ cur) {
old_constants_[cur->first] = cur->second;
for (map<perm_string,const VType*>::const_iterator cur = that->cur_types_.begin()
; cur != that->cur_types_.end() ; ++ cur) {
if (cur->second == 0)
continue;
use_types_[cur->first] = cur->second;
}
for (map<perm_string,const_t*>::const_iterator cur = that->new_constants_.begin()
; cur != that->new_constants_.end() ; ++ cur) {
old_constants_[cur->first] = cur->second;
for (map<perm_string,const_t*>::const_iterator cur = that->cur_constants_.begin()
; cur != that->cur_constants_.end() ; ++ cur) {
use_constants_[cur->first] = cur->second;
}
}
void ActiveScope::set_package_header(Package*pkg)
{
assert(package_header_ == 0);
package_header_ = pkg;
}
Subprogram* ActiveScope::recall_subprogram(perm_string name) const
{
if (Subprogram*tmp = find_subprogram(name))
return tmp;
if (package_header_)
return package_header_->find_subprogram(name);
return 0;
}
bool ActiveScope::is_vector_name(perm_string name) const
{
if (find_signal(name))
@ -189,7 +234,7 @@ bool ActiveScope::is_vector_name(perm_string name) const
return false;
}
Scope::Scope(const ScopeBase&ref)
Scope::Scope(const ActiveScope&ref)
: ScopeBase(ref)
{
}

View File

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

View File

@ -1,7 +1,8 @@
#ifndef __sequential_H
#define __sequential_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -116,6 +117,7 @@ class ReturnStmt : public SequentialStmt {
~ReturnStmt();
public:
int emit(ostream&out, Entity*entity, Architecture*arc);
void dump(ostream&out, int indent) const;
private:

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
* and/or modify it in source code form under the terms of the GNU
@ -82,6 +83,14 @@ int IfSequential::Elsif::statement_emit(ostream&out, Entity*ent, Architecture*ar
return errors;
}
int ReturnStmt::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
out << "return ";
errors += val_->emit(out, ent, arc);
out << ";" << endl;
return errors;
}
int SignalSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
{
@ -203,13 +212,23 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc)
ivl_assert(*this, start_rc);
ivl_assert(*this, finish_rc);
if (range_->is_downto() && start_val < finish_val) {
out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl;
if (! range_->is_downto()) {
int64_t tmp = start_val;
start_val = finish_val;
finish_val = tmp;
}
if (range_->is_downto() && (start_val < finish_val)) {
out << "begin /* Degenerate loop at " << get_fileline()
<< ": " << start_val
<< " downto " << finish_val << " */ end" << endl;
return errors;
}
if (!range_->is_downto() && start_val > finish_val) {
out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl;
out << "begin /* Degenerate loop at " << get_fileline()
<< ": " << start_val
<< " to " << finish_val << " */ end" << endl;
return errors;
}

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

View File

@ -1,7 +1,8 @@
#ifndef __vtype_H
#define __vtype_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -27,6 +28,8 @@
# include <inttypes.h>
# include "StringHeap.h"
class Architecture;
class Entity;
class Expression;
class prange_t;
class VTypeDef;
@ -45,6 +48,15 @@ class VType {
VType() { }
virtual ~VType() =0;
// This is rarely used, but some types may have expressions
// that need to be elaborated.
virtual int elaborate(Entity*end, Architecture*arc) const;
// This virtual method returns true if that is equivalent to
// this type. This method is used for example to compare
// function prototypes.
virtual bool type_match(const VType*that) const;
// This virtual method writes a VHDL-accurate representation
// of this type to the designated stream. This is used for
// writing parsed types to library files.
@ -112,7 +124,7 @@ class VTypeERROR : public VType {
class VTypePrimitive : public VType {
public:
enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC };
enum type_t { BOOLEAN, BIT, INTEGER, STDLOGIC, CHARACTER };
public:
VTypePrimitive(type_t);
@ -134,6 +146,7 @@ extern const VTypePrimitive* primitive_BOOLEAN;
extern const VTypePrimitive* primitive_BIT;
extern const VTypePrimitive* primitive_INTEGER;
extern const VTypePrimitive* primitive_STDLOGIC;
extern const VTypePrimitive* primitive_CHARACTER;
/*
* An array is a compound N-dimensional array of element type. The
@ -164,6 +177,7 @@ class VTypeArray : public VType {
VTypeArray(const VType*etype, std::list<prange_t*>*r, bool signed_vector =false);
~VTypeArray();
int elaborate(Entity*ent, Architecture*arc) const;
void write_to_stream(std::ostream&fd) const;
void show(std::ostream&) const;
@ -191,6 +205,10 @@ class VTypeRange : public VType {
VTypeRange(const VType*base, int64_t max_val, int64_t min_val);
~VTypeRange();
// Get the type that is limited by the range.
inline const VType* base_type() const { return base_; }
public: // Virtual methods
void write_to_stream(std::ostream&fd) const;
int emit_def(std::ostream&out) const;

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();
dims.pop_front();
out << "[";
errors += cur->dimension(0).msb()->emit(out, 0, 0);
if (cur->dimension(0).msb())
errors += cur->dimension(0).msb()->emit(out, 0, 0);
else
out << "?error?";
out << ":";
errors += cur->dimension(0).lsb()->emit(out, 0, 0);
if (cur->dimension(0).lsb())
errors += cur->dimension(0).lsb()->emit(out, 0, 0);
else
out << "?error?";
out << "]";
}
@ -130,6 +136,9 @@ int VTypePrimitive::emit_primitive_type(ostream&out) const
case INTEGER:
out << "bool [31:0]";
break;
case CHARACTER:
out << "char";
break;
default:
assert(0);
break;

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.
*/
# define __STDC_LIMIT_MACROS
# include "vtype.h"
# include "expression.h"
# include <typeinfo>
# include <stdint.h>
# include <cassert>
using namespace std;
@ -115,6 +117,15 @@ void VTypePrimitive::write_to_stream(ostream&fd) const
void VTypeRange::write_to_stream(ostream&fd) const
{
// Detect some special cases that can be written as ieee or
// standard types.
if (const VTypePrimitive*tmp = dynamic_cast<const VTypePrimitive*> (base_)) {
if (min_==0 && max_==INT64_MAX && tmp->type()==VTypePrimitive::INTEGER) {
fd << "natural";
return;
}
}
base_->write_to_stream(fd);
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);
};
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 {
public:
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;
}
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)
{
T*tmp = reinterpret_cast<T*>(buf+offset_);
@ -326,8 +414,15 @@ void class_type::set_property(size_t idx, const string&name, const string&type)
properties_[idx].type = new property_string;
else if (type == "o")
properties_[idx].type = new property_object;
else
else if (type[0] == 'b') {
size_t wid = strtoul(type.c_str()+1, 0, 0);
properties_[idx].type = new property_bit(wid);
} else if (type[0] == 'L') {
size_t wid = strtoul(type.c_str()+1,0,0);
properties_[idx].type = new property_logic(wid);
} else {
properties_[idx].type = 0;
}
}
void class_type::finish_setup(void)