Merge branch 'work14'

This commit is contained in:
Stephen Williams 2013-07-03 20:00:22 -07:00
commit 173577d5f7
48 changed files with 1535 additions and 269 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2008,2010,2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2008,2010,2012-2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -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)
{

View File

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

View File

@ -933,6 +933,35 @@ unsigned PECallFunction::test_width_sfunc_(Design*des, NetScope*scope,
{
perm_string name = peek_tail_name(path_);
if (name=="$ivlh_to_unsigned") {
ivl_assert(*this, parms_.size() == 2);
// The Icarus Verilog specific $ivl_unsigned() system
// task takes a second argument which is the output
// size. This can be an arbitrary constant function.
PExpr*pexpr = parms_[1];
if (pexpr == 0) {
cerr << get_fileline() << ": error: "
<< "Missing $ivlh_to_unsigned width." << endl;
return 0;
}
NetExpr*nexpr = elab_and_eval(des, scope, pexpr, -1, true);
if (nexpr == 0) {
cerr << get_fileline() << ": error: "
<< "Unable to evaluate " << name
<< " width argument: " << *pexpr << endl;
return 0;
}
long value = 0;
bool rc = eval_as_long(value, nexpr);
ivl_assert(*this, rc && value>=0);
expr_width_ = value;
signed_flag_= false;
return expr_width_;
}
if (name=="$signed" || name=="$unsigned") {
PExpr*expr = parms_[0];
if (expr == 0)
@ -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;

View File

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

View File

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

View File

@ -480,7 +480,7 @@ NetEConst* NetEBComp::eval_gteq_(const NetExpr*le, const NetExpr*re) const
if (le->expr_type() == IVL_VT_REAL || re->expr_type() == IVL_VT_REAL)
return eval_leeq_real_(re, le, true);
const NetEConst*l = dynamic_cast<const NetEConst*>(left_);
const NetEConst*l = dynamic_cast<const NetEConst*>(le);
if (l == 0) return 0;
verinum lv = l->value();

View File

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

View File

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

View File

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

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 1998-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -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 ";

View File

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

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2004-2012 Stephen Williams (steve@icarus.com)
* Copyright (c) 2004-2013 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -153,6 +153,12 @@ static void show_stmt_delayx(ivl_statement_t net, unsigned ind)
show_statement(ivl_stmt_sub_stmt(net), ind+2);
}
static void show_stmt_disable(ivl_statement_t net, unsigned ind)
{
ivl_scope_t scope = ivl_stmt_call(net);
fprintf(out, "%*sdisable %s\n", ind, "", ivl_scope_basename(scope));
}
static void show_stmt_force(ivl_statement_t net, unsigned ind)
{
unsigned idx;
@ -378,6 +384,10 @@ void show_statement(ivl_statement_t net, unsigned ind)
show_stmt_delayx(net, ind);
break;
case IVL_ST_DISABLE:
show_stmt_disable(net, ind);
break;
case IVL_ST_FORCE:
show_stmt_force(net, ind);
break;

View File

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

View File

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

View File

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

View File

@ -32,12 +32,12 @@ int Architecture::elaborate(Entity*entity)
// from the constant declaration itself. Elaborate the value
// expression with the declared type.
for (map<perm_string,struct const_t*>::iterator cur = old_constants_.begin()
; cur != old_constants_.end() ; ++cur) {
for (map<perm_string,struct const_t*>::iterator cur = use_constants_.begin()
; cur != use_constants_.end() ; ++cur) {
cur->second->val->elaborate_expr(entity, this, cur->second->typ);
}
for (map<perm_string,struct const_t*>::iterator cur = new_constants_.begin()
; cur != new_constants_.end() ; ++cur) {
for (map<perm_string,struct const_t*>::iterator cur = cur_constants_.begin()
; cur != cur_constants_.end() ; ++cur) {
cur->second->val->elaborate_expr(entity, this, cur->second->typ);
}
@ -174,9 +174,54 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
return -1;
const Expression*ce_raw = stmt->peek_condition();
// Now we have matched this pattern:
// process(<expr>) begin if <ce_raw>...
// The <ce_raw> is the condition.
// We expect the condition to be <name>'event AND <name>='1'.
// If it's not a logical AND, I give up.
if (const ExpFunc*ce_func = dynamic_cast<const ExpFunc*>(ce_raw)) {
if (ce_func->func_args() != 1)
return -1;
if (ce_func->func_name()!="rising_edge" && ce_func->func_name()!="falling_edge")
return -1;
if (! se->symbolic_compare(ce_func->func_arg(0)))
return -1;
// We've matched this pattern:
// process(<se>) if (rising_edge(<se>)) then ...
// and we can convert it to:
// always @(posedge <se>) ...
ExpEdge::fun_t use_edge;
if (ce_func->func_name()=="rising_edge")
use_edge = ExpEdge::POSEDGE;
else if (ce_func->func_name()=="falling_edge")
use_edge = ExpEdge::NEGEDGE;
else
use_edge = ExpEdge::ANYEDGE;
// Replace the sensitivity expression with an edge
// expression. The ExpEdge expression signals that this
// is an always-@(edge) statement.
ExpEdge*edge = new ExpEdge(use_edge, se);
assert(sensitivity_list_.size() == 1);
sensitivity_list_.pop_front();
sensitivity_list_.push_front(edge);
// Replace the statement with the body of the always
// statement, which is the true clause of the top "if"
// statement. There should be no "else" clause.
assert(statements_list_.size() == 1);
statements_list_.pop_front();
stmt->extract_true(statements_list_);
delete stmt;
return 0;
}
// Here we expect the condition to be
// <name>'event AND <name>='1'.
// So if ce_raw is not a logical AND, I give up.
const ExpLogical*ce = dynamic_cast<const ExpLogical*> (ce_raw);
if (ce == 0)
return -1;

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -113,6 +114,10 @@ int Entity::elaborate_ports_(void)
continue;
}
// Elaborate the type to elaborate any expressions that
// are used by the types.
errors += type->elaborate(this, bind_arch_);
VType::decl_t cur_decl;
cur_decl.type = type;
declarations_[cur_port->name] = cur_decl;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

76
vhdlpp/package_emit.cc Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "package.h"
# include <iostream>
# include "ivl_assert.h"
using namespace std;
int Package::emit_package(ostream&fd) const
{
// Don't emit the package if there is nothing in it that SV
// cares about.
if (cur_types_.empty() && cur_constants_.empty() && cur_subprograms_.empty())
return 0;
// If this package was imported from a library, then do not
// emit it again.
if (from_library_.str() != 0) {
fd << "/* Suppress package " << name()
<< " from library " << from_library_ << " */" << endl;
return 0;
}
int errors = 0;
fd << "package \\" << name() << " ;" << endl;
// Only emit types that were defined within this package. Skip
// the types that were imported from elsewhere.
for (map<perm_string,const VType*>::const_iterator cur = cur_types_.begin()
; cur != cur_types_.end() ; ++ cur) {
fd << "typedef ";
errors += cur->second->emit_def(fd);
fd << " \\" << cur->first << " ;" << endl;
}
for (map<perm_string,struct const_t*>::const_iterator cur = use_constants_.begin()
; cur != use_constants_.end() ; ++cur) {
fd << "localparam \\" << cur->first << " = ";
errors += cur->second->val->emit_package(fd);
fd << ";" << endl;
}
for (map<perm_string,struct const_t*>::const_iterator cur = cur_constants_.begin()
; cur != cur_constants_.end() ; ++cur) {
fd << "localparam " << cur->first << " = ";
errors += cur->second->val->emit_package(fd);
fd << ";" << endl;
}
for (map<perm_string,Subprogram*>::const_iterator cur = cur_subprograms_.begin()
; cur != cur_subprograms_.end() ; ++ cur) {
errors += cur->second->emit_package(fd);
}
fd << "endpackage" << endl;
return errors;
}

View File

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

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -19,6 +20,7 @@
*/
# include "parse_misc.h"
# include "parse_types.h"
# include "parse_api.h"
# include "entity.h"
# include "architec.h"
@ -65,11 +67,11 @@ void bind_architecture_to_entity(const char*ename, Architecture*arch)
}
}
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase* /* scope */,
Expression*array_left,
bool /* downto*/ ,
Expression*array_right)
static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase* /* scope */,
Expression*array_left,
bool /* downto*/ ,
Expression*array_right)
{
const VType*base_type = parse_type_by_name(lex_strings.make(base_name));
@ -98,6 +100,21 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
return base_type;
}
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope, list<prange_t*>*ranges)
{
if (ranges->size() == 1) {
prange_t*tmpr = ranges->front();
Expression*lef = tmpr->expr_left();
Expression*rig = tmpr->expr_right();
return calculate_subtype_array(loc, base_name, scope,
lef, tmpr->is_downto(), rig);
}
sorrymsg(loc, "Don't know how to handle multiple ranges here.\n");
return 0;
}
const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope,
Expression*range_left,

View File

@ -1,7 +1,8 @@
#ifndef __parse_misc_H
#define __parse_misc_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -25,6 +26,7 @@ class ActiveScope;
class Architecture;
class Expression;
class Package;
class prange_t;
class ScopeBase;
class VType;
@ -33,9 +35,7 @@ extern void bind_architecture_to_entity(const char*ename, Architecture*arch);
extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope,
Expression*array_left,
bool downto,
Expression*array_right);
std::list<prange_t*>*ranges);
extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
ScopeBase*scope,
Expression*range_left,
@ -57,6 +57,8 @@ extern const VType* parse_type_by_name(perm_string name);
*/
extern void library_save_package(perm_string library_parse_name, Package*pack);
extern Package*library_recall_package(perm_string library_parse_name, perm_string name);
extern void library_import(const YYLTYPE&loc, const std::list<perm_string>*names);
extern void library_use(const YYLTYPE&loc, ActiveScope*res, const char*libname, const char*pack, const char*ident);

View File

@ -1,7 +1,8 @@
#ifndef __parse_types_H
#define __parse_types_H
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011,2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -74,10 +75,12 @@ class prange_t {
~prange_t() { delete left_; delete right_; }
void dump(ostream&out, int indent) const;
Expression*msb() { return direction_? left_ : right_; }
Expression*lsb() { return direction_? right_: left_; }
inline Expression*msb() { return direction_? left_ : right_; }
inline Expression*lsb() { return direction_? right_: left_; }
inline bool is_downto() const { return direction_; }
inline Expression*expr_left() { return left_; }
inline Expression*expr_right() { return right_; }
private:
Expression *left_, *right_;
@ -87,4 +90,10 @@ class prange_t {
prange_t(const prange_t&);
prange_t operator=(const prange_t&);
};
struct adding_term {
ExpArithmetic::fun_t op;
Expression*term;
};
#endif

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,6 @@
/*
* Copyright (c) 2011 Stephen Williams (steve@icarus.com)
* Copyright (c) 2011-2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -82,6 +83,14 @@ int IfSequential::Elsif::statement_emit(ostream&out, Entity*ent, Architecture*ar
return errors;
}
int ReturnStmt::emit(ostream&out, Entity*ent, Architecture*arc)
{
int errors = 0;
out << "return ";
errors += val_->emit(out, ent, arc);
out << ";" << endl;
return errors;
}
int SignalSeqAssignment::emit(ostream&out, Entity*ent, Architecture*arc)
{
@ -203,13 +212,23 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, Architecture*arc)
ivl_assert(*this, start_rc);
ivl_assert(*this, finish_rc);
if (range_->is_downto() && start_val < finish_val) {
out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl;
if (! range_->is_downto()) {
int64_t tmp = start_val;
start_val = finish_val;
finish_val = tmp;
}
if (range_->is_downto() && (start_val < finish_val)) {
out << "begin /* Degenerate loop at " << get_fileline()
<< ": " << start_val
<< " downto " << finish_val << " */ end" << endl;
return errors;
}
if (!range_->is_downto() && start_val > finish_val) {
out << "begin /* Degenerate loop at " << get_fileline() << " */ end" << endl;
out << "begin /* Degenerate loop at " << get_fileline()
<< ": " << start_val
<< " to " << finish_val << " */ end" << endl;
return errors;
}

98
vhdlpp/subprogram.cc Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "subprogram.h"
# include "entity.h"
# include "vtype.h"
# include "ivl_assert.h"
using namespace std;
Subprogram::Subprogram(perm_string nam, list<InterfacePort*>*ports,
const VType*return_type)
: name_(nam), parent_(0), ports_(ports), return_type_(return_type), statements_(0)
{
}
Subprogram::~Subprogram()
{
}
void Subprogram::set_parent(const ScopeBase*par)
{
ivl_assert(*this, parent_ == 0);
parent_ = par;
}
void Subprogram::set_program_body(list<SequentialStmt*>*stmt)
{
ivl_assert(*this, statements_==0);
statements_ = stmt;
}
bool Subprogram::compare_specification(Subprogram*that) const
{
if (name_ != that->name_)
return false;
if (return_type_==0) {
if (that->return_type_!=0)
return false;
} else {
if (that->return_type_==0)
return false;
if (! return_type_->type_match(that->return_type_))
return false;
}
if (ports_==0) {
if (that->ports_!=0)
return false;
} else {
if (that->ports_==0)
return false;
if (ports_->size() != that->ports_->size())
return false;
}
return true;
}
void Subprogram::write_to_stream(ostream&fd) const
{
fd << " function " << name_ << "(";
if (ports_ && ! ports_->empty()) {
list<InterfacePort*>::const_iterator cur = ports_->begin();
InterfacePort*curp = *cur;
fd << curp->name << " : ";
curp->type->write_to_stream(fd);
for (++cur ; cur != ports_->end() ; ++cur) {
curp = *cur;
fd << "; " << curp->name << " : ";
curp->type->write_to_stream(fd);
}
}
fd << ") return ";
return_type_->write_to_stream(fd);
fd << ";" << endl;
}

65
vhdlpp/subprogram.h Normal file
View File

@ -0,0 +1,65 @@
#ifndef __subprogram_H
#define __subprogram_H
/*
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "StringHeap.h"
# include "LineInfo.h"
# include <iostream>
# include <list>
class InterfacePort;
class ScopeBase;
class SequentialStmt;
class VType;
class Subprogram : public LineInfo {
public:
Subprogram(perm_string name, std::list<InterfacePort*>*ports,
const VType*return_type);
~Subprogram();
void set_parent(const ScopeBase*par);
inline const ScopeBase*get_parent() const { return parent_; }
inline const perm_string&name() const { return name_; }
void set_program_body(std::list<SequentialStmt*>*statements);
// Return true if the specification (name, types, ports)
// matches this subprogram and that subprogram.
bool compare_specification(Subprogram*that) const;
// Emit a definition as it would show up in a package.
int emit_package(std::ostream&fd) const;
void write_to_stream(std::ostream&fd) const;
void dump(std::ostream&fd) const;
private:
perm_string name_;
const ScopeBase*parent_;
std::list<InterfacePort*>*ports_;
const VType*return_type_;
std::list<SequentialStmt*>*statements_;
};
#endif

79
vhdlpp/subprogram_emit.cc Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "subprogram.h"
# include "sequential.h"
# include "vtype.h"
# include <iostream>
using namespace std;
int Subprogram::emit_package(ostream&fd) const
{
int errors = 0;
if (return_type_) {
fd << "function ";
return_type_->emit_def(fd);
fd << " " << name_;
fd << "(";
} else {
fd << "task " << name_ << ";" << endl;
}
for (list<InterfacePort*>::const_iterator cur = ports_->begin()
; cur != ports_->end() ; ++cur) {
if (cur != ports_->begin())
fd << ", ";
InterfacePort*curp = *cur;
switch (curp->mode) {
case PORT_IN:
fd << "input ";
break;
case PORT_OUT:
fd << "output ";
break;
case PORT_NONE:
fd << "inout /* PORT_NONE? */ ";
break;
}
errors += curp->type->emit_def(fd);
fd << " \\" << curp->name << " ";
}
fd << ");" << endl;
if (statements_) {
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
; cur != statements_->end() ; ++cur) {
errors += (*cur)->emit(fd, 0, 0);
}
} else {
fd << " begin /* empty body */ end" << endl;
}
if (return_type_)
fd << "endfunction" << endl;
else
fd << "endtask" << endl;
return errors;
}

View File

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

View File

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

45
vhdlpp/vtype_elaborate.cc Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "vtype.h"
# include "expression.h"
int VType::elaborate(Entity*, Architecture*) const
{
return 0;
}
int VTypeArray::elaborate(Entity*ent, Architecture*arc) const
{
int errors = 0;
etype_->elaborate(ent, arc);
for (vector<range_t>::const_iterator cur = ranges_.begin()
; cur != ranges_.end() ; ++ cur) {
Expression*tmp = cur->msb();
if (tmp) errors += tmp->elaborate_expr(ent, arc, 0);
tmp = cur->lsb();
if (tmp) errors += tmp->elaborate_expr(ent, arc, 0);
}
return errors;
}

View File

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

26
vhdlpp/vtype_match.cc Normal file
View File

@ -0,0 +1,26 @@
/*
* Copyright (c) 2013 Stephen Williams (steve@icarus.com)
* Copyright CERN 2013 / Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
* General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# include "vtype.h"
bool VType::type_match(const VType*that) const
{
return this == that;
}

View File

@ -17,9 +17,11 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
# define __STDC_LIMIT_MACROS
# include "vtype.h"
# include "expression.h"
# include <typeinfo>
# include <stdint.h>
# include <cassert>
using namespace std;
@ -115,6 +117,15 @@ void VTypePrimitive::write_to_stream(ostream&fd) const
void VTypeRange::write_to_stream(ostream&fd) const
{
// Detect some special cases that can be written as ieee or
// standard types.
if (const VTypePrimitive*tmp = dynamic_cast<const VTypePrimitive*> (base_)) {
if (min_==0 && max_==INT64_MAX && tmp->type()==VTypePrimitive::INTEGER) {
fd << "natural";
return;
}
}
base_->write_to_stream(fd);
fd << " range " << min_ << " to " << max_;
}