Merge branch 'master' of github.com:steveicarus/iverilog
This commit is contained in:
commit
e736c022b1
6
PExpr.h
6
PExpr.h
|
|
@ -387,9 +387,9 @@ class PEIdent : public PExpr {
|
|||
bool elaborate_lval_net_idx_(Design*, NetScope*, NetAssign_*,
|
||||
index_component_t::ctype_t,
|
||||
bool need_const_idx) const;
|
||||
bool elaborate_lval_net_class_member_(Design*, NetScope*,
|
||||
NetAssign_*,
|
||||
const perm_string&) const;
|
||||
NetAssign_*elaborate_lval_net_class_member_(Design*, NetScope*,
|
||||
NetNet*,
|
||||
const perm_string&) const;
|
||||
bool elaborate_lval_net_packed_member_(Design*, NetScope*,
|
||||
NetAssign_*,
|
||||
const perm_string&) const;
|
||||
|
|
|
|||
2
PTask.h
2
PTask.h
|
|
@ -110,6 +110,8 @@ class PFunction : public PTaskFunc {
|
|||
void set_statement(Statement *s);
|
||||
void set_return(const data_type_t*t);
|
||||
|
||||
inline Statement* get_statement() { return statement_; }
|
||||
|
||||
void elaborate_scope(Design*des, NetScope*scope) const;
|
||||
|
||||
/* elaborate the ports and return value. */
|
||||
|
|
|
|||
24
Statement.cc
24
Statement.cc
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 1998-2008,2010,2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 1998-2008,2010,2012-2013 Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
# include "Statement.h"
|
||||
# include "PExpr.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
Statement::~Statement()
|
||||
{
|
||||
|
|
@ -126,6 +127,17 @@ void PBlock::set_statement(const vector<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)
|
||||
{
|
||||
|
|
|
|||
17
Statement.h
17
Statement.h
|
|
@ -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.
|
||||
|
|
|
|||
157
elab_expr.cc
157
elab_expr.cc
|
|
@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
|
|||
{
|
||||
perm_string name = peek_tail_name(path_);
|
||||
|
||||
if (name=="$ivlh_to_unsigned") {
|
||||
ivl_assert(*this, parms_.size() == 2);
|
||||
// The Icarus Verilog specific $ivl_unsigned() system
|
||||
// task takes a second argument which is the output
|
||||
// size. This can be an arbitrary constant function.
|
||||
PExpr*pexpr = parms_[1];
|
||||
if (pexpr == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Missing $ivlh_to_unsigned width." << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetExpr*nexpr = elab_and_eval(des, scope, pexpr, -1, true);
|
||||
if (nexpr == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Unable to evaluate " << name
|
||||
<< " width argument: " << *pexpr << endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
long value = 0;
|
||||
bool rc = eval_as_long(value, nexpr);
|
||||
ivl_assert(*this, rc && value>=0);
|
||||
|
||||
expr_width_ = value;
|
||||
signed_flag_= false;
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
if (name=="$signed" || name=="$unsigned") {
|
||||
PExpr*expr = parms_[0];
|
||||
if (expr == 0)
|
||||
|
|
@ -1135,7 +1164,11 @@ unsigned PECallFunction::test_width_method_(Design*des, NetScope*scope,
|
|||
}
|
||||
|
||||
const netclass_t* class_type = net->class_type();
|
||||
member_type = class_type->get_property(member_name);
|
||||
int midx = class_type->property_idx_from_name(member_name);
|
||||
if (midx >= 0)
|
||||
member_type = class_type->get_prop_type(midx);
|
||||
else
|
||||
member_type = 0;
|
||||
use_path = tmp_path;
|
||||
|
||||
use_darray = dynamic_cast<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.
|
||||
|
|
|
|||
84
elab_lval.cc
84
elab_lval.cc
|
|
@ -256,8 +256,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
}
|
||||
|
||||
if (reg->class_type() && !method_name.nil() && gn_system_verilog()) {
|
||||
NetAssign_*lv = new NetAssign_(reg);
|
||||
elaborate_lval_net_class_member_(des, use_scope, lv, method_name);
|
||||
NetAssign_*lv = elaborate_lval_net_class_member_(des, use_scope, reg, method_name);
|
||||
return lv;
|
||||
}
|
||||
|
||||
|
|
@ -316,7 +315,7 @@ NetAssign_* PEIdent::elaborate_lval(Design*des,
|
|||
return lv;
|
||||
}
|
||||
|
||||
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
|
||||
NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*des,
|
||||
NetScope*scope) const
|
||||
{
|
||||
if (!gn_system_verilog())
|
||||
|
|
@ -343,6 +342,40 @@ NetAssign_* PEIdent::elaborate_lval_method_class_member_(Design*,
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Detect assignment to constant properties. Note that the
|
||||
// initializer constructor MAY assign to constant properties,
|
||||
// as this is how the property gets its value.
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_const()) {
|
||||
if (class_type->get_prop_initialized(pidx)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else if (scope->basename()!="new" && scope->basename()!="new@") {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this method."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else {
|
||||
|
||||
// Mark this property as initilized. This is used
|
||||
// to know that we have initialized the constant
|
||||
// object so the next assignment will be marked as
|
||||
// illegal.
|
||||
class_type->set_prop_initialized(pidx);
|
||||
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": PEIdent::elaborate_lval_method_class_member_: "
|
||||
<< "Found initilzers for property " << class_type->get_prop_name(pidx) << endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetAssign_*this_lval = new NetAssign_(this_net);
|
||||
this_lval->set_property(member_name);
|
||||
|
||||
|
|
@ -812,31 +845,58 @@ bool PEIdent::elaborate_lval_net_idx_(Design*des,
|
|||
return true;
|
||||
}
|
||||
|
||||
bool PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*,
|
||||
NetAssign_*lv,
|
||||
const perm_string&method_name) const
|
||||
NetAssign_* PEIdent::elaborate_lval_net_class_member_(Design*des, NetScope*scope,
|
||||
NetNet*sig, const perm_string&method_name) const
|
||||
{
|
||||
if (debug_elaborate) {
|
||||
cerr << get_fileline() << ": elaborate_lval_net_class_member_: "
|
||||
<< "l-value is property " << method_name
|
||||
<< " of " << lv->sig()->name() << "." << endl;
|
||||
<< " of " << sig->name() << "." << endl;
|
||||
}
|
||||
|
||||
const netclass_t*class_type = lv->sig()->class_type();
|
||||
const netclass_t*class_type = sig->class_type();
|
||||
ivl_assert(*this, class_type);
|
||||
|
||||
/* Make sure the property is really present in the class. If
|
||||
not, then generate an error message and return an error. */
|
||||
ivl_type_t ptype = class_type->get_property(method_name);
|
||||
if (ptype == 0) {
|
||||
int pidx = class_type->property_idx_from_name(method_name);
|
||||
if (pidx < 0) {
|
||||
cerr << get_fileline() << ": error: Class " << class_type->get_name()
|
||||
<< " does not have a property " << method_name << "." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
property_qualifier_t qual = class_type->get_prop_qual(pidx);
|
||||
if (qual.test_local() && ! class_type->test_scope_is_method(scope)) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Local property " << class_type->get_prop_name(pidx)
|
||||
<< " is not accessible (l-value) in this context."
|
||||
<< " (scope=" << scope_path(scope) << ")" << endl;
|
||||
des->errors += 1;
|
||||
|
||||
} else if (qual.test_static()) {
|
||||
|
||||
// Special case: this is a static property. Ignore the
|
||||
// "this" sig and use the property itself, which is not
|
||||
// part of the sig, as the l-value.
|
||||
NetNet*psig = class_type->find_static_property(method_name);
|
||||
ivl_assert(*this, psig);
|
||||
|
||||
NetAssign_*lv = new NetAssign_(psig);
|
||||
return lv;
|
||||
|
||||
} else if (qual.test_const()) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Property " << class_type->get_prop_name(pidx)
|
||||
<< " is constant in this context." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
NetAssign_*lv = new NetAssign_(sig);
|
||||
lv->set_property(method_name);
|
||||
|
||||
ivl_type_t ptype = class_type->get_prop_type(pidx);
|
||||
const netdarray_t*mtype = dynamic_cast<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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
35
elab_sig.cc
35
elab_sig.cc
|
|
@ -314,6 +314,25 @@ bool Module::elaborate_sig(Design*des, NetScope*scope) const
|
|||
|
||||
void netclass_t::elaborate_sig(Design*des, PClass*pclass)
|
||||
{
|
||||
for (map<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;
|
||||
|
|
|
|||
99
elaborate.cc
99
elaborate.cc
|
|
@ -2361,11 +2361,17 @@ NetProc* PAssign::elaborate_compressed_(Design*des, NetScope*scope) const
|
|||
return cur;
|
||||
}
|
||||
|
||||
/*
|
||||
* Assignments within program blocks can only write to certain types
|
||||
* of variables. We can only write to:
|
||||
* - variables in a program block
|
||||
* - static properties of a class
|
||||
*/
|
||||
static bool lval_not_program_variable(const NetAssign_*lv)
|
||||
{
|
||||
while (lv) {
|
||||
NetScope*sig_scope = lv->sig()->scope();
|
||||
if (! sig_scope->program_block())
|
||||
if (! sig_scope->program_block() && sig_scope->type()!=NetScope::CLASS)
|
||||
return true;
|
||||
|
||||
lv = lv->more;
|
||||
|
|
@ -2793,14 +2799,6 @@ NetProc* PBlock::elaborate(Design*des, NetScope*scope) const
|
|||
if (nscope->calls_sys_task())
|
||||
scope->calls_sys_task(true);
|
||||
|
||||
if (!wires.empty()) {
|
||||
if (scope->need_const_func()) {
|
||||
cerr << get_fileline() << ": sorry: Block variables inside "
|
||||
"a constant function are not yet supported." << endl;
|
||||
}
|
||||
scope->is_const_func(false);
|
||||
}
|
||||
|
||||
cur->set_line(*this);
|
||||
return cur;
|
||||
}
|
||||
|
|
@ -4445,6 +4443,69 @@ NetProc* PRepeat::elaborate(Design*des, NetScope*scope) const
|
|||
return proc;
|
||||
}
|
||||
|
||||
NetProc* PReturn::elaborate(Design*des, NetScope*scope) const
|
||||
{
|
||||
NetScope*target = scope;
|
||||
for (;;) {
|
||||
if (target == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Return statement is not in a function." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (target->type() == NetScope::FUNC)
|
||||
break;
|
||||
|
||||
if (target->type() == NetScope::TASK) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Cannot \"return\" from tasks." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (target->type()==NetScope::BEGIN_END) {
|
||||
target = target->parent();
|
||||
continue;
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Cannot \"return\" from this scope: " << scope_path(target) << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// We don't yet support void functions, so require an
|
||||
// expression for the return statement.
|
||||
if (expr_ == 0) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
<< "Return from " << scope_path(target)
|
||||
<< " requires a return value expression." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
NetNet*res = target->find_signal(target->basename());
|
||||
ivl_variable_type_t lv_type = res->data_type();
|
||||
unsigned long wid = res->vector_width();
|
||||
NetAssign_*lv = new NetAssign_(res);
|
||||
|
||||
NetExpr*val = elaborate_rval_expr(des, scope, lv_type, wid, expr_);
|
||||
|
||||
NetBlock*proc = new NetBlock(NetBlock::SEQU, 0);
|
||||
proc->set_line( *this );
|
||||
|
||||
NetAssign*assn = new NetAssign(lv, val);
|
||||
assn->set_line( *this );
|
||||
proc->append(assn);
|
||||
|
||||
NetDisable*disa = new NetDisable(target);
|
||||
disa->set_line( *this );
|
||||
proc->append( disa );
|
||||
|
||||
return proc;
|
||||
}
|
||||
|
||||
/*
|
||||
* A task definition is elaborated by elaborating the statement that
|
||||
* it contains, and connecting its ports to NetNet objects. The
|
||||
|
|
@ -4883,6 +4944,13 @@ static void elaborate_classes(Design*des, NetScope*scope,
|
|||
; cur != classes.end() ; ++ cur) {
|
||||
netclass_t*use_class = scope->find_class(cur->second->pscope_name());
|
||||
use_class->elaborate(des, cur->second);
|
||||
|
||||
if (use_class->test_for_missing_initializers()) {
|
||||
cerr << cur->second->get_fileline() << ": error: "
|
||||
<< "Const properties of class " << use_class->get_name()
|
||||
<< " are missing initialization." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -4962,6 +5030,19 @@ bool Module::elaborate(Design*des, NetScope*scope) const
|
|||
*/
|
||||
void netclass_t::elaborate(Design*des, PClass*pclass)
|
||||
{
|
||||
if (! pclass->type->initialize_static.empty()) {
|
||||
std::vector<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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
166
net_func_eval.cc
166
net_func_eval.cc
|
|
@ -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) {
|
||||
|
|
|
|||
64
netclass.cc
64
netclass.cc
|
|
@ -32,7 +32,7 @@ netclass_t::~netclass_t()
|
|||
{
|
||||
}
|
||||
|
||||
bool netclass_t::set_property(perm_string pname, ivl_type_s*ptype)
|
||||
bool netclass_t::set_property(perm_string pname, property_qualifier_t qual, ivl_type_s*ptype)
|
||||
{
|
||||
map<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;
|
||||
}
|
||||
|
|
|
|||
30
netclass.h
30
netclass.h
|
|
@ -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_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
45
parse.y
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
2
pform.h
2
pform.h
|
|
@ -189,7 +189,7 @@ extern void pform_class_property(const struct vlltype&loc,
|
|||
extern void pform_set_this_class(const struct vlltype&loc, PTaskFunc*net);
|
||||
extern void pform_set_constructor_return(PFunction*net);
|
||||
|
||||
extern void pform_end_class_declaration(void);
|
||||
extern void pform_end_class_declaration(const struct vlltype&loc);
|
||||
|
||||
extern void pform_make_udp(perm_string name, list<perm_string>*parms,
|
||||
std::vector<PWire*>*decl, list<string>*table,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
198
vhdlpp/parse.y
198
vhdlpp/parse.y
|
|
@ -6,8 +6,8 @@
|
|||
%parse-param {perm_string parse_library_name}
|
||||
%{
|
||||
/*
|
||||
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012 / Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2012-2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -34,7 +34,8 @@
|
|||
# include "architec.h"
|
||||
# include "expression.h"
|
||||
# include "sequential.h"
|
||||
# include "package.h"
|
||||
# include "subprogram.h"
|
||||
# include "package.h"
|
||||
# include "vsignal.h"
|
||||
# include "vtype.h"
|
||||
# include <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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
# include "architec.h"
|
||||
# include "expression.h"
|
||||
# include "sequential.h"
|
||||
# include "subprogram.h"
|
||||
# include "parse_types.h"
|
||||
|
||||
class VType;
|
||||
|
|
|
|||
123
vhdlpp/scope.cc
123
vhdlpp/scope.cc
|
|
@ -1,5 +1,6 @@
|
|||
/*
|
||||
* Copyright (c) 2011-2012 Stephen Williams (steve@icarus.com)
|
||||
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
|
||||
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
|
||||
*
|
||||
* This source code is free software; you can redistribute it
|
||||
* and/or modify it in source code form under the terms of the GNU
|
||||
|
|
@ -18,9 +19,11 @@
|
|||
*/
|
||||
|
||||
# include "scope.h"
|
||||
# include "package.h"
|
||||
# include <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)
|
||||
{
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in New Issue