Merge branch 'work14'
This commit is contained in:
commit
173577d5f7
12
Statement.cc
12
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
|
||||
|
|
@ -341,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)
|
||||
{
|
||||
|
|
|
|||
13
Statement.h
13
Statement.h
|
|
@ -466,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.
|
||||
|
|
|
|||
65
elab_expr.cc
65
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)
|
||||
|
|
@ -1232,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. */
|
||||
|
|
@ -1918,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;
|
||||
|
|
@ -2049,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;
|
||||
|
|
|
|||
14
elab_sig.cc
14
elab_sig.cc
|
|
@ -983,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. */
|
||||
|
|
@ -993,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;
|
||||
|
|
|
|||
71
elaborate.cc
71
elaborate.cc
|
|
@ -2799,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;
|
||||
}
|
||||
|
|
@ -4451,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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
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) {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
};
|
||||
};
|
||||
|
||||
|
|
|
|||
10
parse.y
10
parse.y
|
|
@ -1244,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;
|
||||
}
|
||||
;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -938,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 ";
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue