Merge branch 'master' into return-stack
# Conflicts: # sv_vpi_user.h
This commit is contained in:
commit
f494b478cc
|
|
@ -384,6 +384,11 @@ The function returns an integer.
|
||||||
The function returns a vector with the given width, and is signed or
|
The function returns a vector with the given width, and is signed or
|
||||||
unsigned according to the flag.
|
unsigned according to the flag.
|
||||||
|
|
||||||
|
.TP 8
|
||||||
|
.B vpiSysFuncString
|
||||||
|
The function returns a string. This is an Icarus-specific extension, not
|
||||||
|
available in the VPI standard.
|
||||||
|
|
||||||
.SH "COMMAND FILES"
|
.SH "COMMAND FILES"
|
||||||
The command file allows the user to place source file names and
|
The command file allows the user to place source file names and
|
||||||
certain command line switches into a text file instead of on a long
|
certain command line switches into a text file instead of on a long
|
||||||
|
|
|
||||||
|
|
@ -2838,7 +2838,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
||||||
concat->set(idx, parms[off+idx]);
|
concat->set(idx, parms[off+idx]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wid_sum == 0) {
|
if (wid_sum == 0 && expr_type_ != IVL_VT_STRING) {
|
||||||
cerr << get_fileline() << ": error: Concatenation/replication "
|
cerr << get_fileline() << ": error: Concatenation/replication "
|
||||||
<< "may not have zero width in this context." << endl;
|
<< "may not have zero width in this context." << endl;
|
||||||
des->errors += 1;
|
des->errors += 1;
|
||||||
|
|
|
||||||
|
|
@ -75,6 +75,10 @@ EXTERN_C_START
|
||||||
/********* task/function properties **********/
|
/********* task/function properties **********/
|
||||||
#define vpiOtherFunc 6
|
#define vpiOtherFunc 6
|
||||||
|
|
||||||
|
/* Icarus-specific function type to use string as the return type */
|
||||||
|
#define vpiStringFunc 10
|
||||||
|
#define vpiSysFuncString vpiSysFuncString
|
||||||
|
|
||||||
EXTERN_C_END
|
EXTERN_C_END
|
||||||
|
|
||||||
#endif /* SV_VPI_USER_H */
|
#endif /* SV_VPI_USER_H */
|
||||||
|
|
|
||||||
22
synth2.cc
22
synth2.cc
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2002-2015 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2002-2016 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -103,6 +103,14 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
||||||
NetNet*rsig = rval_->synthesize(des, scope, rval_);
|
NetNet*rsig = rval_->synthesize(des, scope, rval_);
|
||||||
assert(rsig);
|
assert(rsig);
|
||||||
|
|
||||||
|
if (lval_->word() && ! dynamic_cast<NetEConst*>(lval_->word())) {
|
||||||
|
cerr << get_fileline() << ": sorry: assignment to variable "
|
||||||
|
"location in memory is not currently supported in "
|
||||||
|
"synthesis." << endl;
|
||||||
|
des->errors += 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
NetNet*lsig = lval_->sig();
|
NetNet*lsig = lval_->sig();
|
||||||
if (!lsig) {
|
if (!lsig) {
|
||||||
cerr << get_fileline() << ": error: "
|
cerr << get_fileline() << ": error: "
|
||||||
|
|
@ -218,6 +226,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
||||||
rsig = tmp;
|
rsig = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rsig = crop_to_width(des, rsig, lsig->vector_width());
|
||||||
|
|
||||||
if (nex_out.pin_count() > 1) {
|
if (nex_out.pin_count() > 1) {
|
||||||
NexusSet tmp_set;
|
NexusSet tmp_set;
|
||||||
nex_output(tmp_set);
|
nex_output(tmp_set);
|
||||||
|
|
@ -1411,6 +1421,16 @@ bool NetBlock::synth_sync(Design*des, NetScope*scope,
|
||||||
are used to collect the outputs from the substatement
|
are used to collect the outputs from the substatement
|
||||||
for the inputs of the FF bank. */
|
for the inputs of the FF bank. */
|
||||||
NetBus tmp_out (scope, tmp_set.size());
|
NetBus tmp_out (scope, tmp_set.size());
|
||||||
|
for (unsigned idx = 0 ; idx < tmp_out.pin_count() ; idx += 1) {
|
||||||
|
unsigned ptr = nex_map.find_nexus(tmp_set[idx]);
|
||||||
|
ivl_assert(*this, ptr < nex_out.pin_count());
|
||||||
|
if (nex_out.pin(ptr).is_linked()) {
|
||||||
|
cerr << get_fileline() << ": sorry: multiple statements "
|
||||||
|
"assigning to the same flip-flop are not yet "
|
||||||
|
"supported in synthesis." << endl;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Create a temporary ff_ce (FF clock-enable) that
|
/* Create a temporary ff_ce (FF clock-enable) that
|
||||||
accounts for the subset of outputs that this
|
accounts for the subset of outputs that this
|
||||||
|
|
|
||||||
11
sys_funcs.cc
11
sys_funcs.cc
|
|
@ -204,6 +204,17 @@ int load_sys_func_table(const char*path)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (strcmp(stype,"vpiSysFuncString") == 0) {
|
||||||
|
cell = new struct sfunc_return_type_cell;
|
||||||
|
cell->name = lex_strings.add(name);
|
||||||
|
cell->type = IVL_VT_STRING;
|
||||||
|
cell->wid = 0; // string is a dynamic length type
|
||||||
|
cell->signed_flag = false;
|
||||||
|
cell->next = sfunc_stack;
|
||||||
|
sfunc_stack = cell;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
fprintf(stderr, "%s:%s: Unknown type: %s\n",
|
fprintf(stderr, "%s:%s: Unknown type: %s\n",
|
||||||
path, name, stype);
|
path, name, stype);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -519,3 +519,14 @@ void draw_vpi_rfunc_call(ivl_expr_t fnet)
|
||||||
|
|
||||||
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw_vpi_sfunc_call(ivl_expr_t fnet)
|
||||||
|
{
|
||||||
|
char call_string[1024];
|
||||||
|
|
||||||
|
sprintf(call_string, " %%vpi_func/s %u %u \"%s\"",
|
||||||
|
ivl_file_table_index(ivl_expr_file(fnet)),
|
||||||
|
ivl_expr_lineno(fnet), ivl_expr_name(fnet));
|
||||||
|
|
||||||
|
draw_vpi_taskfunc_args(call_string, 0, fnet);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2014 Stephen Williams (steve@icarus.com)
|
* Copyright (c) 2014-2016 Stephen Williams (steve@icarus.com)
|
||||||
*
|
*
|
||||||
* This source code is free software; you can redistribute it
|
* This source code is free software; you can redistribute it
|
||||||
* and/or modify it in source code form under the terms of the GNU
|
* and/or modify it in source code form under the terms of the GNU
|
||||||
|
|
@ -76,8 +76,8 @@ static int draw_condition_binary_compare(ivl_expr_t expr)
|
||||||
%cmp instruction. */
|
%cmp instruction. */
|
||||||
if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) {
|
if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) {
|
||||||
ivl_expr_t tmp = le;
|
ivl_expr_t tmp = le;
|
||||||
re = le;
|
le = re;
|
||||||
le = tmp;
|
re = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
draw_eval_vec4(le);
|
draw_eval_vec4(le);
|
||||||
|
|
|
||||||
|
|
@ -163,6 +163,12 @@ static void string_ex_pop(ivl_expr_t expr)
|
||||||
fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg));
|
fprintf(vvp_out, " %%qpop/%s/str v%p_0;\n", fb, ivl_expr_signal(arg));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void draw_sfunc_string(ivl_expr_t expr)
|
||||||
|
{
|
||||||
|
assert(ivl_expr_value(expr) == IVL_VT_STRING);
|
||||||
|
draw_vpi_sfunc_call(expr);
|
||||||
|
}
|
||||||
|
|
||||||
void draw_eval_string(ivl_expr_t expr)
|
void draw_eval_string(ivl_expr_t expr)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -195,7 +201,7 @@ void draw_eval_string(ivl_expr_t expr)
|
||||||
else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_front")==0)
|
else if (strcmp(ivl_expr_name(expr), "$ivl_darray_method$pop_front")==0)
|
||||||
string_ex_pop(expr);
|
string_ex_pop(expr);
|
||||||
else
|
else
|
||||||
fallback_eval(expr);
|
draw_sfunc_string(expr);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case IVL_EX_UFUNC:
|
case IVL_EX_UFUNC:
|
||||||
|
|
|
||||||
|
|
@ -133,6 +133,7 @@ extern void draw_vpi_task_call(ivl_statement_t net);
|
||||||
|
|
||||||
extern void draw_vpi_func_call(ivl_expr_t expr);
|
extern void draw_vpi_func_call(ivl_expr_t expr);
|
||||||
extern void draw_vpi_rfunc_call(ivl_expr_t expr);
|
extern void draw_vpi_rfunc_call(ivl_expr_t expr);
|
||||||
|
extern void draw_vpi_sfunc_call(ivl_expr_t expr);
|
||||||
|
|
||||||
extern void draw_class_in_scope(ivl_type_t classtype);
|
extern void draw_class_in_scope(ivl_type_t classtype);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ GenerateStatement::~GenerateStatement()
|
||||||
}
|
}
|
||||||
|
|
||||||
ForGenerate::ForGenerate(perm_string gname, perm_string genvar,
|
ForGenerate::ForGenerate(perm_string gname, perm_string genvar,
|
||||||
prange_t*rang, std::list<Architecture::Statement*>&s)
|
ExpRange*rang, std::list<Architecture::Statement*>&s)
|
||||||
: GenerateStatement(gname, s), genvar_(genvar),
|
: GenerateStatement(gname, s), genvar_(genvar),
|
||||||
lsb_(rang->lsb()), msb_(rang->msb())
|
lsb_(rang->lsb()), msb_(rang->msb())
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class GenerateStatement;
|
||||||
class SequentialStmt;
|
class SequentialStmt;
|
||||||
class Signal;
|
class Signal;
|
||||||
class named_expr_t;
|
class named_expr_t;
|
||||||
class prange_t;
|
class ExpRange;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The Architecture class carries the contents (name, statements,
|
* The Architecture class carries the contents (name, statements,
|
||||||
|
|
@ -142,7 +142,7 @@ class ForGenerate : public GenerateStatement {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ForGenerate(perm_string gname, perm_string genvar,
|
ForGenerate(perm_string gname, perm_string genvar,
|
||||||
prange_t*rang, std::list<Architecture::Statement*>&s);
|
ExpRange*rang, std::list<Architecture::Statement*>&s);
|
||||||
~ForGenerate();
|
~ForGenerate();
|
||||||
|
|
||||||
int elaborate(Entity*ent, Architecture*arc);
|
int elaborate(Entity*ent, Architecture*arc);
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
# include "entity.h"
|
# include "entity.h"
|
||||||
# include "expression.h"
|
# include "expression.h"
|
||||||
# include "sequential.h"
|
# include "sequential.h"
|
||||||
|
# include "subprogram.h"
|
||||||
# include <typeinfo>
|
# include <typeinfo>
|
||||||
# include <cassert>
|
# include <cassert>
|
||||||
|
|
||||||
|
|
@ -59,6 +60,11 @@ int Architecture::elaborate(Entity*entity)
|
||||||
cur->second->elaborate_init_expr(entity, this);
|
cur->second->elaborate_init_expr(entity, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Elaborate subprograms
|
||||||
|
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
|
||||||
|
; cur != cur_subprograms_.end() ; ++cur) {
|
||||||
|
errors += cur->second->elaborate();
|
||||||
|
}
|
||||||
// Create 'initial' and 'final' blocks for implicit
|
// Create 'initial' and 'final' blocks for implicit
|
||||||
// initalization and clean-up actions
|
// initalization and clean-up actions
|
||||||
if(!initializers_.empty())
|
if(!initializers_.empty())
|
||||||
|
|
@ -222,7 +228,7 @@ int ProcessStatement::rewrite_as_always_edge_(Entity*, Architecture*)
|
||||||
}
|
}
|
||||||
|
|
||||||
// If operand1 is not an 'event attribute, I give up.
|
// If operand1 is not an 'event attribute, I give up.
|
||||||
const ExpAttribute*op1 = dynamic_cast<const ExpAttribute*>(op1_raw);
|
const ExpObjAttribute*op1 = dynamic_cast<const ExpObjAttribute*>(op1_raw);
|
||||||
if (op1 == 0)
|
if (op1 == 0)
|
||||||
return -1;
|
return -1;
|
||||||
if (op1->peek_attribute() != "event")
|
if (op1->peek_attribute() != "event")
|
||||||
|
|
|
||||||
|
|
@ -101,7 +101,7 @@ void ComponentBase::dump_ports(ostream&out, int indent) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Scope::dump_scope(ostream&out) const
|
void ScopeBase::dump_scope(ostream&out) const
|
||||||
{
|
{
|
||||||
// Dump types
|
// Dump types
|
||||||
out << " -- imported types" << endl;
|
out << " -- imported types" << endl;
|
||||||
|
|
@ -251,9 +251,16 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const
|
||||||
out << setw(indent) << "" << "?choice_t?" << endl;
|
out << setw(indent) << "" << "?choice_t?" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpAttribute::dump(ostream&out, int indent) const
|
void ExpTypeAttribute::dump(ostream&out, int indent) const
|
||||||
{
|
{
|
||||||
out << setw(indent) << "" << "Attribute " << name_
|
out << setw(indent) << "" << "Attribute (type-related) " << name_
|
||||||
|
<< " at " << get_fileline() << endl;
|
||||||
|
base_->show(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpObjAttribute::dump(ostream&out, int indent) const
|
||||||
|
{
|
||||||
|
out << setw(indent) << "" << "Attribute (object-related) " << name_
|
||||||
<< " at " << get_fileline() << endl;
|
<< " at " << get_fileline() << endl;
|
||||||
base_->dump(out, indent+4);
|
base_->dump(out, indent+4);
|
||||||
}
|
}
|
||||||
|
|
@ -442,13 +449,6 @@ void named_expr_t::dump(ostream&out, int indent) const
|
||||||
expr_->dump(out, indent);
|
expr_->dump(out, indent);
|
||||||
}
|
}
|
||||||
|
|
||||||
void prange_t::dump(ostream&out, int indent) const
|
|
||||||
{
|
|
||||||
left_->dump(out, indent);
|
|
||||||
out << setw(indent) << "" << (direction_ ? "downto" : "to");
|
|
||||||
right_->dump(out, indent);
|
|
||||||
}
|
|
||||||
|
|
||||||
ostream& Expression::dump_inline(ostream&out) const
|
ostream& Expression::dump_inline(ostream&out) const
|
||||||
{
|
{
|
||||||
out << typeid(*this).name();
|
out << typeid(*this).name();
|
||||||
|
|
|
||||||
|
|
@ -54,29 +54,88 @@ bool Expression::symbolic_compare(const Expression*) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam)
|
ExpAttribute::ExpAttribute(perm_string nam, list<Expression*>*args)
|
||||||
: base_(bas), name_(nam)
|
: name_(nam), args_(args)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpAttribute::~ExpAttribute()
|
ExpAttribute::~ExpAttribute()
|
||||||
{
|
{
|
||||||
/* Different attributes can point to the same base so we cannot delete this here.
|
if(args_) {
|
||||||
* Look at the vhdl_range test with valgrind to see this issue. */
|
for(list<Expression*>::iterator it = args_->begin();
|
||||||
// delete base_;
|
it != args_->end(); ++it) {
|
||||||
|
delete *it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delete args_;
|
||||||
}
|
}
|
||||||
|
|
||||||
Expression*ExpAttribute::clone() const
|
list<Expression*>*ExpAttribute::clone_args() const {
|
||||||
{
|
list<Expression*>*new_args = NULL;
|
||||||
return new ExpAttribute(static_cast<ExpName*>(base_->clone()), name_);
|
|
||||||
|
if(args_) {
|
||||||
|
for(list<Expression*>::iterator it = args_->begin();
|
||||||
|
it != args_->end(); ++it) {
|
||||||
|
new_args->push_back((*it)->clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new_args;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpAttribute::visit(ExprVisitor& func)
|
void ExpAttribute::visit_args(ExprVisitor& func)
|
||||||
{
|
{
|
||||||
|
if(args_) {
|
||||||
|
for(list<Expression*>::iterator it = args_->begin();
|
||||||
|
it != args_->end(); ++it) {
|
||||||
|
func(*it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpObjAttribute::ExpObjAttribute(ExpName*base, perm_string name, list<Expression*>*args)
|
||||||
|
: ExpAttribute(name, args), base_(base)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpObjAttribute::~ExpObjAttribute()
|
||||||
|
{
|
||||||
|
delete base_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression*ExpObjAttribute::clone() const
|
||||||
|
{
|
||||||
|
return new ExpObjAttribute(static_cast<ExpName*>(base_->clone()),
|
||||||
|
name_, clone_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpObjAttribute::visit(ExprVisitor& func)
|
||||||
|
{
|
||||||
|
visit_args(func);
|
||||||
base_->visit(func);
|
base_->visit(func);
|
||||||
func(this);
|
func(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpTypeAttribute::ExpTypeAttribute(const VType*base, perm_string name, list<Expression*>*args)
|
||||||
|
: ExpAttribute(name, args), base_(base)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression*ExpTypeAttribute::clone() const
|
||||||
|
{
|
||||||
|
return new ExpTypeAttribute(base_, name_, clone_args());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpTypeAttribute::visit(ExprVisitor& func)
|
||||||
|
{
|
||||||
|
visit_args(func);
|
||||||
|
func(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
const perm_string ExpAttribute::LEFT = perm_string::literal("left");
|
||||||
|
const perm_string ExpAttribute::RIGHT = perm_string::literal("right");
|
||||||
|
|
||||||
ExpBinary::ExpBinary(Expression*op1, Expression*op2)
|
ExpBinary::ExpBinary(Expression*op1, Expression*op2)
|
||||||
: operand1_(op1), operand2_(op2)
|
: operand1_(op1), operand2_(op2)
|
||||||
{
|
{
|
||||||
|
|
@ -88,14 +147,14 @@ ExpBinary::~ExpBinary()
|
||||||
delete operand2_;
|
delete operand2_;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpBinary::eval_operand1(ScopeBase*scope, int64_t&val) const
|
bool ExpBinary::eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
{
|
{
|
||||||
return operand1_->evaluate(scope, val);
|
return operand1_->evaluate(ent, scope, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpBinary::eval_operand2(ScopeBase*scope, int64_t&val) const
|
bool ExpBinary::eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
{
|
{
|
||||||
return operand2_->evaluate(scope, val);
|
return operand2_->evaluate(ent, scope, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpBinary::visit(ExprVisitor& func)
|
void ExpBinary::visit(ExprVisitor& func)
|
||||||
|
|
@ -192,7 +251,7 @@ ExpAggregate::choice_t::choice_t()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpAggregate::choice_t::choice_t(prange_t*rang)
|
ExpAggregate::choice_t::choice_t(ExpRange*rang)
|
||||||
: range_(rang)
|
: range_(rang)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -203,7 +262,7 @@ ExpAggregate::choice_t::choice_t(const choice_t&other)
|
||||||
expr_.reset(e->clone());
|
expr_.reset(e->clone());
|
||||||
|
|
||||||
if(other.range_.get())
|
if(other.range_.get())
|
||||||
range_.reset(new prange_t(*other.range_.get()));
|
range_.reset(static_cast<ExpRange*>(other.range_.get()->clone()));
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpAggregate::choice_t::~choice_t()
|
ExpAggregate::choice_t::~choice_t()
|
||||||
|
|
@ -221,7 +280,7 @@ Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
prange_t*ExpAggregate::choice_t::range_expressions(void)
|
ExpRange*ExpAggregate::choice_t::range_expressions(void)
|
||||||
{
|
{
|
||||||
return range_.get();
|
return range_.get();
|
||||||
}
|
}
|
||||||
|
|
@ -493,7 +552,7 @@ ExpInteger::~ExpInteger()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpInteger::evaluate(ScopeBase*, int64_t&val) const
|
bool ExpInteger::evaluate(Entity*, ScopeBase*, int64_t&val) const
|
||||||
{
|
{
|
||||||
val = value_;
|
val = value_;
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -535,6 +594,7 @@ ExpName::ExpName(perm_string nn, list<Expression*>*indices)
|
||||||
ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb)
|
ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb)
|
||||||
: name_(nn), index_(msb), lsb_(lsb)
|
: name_(nn), index_(msb), lsb_(lsb)
|
||||||
{
|
{
|
||||||
|
ivl_assert(*this, !msb || msb != lsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpName::ExpName(ExpName*prefix, perm_string nn)
|
ExpName::ExpName(ExpName*prefix, perm_string nn)
|
||||||
|
|
@ -545,6 +605,7 @@ ExpName::ExpName(ExpName*prefix, perm_string nn)
|
||||||
ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb)
|
ExpName::ExpName(ExpName*prefix, perm_string nn, Expression*msb, Expression*lsb)
|
||||||
: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb)
|
: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb)
|
||||||
{
|
{
|
||||||
|
ivl_assert(*this, !msb || msb != lsb);
|
||||||
}
|
}
|
||||||
|
|
||||||
ExpName::~ExpName()
|
ExpName::~ExpName()
|
||||||
|
|
@ -712,3 +773,75 @@ double ExpTime::to_fs() const
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ExpRange::ExpRange(Expression*left, Expression*right, range_dir_t direction)
|
||||||
|
: left_(left), right_(right), direction_(direction), range_expr_(false),
|
||||||
|
range_base_(NULL)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpRange::ExpRange(ExpName*base, bool reverse_range)
|
||||||
|
: left_(NULL), right_(NULL), direction_(AUTO), range_expr_(true),
|
||||||
|
range_base_(base), range_reverse_(reverse_range)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ExpRange::~ExpRange()
|
||||||
|
{
|
||||||
|
delete left_;
|
||||||
|
delete right_;
|
||||||
|
delete range_base_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression*ExpRange::clone() const
|
||||||
|
{
|
||||||
|
if(range_expr_)
|
||||||
|
return new ExpRange(static_cast<ExpName*>(range_base_->clone()), range_reverse_);
|
||||||
|
else
|
||||||
|
return new ExpRange(left_->clone(), right_->clone(), direction_);
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* ExpRange::msb()
|
||||||
|
{
|
||||||
|
ivl_assert(*this, direction() != AUTO);
|
||||||
|
|
||||||
|
switch(direction()) {
|
||||||
|
case DOWNTO: return left_;
|
||||||
|
case TO: return right_;
|
||||||
|
default: return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression* ExpRange::lsb()
|
||||||
|
{
|
||||||
|
ivl_assert(*this, direction() != AUTO);
|
||||||
|
|
||||||
|
switch(direction()) {
|
||||||
|
case DOWNTO: return right_;
|
||||||
|
case TO: return left_;
|
||||||
|
default: return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression*ExpRange::left()
|
||||||
|
{
|
||||||
|
if(range_expr_ && !left_)
|
||||||
|
// TODO check if it is an object or type
|
||||||
|
left_ = new ExpObjAttribute(static_cast<ExpName*>(range_base_->clone()),
|
||||||
|
ExpAttribute::LEFT, NULL);
|
||||||
|
|
||||||
|
return left_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Expression*ExpRange::right()
|
||||||
|
{
|
||||||
|
if(range_expr_ && !right_)
|
||||||
|
// TODO check if it is an object or type
|
||||||
|
right_ = new ExpObjAttribute(static_cast<ExpName*>(range_base_->clone()),
|
||||||
|
ExpAttribute::RIGHT, NULL);
|
||||||
|
return right_;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,7 @@
|
||||||
# include <memory>
|
# include <memory>
|
||||||
# include <vector>
|
# include <vector>
|
||||||
|
|
||||||
class prange_t;
|
class ExpRange;
|
||||||
class Entity;
|
|
||||||
class ScopeBase;
|
class ScopeBase;
|
||||||
class SubprogramHeader;
|
class SubprogramHeader;
|
||||||
class VType;
|
class VType;
|
||||||
|
|
@ -107,8 +106,8 @@ class Expression : public LineInfo {
|
||||||
// to constant literal values. Return true and set the val
|
// to constant literal values. Return true and set the val
|
||||||
// argument if the evaluation works, or return false if it
|
// argument if the evaluation works, or return false if it
|
||||||
// cannot be done.
|
// cannot be done.
|
||||||
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
|
virtual bool evaluate(Entity*, ScopeBase*, int64_t&) const { return false; }
|
||||||
virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
bool evaluate(ScopeBase*scope, int64_t&val) const { return evaluate(NULL, scope, val); }
|
||||||
|
|
||||||
// The symbolic compare returns true if the two expressions
|
// The symbolic compare returns true if the two expressions
|
||||||
// are equal without actually calculating the value.
|
// are equal without actually calculating the value.
|
||||||
|
|
@ -125,7 +124,7 @@ class Expression : public LineInfo {
|
||||||
virtual void dump(ostream&out, int indent = 0) const =0;
|
virtual void dump(ostream&out, int indent = 0) const =0;
|
||||||
virtual ostream& dump_inline(ostream&out) const;
|
virtual ostream& dump_inline(ostream&out) const;
|
||||||
|
|
||||||
// Recursively visits a tree of expressions (useful of complex expressions).
|
// Recursively visits a tree of expressions (useful for complex expressions).
|
||||||
virtual void visit(ExprVisitor& func) { func(this); }
|
virtual void visit(ExprVisitor& func) { func(this); }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
@ -205,8 +204,8 @@ class ExpBinary : public Expression {
|
||||||
int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit_operand1(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit_operand2(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
|
||||||
bool eval_operand1(ScopeBase*scope, int64_t&val) const;
|
bool eval_operand1(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
bool eval_operand2(ScopeBase*scope, int64_t&val) const;
|
bool eval_operand2(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
|
|
||||||
inline void write_to_stream_operand1(std::ostream&out) const
|
inline void write_to_stream_operand1(std::ostream&out) const
|
||||||
{ operand1_->write_to_stream(out); }
|
{ operand1_->write_to_stream(out); }
|
||||||
|
|
@ -239,7 +238,7 @@ class ExpAggregate : public Expression {
|
||||||
// Create a named choice
|
// Create a named choice
|
||||||
explicit choice_t(perm_string name);
|
explicit choice_t(perm_string name);
|
||||||
// discreate_range choice
|
// discreate_range choice
|
||||||
explicit choice_t(prange_t*ran);
|
explicit choice_t(ExpRange*ran);
|
||||||
|
|
||||||
choice_t(const choice_t&other);
|
choice_t(const choice_t&other);
|
||||||
|
|
||||||
|
|
@ -249,15 +248,15 @@ class ExpAggregate : public Expression {
|
||||||
bool others() const;
|
bool others() const;
|
||||||
// Return expression if this represents a simple_expression.
|
// Return expression if this represents a simple_expression.
|
||||||
Expression*simple_expression(bool detach_flag =true);
|
Expression*simple_expression(bool detach_flag =true);
|
||||||
// Return prange_t if this represents a range_expression
|
// Return ExpRange if this represents a range_expression
|
||||||
prange_t*range_expressions(void);
|
ExpRange*range_expressions(void);
|
||||||
|
|
||||||
void write_to_stream(std::ostream&fd);
|
void write_to_stream(std::ostream&fd);
|
||||||
void dump(ostream&out, int indent) const;
|
void dump(ostream&out, int indent) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::auto_ptr<Expression>expr_;
|
std::auto_ptr<Expression>expr_;
|
||||||
std::auto_ptr<prange_t> range_;
|
std::auto_ptr<ExpRange> range_;
|
||||||
private: // not implemented
|
private: // not implemented
|
||||||
choice_t& operator= (const choice_t&);
|
choice_t& operator= (const choice_t&);
|
||||||
};
|
};
|
||||||
|
|
@ -343,7 +342,7 @@ class ExpArithmetic : public ExpBinary {
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
|
virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -356,18 +355,60 @@ class ExpArithmetic : public ExpBinary {
|
||||||
class ExpAttribute : public Expression {
|
class ExpAttribute : public Expression {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ExpAttribute(ExpName*base, perm_string name);
|
ExpAttribute(perm_string name,std::list<Expression*>*args);
|
||||||
~ExpAttribute();
|
virtual ~ExpAttribute();
|
||||||
|
|
||||||
|
inline perm_string peek_attribute() const { return name_; }
|
||||||
|
|
||||||
|
// Constants for the standard attributes
|
||||||
|
static const perm_string LEFT;
|
||||||
|
static const perm_string RIGHT;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::list<Expression*>*clone_args() const;
|
||||||
|
void visit_args(ExprVisitor& func);
|
||||||
|
bool evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
|
bool test_array_type(const VType*type) const;
|
||||||
|
|
||||||
|
perm_string name_;
|
||||||
|
std::list<Expression*>*args_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpObjAttribute : public ExpAttribute {
|
||||||
|
public:
|
||||||
|
ExpObjAttribute(ExpName*base, perm_string name, std::list<Expression*>*args);
|
||||||
|
~ExpObjAttribute();
|
||||||
|
|
||||||
Expression*clone() const;
|
Expression*clone() const;
|
||||||
|
|
||||||
inline perm_string peek_attribute() const { return name_; }
|
|
||||||
inline const ExpName* peek_base() const { return base_; }
|
inline const ExpName* peek_base() const { return base_; }
|
||||||
|
|
||||||
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
|
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
|
// Some attributes can be evaluated at compile time
|
||||||
|
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
void visit(ExprVisitor& func);
|
||||||
|
|
||||||
|
private:
|
||||||
|
ExpName*base_;
|
||||||
|
};
|
||||||
|
|
||||||
|
class ExpTypeAttribute : public ExpAttribute {
|
||||||
|
public:
|
||||||
|
ExpTypeAttribute(const VType*base, perm_string name, std::list<Expression*>*args);
|
||||||
|
// no destructor - VType objects (base_) are shared between many expressions
|
||||||
|
|
||||||
|
Expression*clone() const;
|
||||||
|
|
||||||
|
inline const VType* peek_base() const { return base_; }
|
||||||
|
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
const VType*probe_type(Entity*ent, ScopeBase*scope) const;
|
||||||
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
|
void write_to_stream(std::ostream&fd) const;
|
||||||
// Some attributes can be evaluated at compile time
|
// Some attributes can be evaluated at compile time
|
||||||
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
||||||
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
|
|
@ -375,8 +416,7 @@ class ExpAttribute : public Expression {
|
||||||
void visit(ExprVisitor& func);
|
void visit(ExprVisitor& func);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ExpName*base_;
|
const VType*base_;
|
||||||
perm_string name_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ExpBitstring : public Expression {
|
class ExpBitstring : public Expression {
|
||||||
|
|
@ -440,7 +480,6 @@ class ExpConcat : public Expression {
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
|
|
||||||
bool is_primary(void) const;
|
bool is_primary(void) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
void visit(ExprVisitor& func);
|
void visit(ExprVisitor& func);
|
||||||
|
|
@ -583,7 +622,7 @@ class ExpInteger : public Expression {
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
int emit_package(std::ostream&out);
|
int emit_package(std::ostream&out);
|
||||||
bool is_primary(void) const { return true; }
|
bool is_primary(void) const { return true; }
|
||||||
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
virtual ostream& dump_inline(ostream&out) const;
|
virtual ostream& dump_inline(ostream&out) const;
|
||||||
|
|
||||||
|
|
@ -665,7 +704,6 @@ class ExpName : public Expression {
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
bool is_primary(void) const;
|
bool is_primary(void) const;
|
||||||
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
|
||||||
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
bool symbolic_compare(const Expression*that) const;
|
bool symbolic_compare(const Expression*that) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
@ -773,7 +811,7 @@ class ExpShift : public ExpBinary {
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
|
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -891,7 +929,6 @@ class ExpTime : public Expression {
|
||||||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
void write_to_stream(std::ostream&) const;
|
void write_to_stream(std::ostream&) const;
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
//bool evaluate(ScopeBase*scope, int64_t&val) const;
|
|
||||||
//bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
//bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||||
void dump(ostream&out, int indent = 0) const;
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
|
||||||
|
|
@ -902,6 +939,46 @@ class ExpTime : public Expression {
|
||||||
timeunit_t unit_;
|
timeunit_t unit_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ExpRange : public Expression {
|
||||||
|
public:
|
||||||
|
typedef enum { DOWNTO, TO, AUTO } range_dir_t;
|
||||||
|
|
||||||
|
// Regular range
|
||||||
|
ExpRange(Expression*left, Expression*right, range_dir_t direction);
|
||||||
|
// 'range/'reverse range attribute
|
||||||
|
ExpRange(ExpName*base, bool reverse_range);
|
||||||
|
~ExpRange();
|
||||||
|
|
||||||
|
Expression*clone() const;
|
||||||
|
|
||||||
|
// Returns the upper boundary
|
||||||
|
Expression*msb();
|
||||||
|
// Returns the lower boundary
|
||||||
|
Expression*lsb();
|
||||||
|
|
||||||
|
Expression*left();
|
||||||
|
Expression*right();
|
||||||
|
|
||||||
|
range_dir_t direction() const { return direction_; }
|
||||||
|
|
||||||
|
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||||
|
void write_to_stream(std::ostream&) const;
|
||||||
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
void dump(ostream&out, int indent = 0) const;
|
||||||
|
private:
|
||||||
|
// Regular range related fields
|
||||||
|
Expression*left_, *right_;
|
||||||
|
range_dir_t direction_;
|
||||||
|
|
||||||
|
// 'range/'reverse_range attribute related fields
|
||||||
|
// Flag to indicate it is a 'range/'reverse_range expression
|
||||||
|
bool range_expr_;
|
||||||
|
// Object name to which the attribute is applied
|
||||||
|
ExpName*range_base_;
|
||||||
|
// Flag to distinguish between 'range & 'reverse_range
|
||||||
|
bool range_reverse_;
|
||||||
|
};
|
||||||
|
|
||||||
// Elaborates an expression used as an argument in a procedure/function call.
|
// Elaborates an expression used as an argument in a procedure/function call.
|
||||||
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
|
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
|
||||||
int idx, Entity*ent, ScopeBase*scope);
|
int idx, Entity*ent, ScopeBase*scope);
|
||||||
|
|
|
||||||
|
|
@ -117,3 +117,9 @@ void ExpTime::dump(ostream&out, int indent) const
|
||||||
out << setw(indent) << "" << "Time ";
|
out << setw(indent) << "" << "Time ";
|
||||||
write_to_stream(out);
|
write_to_stream(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpRange::dump(ostream&out, int indent) const
|
||||||
|
{
|
||||||
|
out << setw(indent) << "" << "Range ";
|
||||||
|
write_to_stream(out);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -57,7 +57,8 @@ const VType* Expression::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope, const VType*type)
|
const VType*ExpName::elaborate_adjust_type_with_range_(Entity*ent, ScopeBase*scope,
|
||||||
|
const VType*type)
|
||||||
{
|
{
|
||||||
// Unfold typedefs
|
// Unfold typedefs
|
||||||
while (const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(type)) {
|
while (const VTypeDef*tdef = dynamic_cast<const VTypeDef*>(type)) {
|
||||||
|
|
@ -76,9 +77,9 @@ const VType*ExpName::elaborate_adjust_type_with_range_(Entity*, ScopeBase*scope,
|
||||||
int64_t use_msb, use_lsb;
|
int64_t use_msb, use_lsb;
|
||||||
bool flag;
|
bool flag;
|
||||||
|
|
||||||
flag = index_->evaluate(scope, use_msb);
|
flag = index_->evaluate(ent, scope, use_msb);
|
||||||
ivl_assert(*this, flag);
|
ivl_assert(*this, flag);
|
||||||
flag = lsb_->evaluate(scope, use_lsb);
|
flag = lsb_->evaluate(ent, scope, use_lsb);
|
||||||
ivl_assert(*this, flag);
|
ivl_assert(*this, flag);
|
||||||
|
|
||||||
type = new VTypeArray(array->element_type(), use_msb, use_lsb);
|
type = new VTypeArray(array->element_type(), use_msb, use_lsb);
|
||||||
|
|
@ -216,36 +217,44 @@ int ExpName::elaborate_lval(Entity*ent, ScopeBase*scope, bool is_sequ)
|
||||||
|
|
||||||
const VType*found_type = 0;
|
const VType*found_type = 0;
|
||||||
|
|
||||||
if (const InterfacePort*cur = ent->find_port(name_)) {
|
if (ent) {
|
||||||
if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) {
|
if (const InterfacePort*cur = ent->find_port(name_)) {
|
||||||
cerr << get_fileline() << ": error: Assignment to "
|
if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) {
|
||||||
"input port " << name_ << "." << endl;
|
cerr << get_fileline() << ": error: Assignment to "
|
||||||
return errors += 1;
|
"input port " << name_ << "." << endl;
|
||||||
}
|
return errors += 1;
|
||||||
|
}
|
||||||
|
|
||||||
if (is_sequ)
|
if (is_sequ)
|
||||||
ent->set_declaration_l_value(name_, is_sequ);
|
ent->set_declaration_l_value(name_, is_sequ);
|
||||||
|
|
||||||
found_type = cur->type;
|
found_type = cur->type;
|
||||||
|
|
||||||
} else if (ent->find_generic(name_)) {
|
} else if (ent->find_generic(name_)) {
|
||||||
|
|
||||||
cerr << get_fileline() << ": error: Assignment to generic "
|
cerr << get_fileline() << ": error: Assignment to generic "
|
||||||
<< name_ << " from entity "
|
<< name_ << " from entity "
|
||||||
<< ent->get_name() << "." << endl;
|
<< ent->get_name() << "." << endl;
|
||||||
return 1;
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} else if (Signal*sig = scope->find_signal(name_)) {
|
if (!found_type && scope) {
|
||||||
// Tell the target signal that this may be a sequential l-value.
|
if (Signal*sig = scope->find_signal(name_)) {
|
||||||
if (is_sequ) sig->count_ref_sequ();
|
// Tell the target signal that this may be a sequential l-value.
|
||||||
|
if (is_sequ) sig->count_ref_sequ();
|
||||||
|
|
||||||
found_type = sig->peek_type();
|
found_type = sig->peek_type();
|
||||||
|
|
||||||
} else if (Variable*var = scope->find_variable(name_)) {
|
} else if (Variable*var = scope->find_variable(name_)) {
|
||||||
// Tell the target signal that this may be a sequential l-value.
|
// Tell the target signal that this may be a sequential l-value.
|
||||||
if (is_sequ) var->count_ref_sequ();
|
if (is_sequ) var->count_ref_sequ();
|
||||||
|
|
||||||
found_type = var->peek_type();
|
found_type = var->peek_type();
|
||||||
|
|
||||||
|
} else if (const InterfacePort*port = scope->find_param(name_)) {
|
||||||
|
found_type = port->type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (found_type == 0) {
|
if (found_type == 0) {
|
||||||
|
|
@ -318,7 +327,8 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva
|
||||||
|
|
||||||
int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
int Expression::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
||||||
{
|
{
|
||||||
cerr << get_fileline() << ": internal error: I don't know how to elaborate expression type=" << typeid(*this).name() << endl;
|
cerr << get_fileline() << ": internal error: I don't know how to "
|
||||||
|
<< "elaborate expression type=" << typeid(*this).name() << endl;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,7 +403,7 @@ const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) c
|
||||||
elements_[0]->map_choices(&ce[0]);
|
elements_[0]->map_choices(&ce[0]);
|
||||||
|
|
||||||
ivl_assert(*this, ce.size() == 1);
|
ivl_assert(*this, ce.size() == 1);
|
||||||
prange_t*prange = ce[0].choice->range_expressions();
|
ExpRange*prange = ce[0].choice->range_expressions();
|
||||||
ivl_assert(*this, prange);
|
ivl_assert(*this, prange);
|
||||||
|
|
||||||
Expression*use_msb = prange->msb();
|
Expression*use_msb = prange->msb();
|
||||||
|
|
@ -573,23 +583,32 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VType* ExpAttribute::probe_type(Entity*ent, ScopeBase*scope) const
|
int ExpObjAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
|
||||||
{
|
{
|
||||||
base_->probe_type(ent, scope);
|
const VType*sub_type = base_->probe_type(ent, scope);
|
||||||
|
return base_->elaborate_expr(ent, scope, sub_type);
|
||||||
|
}
|
||||||
|
|
||||||
if (name_ == "length" || name_ == "left" || name_ == "right") {
|
const VType* ExpObjAttribute::probe_type(Entity*, ScopeBase*) const
|
||||||
|
{
|
||||||
|
if (name_ == "length" || name_ == "left" || name_ == "right")
|
||||||
return &primitive_NATURAL;
|
return &primitive_NATURAL;
|
||||||
}
|
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
||||||
|
{
|
||||||
|
// This is just to mute warnings, there is nothing to elaborate here
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExpAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
|
const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const
|
||||||
{
|
{
|
||||||
int errors = 0;
|
if(name_ == "image")
|
||||||
const VType*sub_type = base_->probe_type(ent, scope);
|
return &primitive_STRING;
|
||||||
errors += base_->elaborate_expr(ent, scope, sub_type);
|
|
||||||
return errors;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const VType*ExpBitstring::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const
|
const VType*ExpBitstring::fit_type(Entity*, ScopeBase*, const VTypeArray*atype) const
|
||||||
|
|
@ -648,8 +667,8 @@ const VType*ExpConcat::fit_type(Entity*ent, ScopeBase*scope, const VTypeArray*at
|
||||||
new ExpArithmetic(ExpArithmetic::PLUS, sizes[0], sizes[1]),
|
new ExpArithmetic(ExpArithmetic::PLUS, sizes[0], sizes[1]),
|
||||||
new ExpInteger(1));
|
new ExpInteger(1));
|
||||||
|
|
||||||
std::list<prange_t*> ranges;
|
std::list<ExpRange*> ranges;
|
||||||
ranges.push_front(new prange_t(size, new ExpInteger(0), true));
|
ranges.push_front(new ExpRange(size, new ExpInteger(0), ExpRange::DOWNTO));
|
||||||
const VType*array = new VTypeArray(types[1], &ranges);
|
const VType*array = new VTypeArray(types[1], &ranges);
|
||||||
|
|
||||||
return array;
|
return array;
|
||||||
|
|
@ -912,31 +931,31 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const
|
||||||
|
|
||||||
if(ent) {
|
if(ent) {
|
||||||
if (const InterfacePort*cur = ent->find_port(name_)) {
|
if (const InterfacePort*cur = ent->find_port(name_)) {
|
||||||
ivl_assert(*this, cur->type);
|
ivl_assert(*this, cur->type);
|
||||||
return cur->type;
|
return cur->type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const InterfacePort*cur = ent->find_generic(name_)) {
|
if (const InterfacePort*cur = ent->find_generic(name_)) {
|
||||||
ivl_assert(*this, cur->type);
|
ivl_assert(*this, cur->type);
|
||||||
return cur->type;
|
return cur->type;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(scope) {
|
if(scope) {
|
||||||
if (Signal*sig = scope->find_signal(name_))
|
if (Signal*sig = scope->find_signal(name_))
|
||||||
return sig->peek_type();
|
return sig->peek_type();
|
||||||
|
|
||||||
if (Variable*var = scope->find_variable(name_))
|
if (Variable*var = scope->find_variable(name_))
|
||||||
return var->peek_type();
|
return var->peek_type();
|
||||||
|
|
||||||
const VType*type = 0;
|
const VType*type = 0;
|
||||||
Expression*cval = 0;
|
Expression*cval = 0;
|
||||||
if (scope->find_constant(name_, type, cval))
|
if (scope->find_constant(name_, type, cval))
|
||||||
return type;
|
return type;
|
||||||
|
|
||||||
Architecture*arc = dynamic_cast<Architecture*>(scope);
|
Architecture*arc = dynamic_cast<Architecture*>(scope);
|
||||||
if (arc && (type = arc->probe_genvar_type(name_))) {
|
if (arc && (type = arc->probe_genvar_type(name_))) {
|
||||||
return type;
|
return type;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const InterfacePort*port = scope->find_param(name_)) {
|
if (const InterfacePort*port = scope->find_param(name_)) {
|
||||||
|
|
@ -1048,6 +1067,19 @@ int ExpTime::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ExpRange::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
if(left_)
|
||||||
|
errors += left_->elaborate_expr(ent, scope, &primitive_INTEGER);
|
||||||
|
|
||||||
|
if(right_)
|
||||||
|
errors += right_->elaborate_expr(ent, scope, &primitive_INTEGER);
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
|
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
|
||||||
int idx, Entity*ent, ScopeBase*scope)
|
int idx, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -224,7 +224,7 @@ int ExpAggregate::emit_array_(ostream&out, Entity*ent, ScopeBase*scope, const VT
|
||||||
// If this is a range choice, then calculate the bounds
|
// If this is a range choice, then calculate the bounds
|
||||||
// of the range and scan through the values, mapping the
|
// of the range and scan through the values, mapping the
|
||||||
// value to the aggregate_[idx] element.
|
// value to the aggregate_[idx] element.
|
||||||
if (prange_t*range = aggregate_[idx].choice->range_expressions()) {
|
if (ExpRange*range = aggregate_[idx].choice->range_expressions()) {
|
||||||
int64_t begin_val, end_val;
|
int64_t begin_val, end_val;
|
||||||
|
|
||||||
if (! range->msb()->evaluate(ent, scope, begin_val)) {
|
if (! range->msb()->evaluate(ent, scope, begin_val)) {
|
||||||
|
|
@ -331,13 +331,13 @@ int ExpAggregate::emit_record_(ostream&out, Entity*ent, ScopeBase*scope, const V
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
// Try to evaluate first
|
// Try to evaluate first
|
||||||
int64_t val;
|
int64_t val;
|
||||||
if(evaluate(scope, val)) {
|
if(evaluate(ent, scope, val)) {
|
||||||
out << val;
|
out << val;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -365,12 +365,50 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fallback
|
||||||
out << "$ivl_attribute(";
|
out << "$ivl_attribute(";
|
||||||
errors += base_->emit(out, ent, scope);
|
errors += base_->emit(out, ent, scope);
|
||||||
out << ", \"" << name_ << "\")";
|
out << ", \"" << name_ << "\")";
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ExpTypeAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
// Special case: The image attribute
|
||||||
|
if (name_=="image") {
|
||||||
|
if(!args_ || args_->size() != 1) {
|
||||||
|
out << "/* Invalid 'image attribute */" << endl;
|
||||||
|
cerr << get_fileline() << ": error: 'image attribute takes "
|
||||||
|
<< "exactly one argument." << endl;
|
||||||
|
++errors;
|
||||||
|
} else {
|
||||||
|
out << "$sformatf(\"";
|
||||||
|
|
||||||
|
if(base_->type_match(&primitive_INTEGER))
|
||||||
|
out << "%0d";
|
||||||
|
else if(base_->type_match(&primitive_REAL))
|
||||||
|
out << "%f";
|
||||||
|
else if(base_->type_match(&primitive_CHARACTER))
|
||||||
|
out << "'%c'";
|
||||||
|
else if(base_->type_match(&primitive_TIME))
|
||||||
|
out << "%+0t";
|
||||||
|
|
||||||
|
out << "\",";
|
||||||
|
args_->front()->emit(out, ent, scope);
|
||||||
|
out << ")";
|
||||||
|
}
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback
|
||||||
|
out << "$ivl_attribute(";
|
||||||
|
errors += base_->emit_def(out, empty_perm_string);
|
||||||
|
out << ", \"" << name_ << "\")";
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
int ExpArithmetic::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
@ -453,17 +491,16 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*,
|
||||||
int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
const VType*etype = peek_type();
|
const VType*etype = peek_type();
|
||||||
|
const VTypeArray*array;
|
||||||
|
|
||||||
|
if (etype != &primitive_CHARACTER && (array = dynamic_cast<const VTypeArray*>(etype))) {
|
||||||
|
etype = array->element_type();
|
||||||
|
}
|
||||||
|
|
||||||
if (const VTypePrimitive*use_type = dynamic_cast<const VTypePrimitive*>(etype)) {
|
if (const VTypePrimitive*use_type = dynamic_cast<const VTypePrimitive*>(etype)) {
|
||||||
return emit_primitive_bit_(out, ent, scope, use_type);
|
return emit_primitive_bit_(out, ent, scope, use_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (const VTypeArray*array = dynamic_cast<const VTypeArray*>(etype)) {
|
|
||||||
if (const VTypePrimitive*use_type = dynamic_cast<const VTypePrimitive*>(array->element_type())) {
|
|
||||||
return emit_primitive_bit_(out, ent, scope, use_type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
out << "\"" << value_ << "\"";
|
out << "\"" << value_ << "\"";
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -583,7 +620,10 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
ivl_assert(*this, def_);
|
if(!def_) {
|
||||||
|
cerr << get_fileline() << ": error: unknown function: " << name_ << endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
// If this function has an elaborated definition, and if
|
// If this function has an elaborated definition, and if
|
||||||
// that definition is in a package, then include the
|
// that definition is in a package, then include the
|
||||||
|
|
@ -909,10 +949,11 @@ bool ExpString::is_primary(void) const
|
||||||
|
|
||||||
int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope)
|
int ExpString::emit(ostream& out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
|
const VTypeArray*arr;
|
||||||
const VType*type = peek_type();
|
const VType*type = peek_type();
|
||||||
assert(type != 0);
|
assert(type != 0);
|
||||||
|
|
||||||
if (const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type)) {
|
if (type != &primitive_STRING && (arr = dynamic_cast<const VTypeArray*>(type))) {
|
||||||
return emit_as_array_(out, ent, scope, arr);
|
return emit_as_array_(out, ent, scope, arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1028,3 +1069,25 @@ int ExpTime::emit(ostream&out, Entity*, ScopeBase*)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ExpRange::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
if(range_expr_) {
|
||||||
|
out << "$left(";
|
||||||
|
errors += range_base_->emit(out, ent, scope);
|
||||||
|
out << "):$right(";
|
||||||
|
errors += range_base_->emit(out, ent, scope);
|
||||||
|
out << ")";
|
||||||
|
} else if(direction_ == AUTO) {
|
||||||
|
ivl_assert(*this, false);
|
||||||
|
out << "/* auto dir */";
|
||||||
|
} else {
|
||||||
|
errors += left_->emit(out, ent, scope);
|
||||||
|
out << ":";
|
||||||
|
errors += right_->emit(out, ent, scope);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -25,26 +25,16 @@
|
||||||
# include <limits>
|
# include <limits>
|
||||||
# include <cmath>
|
# include <cmath>
|
||||||
|
|
||||||
bool Expression::evaluate(ScopeBase*, int64_t&) const
|
bool ExpArithmetic::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Expression::evaluate(Entity*, ScopeBase*scope, int64_t&val) const
|
|
||||||
{
|
|
||||||
return evaluate(scope, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const
|
|
||||||
{
|
{
|
||||||
int64_t val1, val2;
|
int64_t val1, val2;
|
||||||
bool rc;
|
bool rc;
|
||||||
|
|
||||||
rc = eval_operand1(scope, val1);
|
rc = eval_operand1(ent, scope, val1);
|
||||||
if (rc == false)
|
if (rc == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rc = eval_operand2(scope, val2);
|
rc = eval_operand2(ent, scope, val2);
|
||||||
if (rc == false)
|
if (rc == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -83,151 +73,110 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpAttribute::evaluate(ScopeBase*scope, int64_t&val) const
|
bool ExpAttribute::test_array_type(const VType*type) const
|
||||||
{
|
{
|
||||||
/* Special Case: The array attributes can sometimes be calculated all
|
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
|
||||||
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" || name_ == "right" || name_ == "left") {
|
|
||||||
const VType*base_type = base_->peek_type();
|
|
||||||
|
|
||||||
if(!base_type) {
|
if (arr == 0) {
|
||||||
const ExpName*name = NULL;
|
cerr << endl << get_fileline() << ": error: "
|
||||||
|
<< "Cannot apply the '" << name_ << " attribute to non-array objects"
|
||||||
|
<< endl;
|
||||||
|
ivl_assert(*this, false);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if(scope && (name = dynamic_cast<const ExpName*>(base_))) {
|
if (arr->dimensions() > 1) {
|
||||||
const perm_string& n = name->peek_name();
|
cerr << endl << get_fileline() << ": error: "
|
||||||
if(const Variable*var = scope->find_variable(n))
|
<< "Cannot apply the '" << name_
|
||||||
base_type = var->peek_type();
|
<< " attribute to multidimensional arrays" << endl;
|
||||||
else if(const Signal*sig = scope->find_signal(n))
|
return false;
|
||||||
base_type = sig->peek_type();
|
}
|
||||||
else if(const InterfacePort*port = scope->find_param(n))
|
|
||||||
base_type = port->type;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!base_type)
|
if (arr->dimension(0).is_box())
|
||||||
return false; // I tried really hard, sorry
|
return false;
|
||||||
|
|
||||||
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
|
return true;
|
||||||
if (arr == 0) {
|
}
|
||||||
cerr << endl << get_fileline() << ": error: "
|
|
||||||
<< "Cannot apply the '" << name_ << " attribute to non-array objects"
|
|
||||||
<< endl;
|
|
||||||
ivl_assert(*this, false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(name_ == "length") {
|
bool ExpAttribute::evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
int64_t size = arr->get_width(scope);
|
{
|
||||||
|
if (name_ == "length" && test_array_type(type)) {
|
||||||
|
int64_t size = type->get_width(scope);
|
||||||
|
|
||||||
if(size > 0)
|
if(size > 0) {
|
||||||
val = size;
|
val = size;
|
||||||
else
|
return true;
|
||||||
return false;
|
}
|
||||||
} else if(name_ == "left") {
|
} else if (name_ == "left" && test_array_type(type)) {
|
||||||
arr->dimension(0).msb()->evaluate(scope, val);
|
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
|
||||||
} else if(name_ == "right") {
|
return arr->dimension(0).msb()->evaluate(ent, scope, val);
|
||||||
arr->dimension(0).lsb()->evaluate(scope, val);
|
} else if (name_ == "right" && test_array_type(type)) {
|
||||||
} else ivl_assert(*this, false);
|
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
|
||||||
|
return arr->dimension(0).lsb()->evaluate(ent, scope, val);
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
bool ExpObjAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
{
|
{
|
||||||
if (!ent || !scope) { // it's impossible to evaluate, probably it is inside a subprogram
|
const VType*base_type = base_->peek_type();
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (name_ == "left" || name_ == "right") {
|
if (base_type == NULL)
|
||||||
const VType*base_type = base_->peek_type();
|
base_type = base_->probe_type(ent, scope);
|
||||||
if (base_type == 0)
|
|
||||||
base_type = base_->probe_type(ent, scope);
|
|
||||||
|
|
||||||
ivl_assert(*this, base_type);
|
if (base_type)
|
||||||
|
return evaluate_type_attr(base_type, ent, scope, val);
|
||||||
|
|
||||||
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(base_type);
|
|
||||||
if (arr == 0) {
|
|
||||||
cerr << endl << get_fileline() << ": error: "
|
|
||||||
<< "Cannot apply the '" << name_
|
|
||||||
<< " attribute to non-array objects" << endl;
|
|
||||||
ivl_assert(*this, false);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
ivl_assert(*this, arr->dimensions() == 1);
|
|
||||||
if(name_ == "left")
|
|
||||||
arr->dimension(0).msb()->evaluate(ent, scope, val);
|
|
||||||
else // "right"
|
|
||||||
arr->dimension(0).lsb()->evaluate(ent, scope, val);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return evaluate(scope, val);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* I don't yet know how to evaluate concatenations. It is not likely
|
|
||||||
* to come up anyhow.
|
|
||||||
*/
|
|
||||||
bool ExpConcat::evaluate(ScopeBase*, int64_t&) const
|
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
|
bool ExpTypeAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
{
|
{
|
||||||
const VType*type;
|
return evaluate_type_attr(base_, ent, scope, val);
|
||||||
Expression*exp;
|
|
||||||
|
|
||||||
if (prefix_.get()) {
|
|
||||||
cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!scope)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (!scope->find_constant(name_, type, exp))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return exp->evaluate(scope, val);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
{
|
{
|
||||||
if (prefix_.get()) {
|
if (prefix_.get()) {
|
||||||
cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl;
|
cerr << get_fileline() << ": sorry: I don't know how to evaluate "
|
||||||
return false;
|
<< "ExpName prefix parts." << endl;
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const InterfacePort*gen = ent->find_generic(name_);
|
if (ent) {
|
||||||
if (gen) {
|
const InterfacePort*gen = ent->find_generic(name_);
|
||||||
cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl;
|
if (gen) {
|
||||||
|
cerr << get_fileline() << ": sorry: I don't necessarily "
|
||||||
|
<< "handle generic overrides." << endl;
|
||||||
|
|
||||||
// Evaluate the default expression and use that.
|
// Evaluate the default expression and use that.
|
||||||
if (gen->expr)
|
if (gen->expr)
|
||||||
return gen->expr->evaluate(ent, scope, val);
|
return gen->expr->evaluate(ent, scope, val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return evaluate(scope, val);
|
if (scope) {
|
||||||
|
const VType*type;
|
||||||
|
Expression*exp;
|
||||||
|
|
||||||
|
if (scope->find_constant(name_, type, exp))
|
||||||
|
return exp->evaluate(ent, scope, val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const
|
bool ExpShift::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||||
{
|
{
|
||||||
int64_t val1, val2;
|
int64_t val1, val2;
|
||||||
bool rc;
|
bool rc;
|
||||||
|
|
||||||
rc = eval_operand1(scope, val1);
|
rc = eval_operand1(ent, scope, val1);
|
||||||
if (rc == false)
|
if (rc == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
rc = eval_operand2(scope, val2);
|
rc = eval_operand2(ent, scope, val2);
|
||||||
if (rc == false)
|
if (rc == false)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -252,7 +201,7 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*bool ExpTime::evaluate(ScopeBase*, int64_t&val) const
|
/*bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const
|
||||||
{
|
{
|
||||||
double v = to_fs();
|
double v = to_fs();
|
||||||
|
|
||||||
|
|
@ -265,8 +214,4 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const
|
||||||
val = v;
|
val = v;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const
|
|
||||||
{
|
|
||||||
return evaluate(NULL, val);
|
|
||||||
}*/
|
}*/
|
||||||
|
|
|
||||||
|
|
@ -61,13 +61,9 @@ void ExpAggregate::choice_t::write_to_stream(ostream&fd)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prange_t*rp = range_expressions()) {
|
if (ExpRange*rp = range_expressions()) {
|
||||||
rp->msb()->write_to_stream(fd);
|
rp->write_to_stream(fd);
|
||||||
if (rp->is_downto())
|
return;
|
||||||
fd << " downto ";
|
|
||||||
else
|
|
||||||
fd << " to ";
|
|
||||||
rp->msb()->write_to_stream(fd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fd << "/* ERROR */";
|
fd << "/* ERROR */";
|
||||||
|
|
@ -111,7 +107,13 @@ void ExpArithmetic::write_to_stream(ostream&out) const
|
||||||
out << ")";
|
out << ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExpAttribute::write_to_stream(ostream&fd) const
|
void ExpObjAttribute::write_to_stream(ostream&fd) const
|
||||||
|
{
|
||||||
|
base_->write_to_stream(fd);
|
||||||
|
fd << "'" << name_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExpTypeAttribute::write_to_stream(ostream&fd) const
|
||||||
{
|
{
|
||||||
base_->write_to_stream(fd);
|
base_->write_to_stream(fd);
|
||||||
fd << "'" << name_;
|
fd << "'" << name_;
|
||||||
|
|
@ -316,3 +318,19 @@ void ExpTime::write_to_stream(ostream&fd) const
|
||||||
case S: fd << " s"; break;
|
case S: fd << " s"; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ExpRange::write_to_stream(ostream&fd) const
|
||||||
|
{
|
||||||
|
if(range_expr_) {
|
||||||
|
range_base_->write_to_stream(fd);
|
||||||
|
fd << (range_reverse_ ? "'reverse_range" : "'range");
|
||||||
|
} else {
|
||||||
|
left_->write_to_stream(fd);
|
||||||
|
switch(direction_) {
|
||||||
|
case DOWNTO: fd << " downto "; break;
|
||||||
|
case TO: fd << " to "; break;
|
||||||
|
default: ivl_assert(*this, false); break;
|
||||||
|
}
|
||||||
|
right_->write_to_stream(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -417,3 +417,27 @@ int emit_packages(void)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int elaborate_library_packages(map<perm_string,Package*>packages)
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for (map<perm_string,Package*>::iterator cur = packages.begin()
|
||||||
|
; cur != packages.end() ; ++cur) {
|
||||||
|
errors += cur->second->elaborate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
|
int elaborate_libraries()
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for (map<perm_string,struct library_contents>::iterator cur = libraries.begin()
|
||||||
|
; cur != libraries.end() ; ++cur) {
|
||||||
|
errors += elaborate_library_packages(cur->second.packages);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ class SubprogramHeader;
|
||||||
extern void library_set_work_path(const char*work_path);
|
extern void library_set_work_path(const char*work_path);
|
||||||
extern void library_add_directory(const char*directory);
|
extern void library_add_directory(const char*directory);
|
||||||
|
|
||||||
|
int elaborate_libraries(void);
|
||||||
|
int emit_packages(void);
|
||||||
|
|
||||||
extern SubprogramHeader*library_find_subprogram(perm_string name);
|
extern SubprogramHeader*library_find_subprogram(perm_string name);
|
||||||
|
|
||||||
#endif /* IVL_library_H */
|
#endif /* IVL_library_H */
|
||||||
|
|
|
||||||
|
|
@ -236,20 +236,27 @@ int main(int argc, char*argv[])
|
||||||
return 3;
|
return 3;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
errors = elaborate_libraries();
|
||||||
|
if (errors > 0) {
|
||||||
|
fprintf(stderr, "%d errors elaborating libraries.\n", errors);
|
||||||
|
parser_cleanup();
|
||||||
|
return 4;
|
||||||
|
}
|
||||||
|
|
||||||
emit_std_types(cout);
|
emit_std_types(cout);
|
||||||
|
|
||||||
errors = emit_packages();
|
errors = emit_packages();
|
||||||
if (errors > 0) {
|
if (errors > 0) {
|
||||||
fprintf(stderr, "%d errors emitting packages.\n", errors);
|
fprintf(stderr, "%d errors emitting packages.\n", errors);
|
||||||
parser_cleanup();
|
parser_cleanup();
|
||||||
return 4;
|
return 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
errors = emit_entities();
|
errors = emit_entities();
|
||||||
if (errors > 0) {
|
if (errors > 0) {
|
||||||
fprintf(stderr, "%d errors emitting design.\n", errors);
|
fprintf(stderr, "%d errors emitting design.\n", errors);
|
||||||
parser_cleanup();
|
parser_cleanup();
|
||||||
return 4;
|
return 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
parser_cleanup();
|
parser_cleanup();
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,18 @@ void Package::set_library(perm_string lname)
|
||||||
from_library_ = lname;
|
from_library_ = lname;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int Package::elaborate()
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for (map<perm_string,SubprogramHeader*>::const_iterator cur = cur_subprograms_.begin()
|
||||||
|
; cur != cur_subprograms_.end() ; ++cur) {
|
||||||
|
errors += cur->second->elaborate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The Package::write_to_stream is used to write the package to the
|
* The Package::write_to_stream is used to write the package to the
|
||||||
* work space (or library) so writes proper VHDL that the library
|
* work space (or library) so writes proper VHDL that the library
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ class Package : public Scope, public LineInfo {
|
||||||
void write_to_stream(std::ostream&fd) const;
|
void write_to_stream(std::ostream&fd) const;
|
||||||
|
|
||||||
int emit_package(std::ostream&fd) const;
|
int emit_package(std::ostream&fd) const;
|
||||||
|
int elaborate();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
perm_string from_library_;
|
perm_string from_library_;
|
||||||
|
|
|
||||||
|
|
@ -87,10 +87,6 @@ static ActiveScope*active_scope = new ActiveScope;
|
||||||
static stack<ActiveScope*> scope_stack;
|
static stack<ActiveScope*> scope_stack;
|
||||||
static SubprogramHeader*active_sub = NULL;
|
static SubprogramHeader*active_sub = NULL;
|
||||||
|
|
||||||
// perm_strings for attributes
|
|
||||||
const static perm_string left_attr = perm_string::literal("left");
|
|
||||||
const static perm_string right_attr = perm_string::literal("right");
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a scope boundary starts, call the push_scope function to push
|
* When a scope boundary starts, call the push_scope function to push
|
||||||
* a scope context. Preload this scope context with the contents of
|
* a scope context. Preload this scope context with the contents of
|
||||||
|
|
@ -245,8 +241,9 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
|
|
||||||
const VType* vtype;
|
const VType* vtype;
|
||||||
|
|
||||||
prange_t* range;
|
ExpRange*range;
|
||||||
std::list<prange_t*>*range_list;
|
std::list<ExpRange*>*range_list;
|
||||||
|
ExpRange::range_dir_t range_dir;
|
||||||
|
|
||||||
ExpArithmetic::fun_t arithmetic_op;
|
ExpArithmetic::fun_t arithmetic_op;
|
||||||
std::list<struct adding_term>*adding_terms;
|
std::list<struct adding_term>*adding_terms;
|
||||||
|
|
@ -305,8 +302,6 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
|
|
||||||
/* The rules may have types. */
|
/* The rules may have types. */
|
||||||
|
|
||||||
%type <flag> direction
|
|
||||||
|
|
||||||
%type <arithmetic_op> adding_operator
|
%type <arithmetic_op> adding_operator
|
||||||
%type <adding_terms> simple_expression_terms
|
%type <adding_terms> simple_expression_terms
|
||||||
|
|
||||||
|
|
@ -341,7 +336,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
%type <expr> variable_declaration_assign_opt waveform_element interface_element_expression
|
%type <expr> variable_declaration_assign_opt waveform_element interface_element_expression
|
||||||
|
|
||||||
%type <expr_list> waveform waveform_elements
|
%type <expr_list> waveform waveform_elements
|
||||||
%type <expr_list> name_list expression_list
|
%type <expr_list> name_list expression_list argument_list argument_list_opt
|
||||||
%type <expr_list> process_sensitivity_list process_sensitivity_list_opt
|
%type <expr_list> process_sensitivity_list process_sensitivity_list_opt
|
||||||
%type <expr_list> selected_names use_clause
|
%type <expr_list> selected_names use_clause
|
||||||
|
|
||||||
|
|
@ -372,6 +367,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
||||||
|
|
||||||
%type <range> range
|
%type <range> range
|
||||||
%type <range_list> range_list index_constraint
|
%type <range_list> range_list index_constraint
|
||||||
|
%type <range_dir> direction
|
||||||
|
|
||||||
%type <case_alt> case_statement_alternative
|
%type <case_alt> case_statement_alternative
|
||||||
%type <case_alt_list> case_statement_alternative_list
|
%type <case_alt_list> case_statement_alternative_list
|
||||||
|
|
@ -448,11 +444,18 @@ architecture_statement_part
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
argument_list : '(' expression_list ')' { $$ = $2; };
|
||||||
|
|
||||||
|
argument_list_opt
|
||||||
|
: argument_list { $$ = $1; }
|
||||||
|
| { $$ = 0; }
|
||||||
|
;
|
||||||
|
|
||||||
assertion_statement
|
assertion_statement
|
||||||
: K_assert expression report_statement
|
: K_assert expression report_statement
|
||||||
{ ReportStmt*report = dynamic_cast<ReportStmt*>($3);
|
{ ReportStmt*report = dynamic_cast<ReportStmt*>($3);
|
||||||
assert(report);
|
assert(report);
|
||||||
AssertStmt*tmp = new AssertStmt($2, report->message().c_str(), report->severity());
|
AssertStmt*tmp = new AssertStmt($2, report->message(), report->severity());
|
||||||
delete report;
|
delete report;
|
||||||
FILE_NAME(tmp,@2);
|
FILE_NAME(tmp,@2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
|
|
@ -752,8 +755,9 @@ composite_type_definition
|
||||||
|
|
||||||
/* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */
|
/* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */
|
||||||
| K_array '(' index_subtype_definition_list ')' K_of subtype_indication
|
| K_array '(' index_subtype_definition_list ')' K_of subtype_indication
|
||||||
{ std::list<prange_t*> r;
|
{ std::list<ExpRange*> r;
|
||||||
r.push_back(new prange_t(NULL, NULL, true)); // NULL boundaries indicate unbounded array type
|
// NULL boundaries indicate unbounded array type
|
||||||
|
r.push_back(new ExpRange(NULL, NULL, ExpRange::DOWNTO));
|
||||||
VTypeArray*tmp = new VTypeArray($6, &r);
|
VTypeArray*tmp = new VTypeArray($6, &r);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
@ -983,8 +987,10 @@ design_units
|
||||||
| design_unit
|
| design_unit
|
||||||
;
|
;
|
||||||
|
|
||||||
/* Indicate the direction as a flag, with "downto" being TRUE. */
|
direction
|
||||||
direction : K_to { $$ = false; } | K_downto { $$ = true; } ;
|
: K_to { $$ = ExpRange::TO; }
|
||||||
|
| K_downto { $$ = ExpRange::DOWNTO; }
|
||||||
|
;
|
||||||
|
|
||||||
element_association
|
element_association
|
||||||
: choices ARROW expression
|
: choices ARROW expression
|
||||||
|
|
@ -1258,8 +1264,8 @@ file_declaration
|
||||||
|
|
||||||
// add file_open() call in 'initial' block
|
// add file_open() call in 'initial' block
|
||||||
params.push_back(new ExpName(*cur));
|
params.push_back(new ExpName(*cur));
|
||||||
params.push_back($5->filename());
|
params.push_back($5->filename()->clone());
|
||||||
params.push_back($5->kind());
|
params.push_back($5->kind()->clone());
|
||||||
ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), ¶ms);
|
ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), ¶ms);
|
||||||
active_scope->add_initializer(fopen_call);
|
active_scope->add_initializer(fopen_call);
|
||||||
|
|
||||||
|
|
@ -1268,6 +1274,8 @@ file_declaration
|
||||||
params.push_back(new ExpName(*cur));
|
params.push_back(new ExpName(*cur));
|
||||||
ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms);
|
ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms);
|
||||||
active_scope->add_finalizer(fclose_call);
|
active_scope->add_finalizer(fclose_call);
|
||||||
|
|
||||||
|
delete $5;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1498,7 +1506,7 @@ index_constraint
|
||||||
| '(' error ')'
|
| '(' error ')'
|
||||||
{ errormsg(@2, "Errors in the index constraint.\n");
|
{ errormsg(@2, "Errors in the index constraint.\n");
|
||||||
yyerrok;
|
yyerrok;
|
||||||
$$ = new list<prange_t*>;
|
$$ = new list<ExpRange*>;
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
@ -1679,14 +1687,14 @@ name /* IEEE 1076-2008 P8.1 */
|
||||||
function calls. The only way we can tell the difference is from
|
function calls. The only way we can tell the difference is from
|
||||||
left context, namely whether the name is a type name or function
|
left context, namely whether the name is a type name or function
|
||||||
name. If none of the above, treat it as a array element select. */
|
name. If none of the above, treat it as a array element select. */
|
||||||
| IDENTIFIER '(' expression_list ')'
|
| IDENTIFIER argument_list
|
||||||
{ perm_string name = lex_strings.make($1);
|
{ perm_string name = lex_strings.make($1);
|
||||||
delete[]$1;
|
delete[]$1;
|
||||||
if (active_scope->is_vector_name(name) || is_subprogram_param(name)) {
|
if (active_scope->is_vector_name(name) || is_subprogram_param(name)) {
|
||||||
ExpName*tmp = new ExpName(name, $3);
|
ExpName*tmp = new ExpName(name, $2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
} else {
|
} else {
|
||||||
ExpFunc*tmp = new ExpFunc(name, $3);
|
ExpFunc*tmp = new ExpFunc(name, $2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
FILE_NAME($$, @1);
|
FILE_NAME($$, @1);
|
||||||
|
|
@ -1876,10 +1884,18 @@ prefix /* IEEE 1076-2008 P8.1 */
|
||||||
primary
|
primary
|
||||||
: name
|
: name
|
||||||
{ $$ = $1; }
|
{ $$ = $1; }
|
||||||
| name '\'' IDENTIFIER
|
| name '\'' IDENTIFIER argument_list_opt
|
||||||
{ perm_string name = lex_strings.make($3);
|
{ ExpAttribute*tmp = NULL;
|
||||||
ExpName*base = dynamic_cast<ExpName*> ($1);
|
perm_string attr = lex_strings.make($3);
|
||||||
ExpAttribute*tmp = new ExpAttribute(base, name);
|
ExpName*base = dynamic_cast<ExpName*>($1);
|
||||||
|
const VType*type = parse_type_by_name(base->peek_name());
|
||||||
|
|
||||||
|
if(type) {
|
||||||
|
tmp = new ExpTypeAttribute(type, attr, $4);
|
||||||
|
} else {
|
||||||
|
tmp = new ExpObjAttribute(base, attr, $4);
|
||||||
|
}
|
||||||
|
|
||||||
FILE_NAME(tmp, @3);
|
FILE_NAME(tmp, @3);
|
||||||
delete[]$3;
|
delete[]$3;
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
|
|
@ -1980,11 +1996,11 @@ procedure_call
|
||||||
delete[] $1;
|
delete[] $1;
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| IDENTIFIER '(' expression_list ')' ';'
|
| IDENTIFIER argument_list ';'
|
||||||
{
|
{
|
||||||
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $3);
|
ProcedureCall* tmp = new ProcedureCall(lex_strings.make($1), $2);
|
||||||
delete[] $1;
|
delete[] $1;
|
||||||
delete $3; // parameters are copied in this variant
|
delete $2; // parameters are copied in this variant
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| IDENTIFIER '(' error ')' ';'
|
| IDENTIFIER '(' error ')' ';'
|
||||||
|
|
@ -2096,18 +2112,15 @@ process_sensitivity_list
|
||||||
|
|
||||||
range
|
range
|
||||||
: simple_expression direction simple_expression
|
: simple_expression direction simple_expression
|
||||||
{ prange_t* tmp = new prange_t($1, $3, $2);
|
{ ExpRange* tmp = new ExpRange($1, $3, $2);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| name '\'' K_range
|
| name '\'' K_range
|
||||||
{
|
{
|
||||||
prange_t*tmp = NULL;
|
ExpRange*tmp = NULL;
|
||||||
ExpName*name = NULL;
|
ExpName*name = NULL;
|
||||||
if((name = dynamic_cast<ExpName*>($1))) {
|
if((name = dynamic_cast<ExpName*>($1))) {
|
||||||
ExpAttribute*left = new ExpAttribute(name, left_attr);
|
tmp = new ExpRange(name, false);
|
||||||
ExpAttribute*right = new ExpAttribute(name, right_attr);
|
|
||||||
tmp = new prange_t(left, right, true);
|
|
||||||
tmp->set_auto_dir();
|
|
||||||
} else {
|
} else {
|
||||||
errormsg(@1, "'range attribute can be used with named expressions only");
|
errormsg(@1, "'range attribute can be used with named expressions only");
|
||||||
}
|
}
|
||||||
|
|
@ -2115,13 +2128,10 @@ range
|
||||||
}
|
}
|
||||||
| name '\'' K_reverse_range
|
| name '\'' K_reverse_range
|
||||||
{
|
{
|
||||||
prange_t*tmp = NULL;
|
ExpRange*tmp = NULL;
|
||||||
ExpName*name = NULL;
|
ExpName*name = NULL;
|
||||||
if((name = dynamic_cast<ExpName*>($1))) {
|
if((name = dynamic_cast<ExpName*>($1))) {
|
||||||
ExpAttribute*left = new ExpAttribute(name, left_attr);
|
tmp = new ExpRange(name, true);
|
||||||
ExpAttribute*right = new ExpAttribute(name, right_attr);
|
|
||||||
tmp = new prange_t(left, right, false);
|
|
||||||
tmp->set_auto_dir();
|
|
||||||
} else {
|
} else {
|
||||||
errormsg(@1, "'reverse_range attribute can be used with named expressions only");
|
errormsg(@1, "'reverse_range attribute can be used with named expressions only");
|
||||||
}
|
}
|
||||||
|
|
@ -2131,12 +2141,12 @@ range
|
||||||
|
|
||||||
range_list
|
range_list
|
||||||
: range
|
: range
|
||||||
{ list<prange_t*>*tmp = new list<prange_t*>;
|
{ list<ExpRange*>*tmp = new list<ExpRange*>;
|
||||||
tmp->push_back($1);
|
tmp->push_back($1);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
| range_list ',' range
|
| range_list ',' range
|
||||||
{ list<prange_t*>*tmp = $1;
|
{ list<ExpRange*>*tmp = $1;
|
||||||
tmp->push_back($3);
|
tmp->push_back($3);
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
@ -2185,10 +2195,9 @@ relation
|
||||||
;
|
;
|
||||||
|
|
||||||
report_statement
|
report_statement
|
||||||
: K_report STRING_LITERAL severity_opt ';'
|
: K_report expression severity_opt ';'
|
||||||
{ ReportStmt*tmp = new ReportStmt($2, $3);
|
{ ReportStmt*tmp = new ReportStmt($2, $3);
|
||||||
FILE_NAME(tmp,@2);
|
FILE_NAME(tmp,@2);
|
||||||
delete[]$2;
|
|
||||||
$$ = tmp;
|
$$ = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -113,14 +113,14 @@ static const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_n
|
||||||
}
|
}
|
||||||
|
|
||||||
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
|
const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
|
||||||
ScopeBase*scope, list<prange_t*>*ranges)
|
ScopeBase*scope, list<ExpRange*>*ranges)
|
||||||
{
|
{
|
||||||
if (ranges->size() == 1) {
|
if (ranges->size() == 1) {
|
||||||
prange_t*tmpr = ranges->front();
|
ExpRange*tmpr = ranges->front();
|
||||||
Expression*lef = tmpr->expr_left();
|
Expression*lef = tmpr->left();
|
||||||
Expression*rig = tmpr->expr_right();
|
Expression*rig = tmpr->right();
|
||||||
return calculate_subtype_array(loc, base_name, scope,
|
return calculate_subtype_array(loc, base_name, scope,
|
||||||
lef, tmpr->is_downto(), rig);
|
lef, tmpr->direction(), rig);
|
||||||
}
|
}
|
||||||
|
|
||||||
sorrymsg(loc, "Don't know how to handle multiple ranges here.\n");
|
sorrymsg(loc, "Don't know how to handle multiple ranges here.\n");
|
||||||
|
|
@ -130,7 +130,7 @@ const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
|
||||||
const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
||||||
ScopeBase*scope,
|
ScopeBase*scope,
|
||||||
Expression*range_left,
|
Expression*range_left,
|
||||||
bool downto,
|
int direction,
|
||||||
Expression*range_right)
|
Expression*range_right)
|
||||||
{
|
{
|
||||||
const VType*base_type = parse_type_by_name(lex_strings.make(base_name));
|
const VType*base_type = parse_type_by_name(lex_strings.make(base_name));
|
||||||
|
|
@ -148,7 +148,7 @@ const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
||||||
if(range_left->evaluate(scope, left_val) && range_right->evaluate(scope, right_val)) {
|
if(range_left->evaluate(scope, left_val) && range_right->evaluate(scope, right_val)) {
|
||||||
subtype = new VTypeRangeConst(base_type, left_val, right_val);
|
subtype = new VTypeRangeConst(base_type, left_val, right_val);
|
||||||
} else {
|
} else {
|
||||||
subtype = new VTypeRangeExpr(base_type, range_left, range_right, downto);
|
subtype = new VTypeRangeExpr(base_type, range_left, range_right, direction);
|
||||||
}
|
}
|
||||||
|
|
||||||
return subtype;
|
return subtype;
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ class ActiveScope;
|
||||||
class Architecture;
|
class Architecture;
|
||||||
class Expression;
|
class Expression;
|
||||||
class Package;
|
class Package;
|
||||||
class prange_t;
|
class ExpRange;
|
||||||
class ScopeBase;
|
class ScopeBase;
|
||||||
class VType;
|
class VType;
|
||||||
|
|
||||||
|
|
@ -35,11 +35,11 @@ extern void bind_architecture_to_entity(const char*ename, Architecture*arch);
|
||||||
|
|
||||||
extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
|
extern const VType* calculate_subtype_array(const YYLTYPE&loc, const char*base_name,
|
||||||
ScopeBase*scope,
|
ScopeBase*scope,
|
||||||
std::list<prange_t*>*ranges);
|
std::list<ExpRange*>*ranges);
|
||||||
extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
||||||
ScopeBase*scope,
|
ScopeBase*scope,
|
||||||
Expression*range_left,
|
Expression*range_left,
|
||||||
bool downto,
|
int direction,
|
||||||
Expression*range_right);
|
Expression*range_right);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,8 @@
|
||||||
class named_expr_t {
|
class named_expr_t {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
named_expr_t (perm_string n, Expression*e) : name_(n), expr_(e) { }
|
named_expr_t(perm_string n, Expression*e) : name_(n), expr_(e) { }
|
||||||
|
~named_expr_t() { delete expr_; }
|
||||||
|
|
||||||
perm_string name() const { return name_; }
|
perm_string name() const { return name_; }
|
||||||
Expression* expr() const { return expr_; }
|
Expression* expr() const { return expr_; }
|
||||||
|
|
@ -68,35 +69,6 @@ class instant_list_t {
|
||||||
std::list<perm_string>* labels_;
|
std::list<perm_string>* labels_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class prange_t {
|
|
||||||
public:
|
|
||||||
prange_t(Expression* left, Expression* right, bool dir)
|
|
||||||
: left_(left), right_(right), direction_(dir), auto_dir_(false) {}
|
|
||||||
prange_t(const prange_t&other) :
|
|
||||||
left_(other.left_->clone()), right_(other.right_->clone()),
|
|
||||||
direction_(other.direction_), auto_dir_(other.auto_dir_) {}
|
|
||||||
~prange_t() { delete left_; delete right_; }
|
|
||||||
void dump(ostream&out, int indent) const;
|
|
||||||
|
|
||||||
inline Expression*msb() { return direction_? left_ : right_; }
|
|
||||||
inline Expression*lsb() { return direction_? right_: left_; }
|
|
||||||
|
|
||||||
inline bool is_downto() const { return direction_; }
|
|
||||||
inline void set_auto_dir(bool enabled = true) { auto_dir_ = enabled; };
|
|
||||||
inline bool is_auto_dir() const { return auto_dir_; }
|
|
||||||
|
|
||||||
inline Expression*expr_left() { return left_; }
|
|
||||||
inline Expression*expr_right() { return right_; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
Expression *left_, *right_;
|
|
||||||
bool direction_;
|
|
||||||
bool auto_dir_;
|
|
||||||
|
|
||||||
private: //not implemented
|
|
||||||
prange_t operator=(const prange_t&);
|
|
||||||
};
|
|
||||||
|
|
||||||
struct adding_term {
|
struct adding_term {
|
||||||
ExpArithmetic::fun_t op;
|
ExpArithmetic::fun_t op;
|
||||||
Expression*term;
|
Expression*term;
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,7 @@ void ScopeBase::cleanup()
|
||||||
* objects from the other scopes untouched.
|
* objects from the other scopes untouched.
|
||||||
*/
|
*/
|
||||||
delete_all(new_signals_);
|
delete_all(new_signals_);
|
||||||
|
delete_all(new_variables_);
|
||||||
delete_all(new_components_);
|
delete_all(new_components_);
|
||||||
delete_all(cur_types_);
|
delete_all(cur_types_);
|
||||||
delete_all(cur_constants_);
|
delete_all(cur_constants_);
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,8 @@ class ScopeBase {
|
||||||
finalizers_.push_back(s);
|
finalizers_.push_back(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dump_scope(ostream&out) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void cleanup();
|
void cleanup();
|
||||||
|
|
||||||
|
|
@ -154,9 +156,6 @@ class Scope : public ScopeBase {
|
||||||
|
|
||||||
ComponentBase* find_component(perm_string by_name);
|
ComponentBase* find_component(perm_string by_name);
|
||||||
|
|
||||||
public:
|
|
||||||
void dump_scope(ostream&out) const;
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Helper method for emitting signals in the scope.
|
// Helper method for emitting signals in the scope.
|
||||||
int emit_signals(ostream&out, Entity*ent, Architecture*arc);
|
int emit_signals(ostream&out, Entity*ent, Architecture*arc);
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ ProcedureCall::ProcedureCall(perm_string name, std::list<Expression*>* param_lis
|
||||||
for(std::list<Expression*>::const_iterator it = param_list->begin();
|
for(std::list<Expression*>::const_iterator it = param_list->begin();
|
||||||
it != param_list->end(); ++it)
|
it != param_list->end(); ++it)
|
||||||
{
|
{
|
||||||
param_list_->push_back(new named_expr_t(empty_perm_string, (*it)->clone()));
|
param_list_->push_back(new named_expr_t(empty_perm_string, *it));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -199,6 +199,8 @@ ProcedureCall::~ProcedureCall()
|
||||||
param_list_->pop_front();
|
param_list_->pop_front();
|
||||||
delete cur;
|
delete cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
delete param_list_;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnStmt::ReturnStmt(Expression*val)
|
ReturnStmt::ReturnStmt(Expression*val)
|
||||||
|
|
@ -238,7 +240,7 @@ void LoopStatement::visit(SeqStmtVisitor& func)
|
||||||
func(this);
|
func(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
ForLoopStatement::ForLoopStatement(perm_string scope_name, perm_string it, prange_t* range, list<SequentialStmt*>* stmts)
|
ForLoopStatement::ForLoopStatement(perm_string scope_name, perm_string it, ExpRange* range, list<SequentialStmt*>* stmts)
|
||||||
: LoopStatement(scope_name, stmts), it_(it), range_(range)
|
: LoopStatement(scope_name, stmts), it_(it), range_(range)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
@ -278,26 +280,24 @@ BasicLoopStatement::~BasicLoopStatement()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
ReportStmt::ReportStmt(const char*msg, severity_t sev)
|
ReportStmt::ReportStmt(Expression*msg, severity_t sev)
|
||||||
: msg_(msg), severity_(sev)
|
: msg_(msg), severity_(sev)
|
||||||
{
|
{
|
||||||
if(sev == ReportStmt::UNSPECIFIED)
|
if(sev == ReportStmt::UNSPECIFIED)
|
||||||
severity_ = ReportStmt::NOTE;
|
severity_ = ReportStmt::NOTE;
|
||||||
}
|
}
|
||||||
|
|
||||||
AssertStmt::AssertStmt(Expression*condition, const char*msg, ReportStmt::severity_t sev)
|
AssertStmt::AssertStmt(Expression*condition, Expression*msg, ReportStmt::severity_t sev)
|
||||||
: ReportStmt("", sev), cond_(condition)
|
: ReportStmt(msg, sev), cond_(condition)
|
||||||
{
|
{
|
||||||
if(msg == NULL)
|
if(msg == NULL)
|
||||||
msg_ = default_msg_;
|
msg_ = new ExpString(default_msg_);
|
||||||
else
|
|
||||||
msg_ = std::string(msg);
|
|
||||||
|
|
||||||
if(sev == ReportStmt::UNSPECIFIED)
|
if(sev == ReportStmt::UNSPECIFIED)
|
||||||
severity_ = ReportStmt::ERROR;
|
severity_ = ReportStmt::ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string AssertStmt::default_msg_ = std::string("Assertion violation.");
|
const char*AssertStmt::default_msg_ = "Assertion violation.";
|
||||||
|
|
||||||
WaitForStmt::WaitForStmt(Expression*delay)
|
WaitForStmt::WaitForStmt(Expression*delay)
|
||||||
: delay_(delay)
|
: delay_(delay)
|
||||||
|
|
|
||||||
|
|
@ -250,7 +250,7 @@ class WhileLoopStatement : public LoopStatement {
|
||||||
class ForLoopStatement : public LoopStatement {
|
class ForLoopStatement : public LoopStatement {
|
||||||
public:
|
public:
|
||||||
ForLoopStatement(perm_string loop_name,
|
ForLoopStatement(perm_string loop_name,
|
||||||
perm_string index, prange_t*, list<SequentialStmt*>*);
|
perm_string index, ExpRange*, list<SequentialStmt*>*);
|
||||||
~ForLoopStatement();
|
~ForLoopStatement();
|
||||||
|
|
||||||
int elaborate(Entity*ent, ScopeBase*scope);
|
int elaborate(Entity*ent, ScopeBase*scope);
|
||||||
|
|
@ -264,7 +264,7 @@ class ForLoopStatement : public LoopStatement {
|
||||||
int emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
|
||||||
perm_string it_;
|
perm_string it_;
|
||||||
prange_t* range_;
|
ExpRange* range_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class BasicLoopStatement : public LoopStatement {
|
class BasicLoopStatement : public LoopStatement {
|
||||||
|
|
@ -280,24 +280,27 @@ class ReportStmt : public SequentialStmt {
|
||||||
public:
|
public:
|
||||||
typedef enum { UNSPECIFIED, NOTE, WARNING, ERROR, FAILURE } severity_t;
|
typedef enum { UNSPECIFIED, NOTE, WARNING, ERROR, FAILURE } severity_t;
|
||||||
|
|
||||||
ReportStmt(const char*message, severity_t severity = NOTE);
|
ReportStmt(Expression*message, severity_t severity);
|
||||||
virtual ~ReportStmt() {}
|
virtual ~ReportStmt() {}
|
||||||
|
|
||||||
void dump(ostream&out, int indent) const;
|
void dump(ostream&out, int indent) const;
|
||||||
|
int elaborate(Entity*ent, ScopeBase*scope);
|
||||||
int emit(ostream&out, Entity*entity, ScopeBase*scope);
|
int emit(ostream&out, Entity*entity, ScopeBase*scope);
|
||||||
void write_to_stream(std::ostream&fd);
|
void write_to_stream(std::ostream&fd);
|
||||||
|
|
||||||
inline const std::string& message() const { return msg_; }
|
inline Expression*message() const { return msg_; }
|
||||||
inline severity_t severity() const { return severity_; }
|
inline severity_t severity() const { return severity_; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::string msg_;
|
void dump_sev_msg(ostream&out, int indent) const;
|
||||||
|
|
||||||
|
Expression*msg_;
|
||||||
severity_t severity_;
|
severity_t severity_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class AssertStmt : public ReportStmt {
|
class AssertStmt : public ReportStmt {
|
||||||
public:
|
public:
|
||||||
AssertStmt(Expression*condition, const char*message,
|
AssertStmt(Expression*condition, Expression*message,
|
||||||
ReportStmt::severity_t severity = ReportStmt::ERROR);
|
ReportStmt::severity_t severity = ReportStmt::ERROR);
|
||||||
|
|
||||||
void dump(ostream&out, int indent) const;
|
void dump(ostream&out, int indent) const;
|
||||||
|
|
@ -309,7 +312,7 @@ class AssertStmt : public ReportStmt {
|
||||||
Expression*cond_;
|
Expression*cond_;
|
||||||
|
|
||||||
// Message displayed when there is no report assigned.
|
// Message displayed when there is no report assigned.
|
||||||
static const std::string default_msg_;
|
static const char*default_msg_;
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitForStmt : public SequentialStmt {
|
class WaitForStmt : public SequentialStmt {
|
||||||
|
|
|
||||||
|
|
@ -169,16 +169,24 @@ void BasicLoopStatement::dump(ostream&out, int indent) const
|
||||||
void ReportStmt::dump(ostream&out, int indent) const
|
void ReportStmt::dump(ostream&out, int indent) const
|
||||||
{
|
{
|
||||||
out << setw(indent) << "" << "ReportStmt at file=" << get_fileline() << endl;
|
out << setw(indent) << "" << "ReportStmt at file=" << get_fileline() << endl;
|
||||||
out << setw(indent+3) << "" << "severity: " << severity_ << endl;
|
dump_sev_msg(out, indent+3);
|
||||||
out << setw(indent+3) << "" << "message: " << msg_ << endl;
|
}
|
||||||
|
|
||||||
|
void ReportStmt::dump_sev_msg(ostream&out, int indent) const
|
||||||
|
{
|
||||||
|
out << setw(indent) << "" << "severity: " << severity_ << endl;
|
||||||
|
|
||||||
|
if(msg_) {
|
||||||
|
out << setw(indent) << "" << "message: ";
|
||||||
|
msg_->dump(out, indent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AssertStmt::dump(ostream&out, int indent) const
|
void AssertStmt::dump(ostream&out, int indent) const
|
||||||
{
|
{
|
||||||
out << setw(indent) << "" << "AssertStmt at file=" << get_fileline() << endl;
|
out << setw(indent) << "" << "AssertStmt at file=" << get_fileline() << endl;
|
||||||
out << setw(indent+3) << "" << "condition: ";
|
out << setw(indent+3) << "" << "condition: ";
|
||||||
cond_->dump(out, indent+3);
|
dump_sev_msg(out, indent+3);
|
||||||
ReportStmt::dump(out, indent+3);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void WaitForStmt::dump(ostream&out, int indent) const
|
void WaitForStmt::dump(ostream&out, int indent) const
|
||||||
|
|
|
||||||
|
|
@ -217,9 +217,17 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int ReportStmt::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
|
{
|
||||||
|
return msg_->elaborate_expr(ent, scope, &primitive_STRING);
|
||||||
|
}
|
||||||
|
|
||||||
int AssertStmt::elaborate(Entity*ent, ScopeBase*scope)
|
int AssertStmt::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
return cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope));
|
int errors = 0;
|
||||||
|
errors += ReportStmt::elaborate(ent, scope);
|
||||||
|
errors += cond_->elaborate_expr(ent, scope, cond_->probe_type(ent, scope));
|
||||||
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope)
|
int WaitForStmt::elaborate(Entity*ent, ScopeBase*scope)
|
||||||
|
|
|
||||||
|
|
@ -383,10 +383,10 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
ivl_assert(*this, range_);
|
ivl_assert(*this, range_);
|
||||||
|
|
||||||
int64_t start_val;
|
int64_t start_val;
|
||||||
bool start_rc = range_->msb()->evaluate(ent, scope, start_val);
|
bool start_rc = range_->left()->evaluate(ent, scope, start_val);
|
||||||
|
|
||||||
int64_t finish_val;
|
int64_t finish_val;
|
||||||
bool finish_rc = range_->lsb()->evaluate(ent, scope, finish_val);
|
bool finish_rc = range_->right()->evaluate(ent, scope, finish_val);
|
||||||
|
|
||||||
perm_string scope_name = loop_name();
|
perm_string scope_name = loop_name();
|
||||||
if (scope_name.nil()) {
|
if (scope_name.nil()) {
|
||||||
|
|
@ -403,48 +403,31 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
// determined during the run-time
|
// determined during the run-time
|
||||||
errors += emit_runtime_(out, ent, scope);
|
errors += emit_runtime_(out, ent, scope);
|
||||||
} else {
|
} else {
|
||||||
bool dir = range_->is_downto();
|
ExpRange::range_dir_t dir = range_->direction();
|
||||||
|
|
||||||
if (!dir) {
|
if(dir == ExpRange::AUTO)
|
||||||
int64_t tmp = start_val;
|
dir = start_val < finish_val ? ExpRange::TO : ExpRange::DOWNTO;
|
||||||
start_val = finish_val;
|
|
||||||
finish_val = tmp;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dir && (start_val < finish_val)) {
|
if ((dir == ExpRange::DOWNTO && start_val < finish_val) ||
|
||||||
if(range_->is_auto_dir()) {
|
(dir == ExpRange::TO && start_val > finish_val)) {
|
||||||
dir = false;
|
out << "begin /* Degenerate loop at " << get_fileline()
|
||||||
} else {
|
<< ": " << start_val;
|
||||||
out << "begin /* Degenerate loop at " << get_fileline()
|
out << (dir == ExpRange::DOWNTO ? " downto " : " to ");
|
||||||
<< ": " << start_val
|
out << finish_val << " */ end" << endl
|
||||||
<< " downto " << finish_val << " */ end" << endl
|
<< "end" << endl;
|
||||||
<< "end" << endl;
|
return errors;
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (!dir && start_val > finish_val) {
|
|
||||||
if(range_->is_auto_dir()) {
|
|
||||||
dir = true;
|
|
||||||
} else {
|
|
||||||
out << "begin /* Degenerate loop at " << get_fileline()
|
|
||||||
<< ": " << start_val
|
|
||||||
<< " to " << finish_val << " */ end" << endl
|
|
||||||
<< "end" << endl;
|
|
||||||
return errors;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "for (\\" << it_ << " = " << start_val << " ; ";
|
out << "for (\\" << it_ << " = " << start_val << " ; ";
|
||||||
|
|
||||||
if (dir)
|
if (dir == ExpRange::DOWNTO)
|
||||||
out << "\\" << it_ << " >= " << finish_val;
|
out << "\\" << it_ << " >= " << finish_val;
|
||||||
else
|
else
|
||||||
out << "\\" << it_ << " <= " << finish_val;
|
out << "\\" << it_ << " <= " << finish_val;
|
||||||
|
|
||||||
out << "; \\" << it_ << " = \\" << it_;
|
out << "; \\" << it_ << " = \\" << it_;
|
||||||
|
|
||||||
if (dir)
|
if (dir == ExpRange::DOWNTO)
|
||||||
out << " - 1)";
|
out << " - 1)";
|
||||||
else
|
else
|
||||||
out << " + 1)";
|
out << " + 1)";
|
||||||
|
|
@ -463,9 +446,7 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
void ForLoopStatement::write_to_stream(ostream&fd)
|
void ForLoopStatement::write_to_stream(ostream&fd)
|
||||||
{
|
{
|
||||||
fd << "for " << it_ << " in ";
|
fd << "for " << it_ << " in ";
|
||||||
range_->expr_left()->write_to_stream(fd);
|
range_->write_to_stream(fd);
|
||||||
fd << " to ";
|
|
||||||
range_->expr_right()->write_to_stream(fd);
|
|
||||||
fd << " loop" << endl;
|
fd << " loop" << endl;
|
||||||
write_to_stream_substatements(fd);
|
write_to_stream_substatements(fd);
|
||||||
fd << "end loop;" << endl;
|
fd << "end loop;" << endl;
|
||||||
|
|
@ -476,41 +457,43 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
int errors = 0;
|
int errors = 0;
|
||||||
|
|
||||||
out << "for (\\" << it_ << " = ";
|
out << "for (\\" << it_ << " = ";
|
||||||
errors += range_->expr_left()->emit(out, ent, scope);
|
errors += range_->left()->emit(out, ent, scope);
|
||||||
|
|
||||||
// Twisted way of determining the loop direction at runtime
|
// Twisted way of determining the loop direction at runtime
|
||||||
out << " ;\n(";
|
out << " ;\n(";
|
||||||
errors += range_->expr_left()->emit(out, ent, scope);
|
errors += range_->left()->emit(out, ent, scope);
|
||||||
out << " < ";
|
out << " < ";
|
||||||
errors += range_->expr_right()->emit(out, ent, scope);
|
errors += range_->right()->emit(out, ent, scope);
|
||||||
out << " ? \\" << it_ << " <= ";
|
out << " ? \\" << it_ << " <= ";
|
||||||
errors += range_->expr_right()->emit(out, ent, scope);
|
errors += range_->right()->emit(out, ent, scope);
|
||||||
out << " : \\" << it_ << " >= ";
|
out << " : \\" << it_ << " >= ";
|
||||||
errors += range_->expr_right()->emit(out, ent, scope);
|
errors += range_->right()->emit(out, ent, scope);
|
||||||
out << ");\n\\" << it_ << " = \\" << it_ << " + (";
|
out << ");\n\\" << it_ << " = \\" << it_ << " + (";
|
||||||
errors += range_->expr_left()->emit(out, ent, scope);
|
errors += range_->left()->emit(out, ent, scope);
|
||||||
out << " < ";
|
out << " < ";
|
||||||
errors += range_->expr_right()->emit(out, ent, scope);
|
errors += range_->right()->emit(out, ent, scope);
|
||||||
out << " ? 1 : -1))";
|
out << " ? 1 : -1))";
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ReportStmt::emit(ostream&out, Entity*, ScopeBase*)
|
int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
{
|
{
|
||||||
out << "$display(\"";
|
out << "$display(\"** ";
|
||||||
|
|
||||||
switch(severity_)
|
switch(severity_)
|
||||||
{
|
{
|
||||||
case NOTE: out << "** Note: "; break;
|
case NOTE: out << "Note"; break;
|
||||||
case WARNING: out << "** Warning: "; break;
|
case WARNING: out << "Warning"; break;
|
||||||
case ERROR: out << "** Error: "; break;
|
case ERROR: out << "Error"; break;
|
||||||
case FAILURE: out << "** Failure: "; break;
|
case FAILURE: out << "Failure"; break;
|
||||||
case UNSPECIFIED: ivl_assert(*this, false); break;
|
case UNSPECIFIED: ivl_assert(*this, false); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
out << ExpString::escape_quot(msg_);
|
out << ": \",";
|
||||||
out << " (" << get_fileline() << ")\");";
|
|
||||||
|
msg_->emit(out, ent, scope);
|
||||||
|
out << ",\" (" << get_fileline() << ")\");";
|
||||||
|
|
||||||
if(severity_ == FAILURE)
|
if(severity_ == FAILURE)
|
||||||
out << "$finish();";
|
out << "$finish();";
|
||||||
|
|
@ -522,7 +505,8 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*)
|
||||||
|
|
||||||
void ReportStmt::write_to_stream(std::ostream&fd)
|
void ReportStmt::write_to_stream(std::ostream&fd)
|
||||||
{
|
{
|
||||||
fd << "report \"" << ExpString::escape_quot(msg_) << "\"" << std::endl;
|
fd << "report ";
|
||||||
|
msg_->write_to_stream(fd);
|
||||||
|
|
||||||
fd << "severity ";
|
fd << "severity ";
|
||||||
switch(severity_)
|
switch(severity_)
|
||||||
|
|
@ -563,7 +547,7 @@ int WaitForStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
|
|
||||||
out << "#(";
|
out << "#(";
|
||||||
errors += delay_->emit(out, ent, scope);
|
errors += delay_->emit(out, ent, scope);
|
||||||
out << ")";
|
out << ");" << std::endl;
|
||||||
|
|
||||||
return errors;
|
return errors;
|
||||||
}
|
}
|
||||||
|
|
@ -586,6 +570,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
case UNTIL:
|
case UNTIL:
|
||||||
if(!sens_list_.empty()) {
|
if(!sens_list_.empty()) {
|
||||||
out << "@(";
|
out << "@(";
|
||||||
|
|
||||||
for(std::set<ExpName*>::iterator it = sens_list_.begin();
|
for(std::set<ExpName*>::iterator it = sens_list_.begin();
|
||||||
it != sens_list_.end(); ++it) {
|
it != sens_list_.end(); ++it) {
|
||||||
if(it != sens_list_.begin())
|
if(it != sens_list_.begin())
|
||||||
|
|
@ -594,7 +579,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
(*it)->emit(out, ent, scope);
|
(*it)->emit(out, ent, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
out << ");";
|
out << "); ";
|
||||||
}
|
}
|
||||||
|
|
||||||
out << "wait(";
|
out << "wait(";
|
||||||
|
|
|
||||||
|
|
@ -46,20 +46,20 @@ const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector<VTypeArra
|
||||||
void generate_global_types(ActiveScope*res)
|
void generate_global_types(ActiveScope*res)
|
||||||
{
|
{
|
||||||
// boolean
|
// boolean
|
||||||
list<perm_string>*enum_BOOLEAN_vals = new list<perm_string>;
|
list<perm_string> enum_BOOLEAN_vals;
|
||||||
enum_BOOLEAN_vals->push_back(perm_string::literal("false"));
|
enum_BOOLEAN_vals.push_back(perm_string::literal("false"));
|
||||||
enum_BOOLEAN_vals->push_back(perm_string::literal("true"));
|
enum_BOOLEAN_vals.push_back(perm_string::literal("true"));
|
||||||
VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals);
|
VTypeEnum*enum_BOOLEAN = new VTypeEnum(&enum_BOOLEAN_vals);
|
||||||
type_BOOLEAN.set_definition(enum_BOOLEAN);
|
type_BOOLEAN.set_definition(enum_BOOLEAN);
|
||||||
std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN;
|
std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN;
|
||||||
std_enums.push_back(enum_BOOLEAN);
|
std_enums.push_back(enum_BOOLEAN);
|
||||||
|
|
||||||
// file_open_kind
|
// file_open_kind
|
||||||
list<perm_string>*enum_FILE_OPEN_KIND_vals = new list<perm_string>;
|
list<perm_string> enum_FILE_OPEN_KIND_vals;
|
||||||
enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("read_mode"));
|
enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("read_mode"));
|
||||||
enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("write_mode"));
|
enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("write_mode"));
|
||||||
enum_FILE_OPEN_KIND_vals->push_back(perm_string::literal("append_mode"));
|
enum_FILE_OPEN_KIND_vals.push_back(perm_string::literal("append_mode"));
|
||||||
VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(enum_FILE_OPEN_KIND_vals);
|
VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(&enum_FILE_OPEN_KIND_vals);
|
||||||
type_FILE_OPEN_KIND.set_definition(enum_FILE_OPEN_KIND);
|
type_FILE_OPEN_KIND.set_definition(enum_FILE_OPEN_KIND);
|
||||||
std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND;
|
std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND;
|
||||||
std_enums.push_back(enum_FILE_OPEN_KIND);
|
std_enums.push_back(enum_FILE_OPEN_KIND);
|
||||||
|
|
@ -80,10 +80,12 @@ void delete_global_types()
|
||||||
{
|
{
|
||||||
typedef_context_t typedef_ctx;
|
typedef_context_t typedef_ctx;
|
||||||
for(map<perm_string, VTypeDef*>::iterator cur = std_types.begin();
|
for(map<perm_string, VTypeDef*>::iterator cur = std_types.begin();
|
||||||
cur != std_types.end() ; ++ cur) {
|
cur != std_types.end(); ++cur) {
|
||||||
delete cur->second->peek_definition();
|
delete cur->second->peek_definition();
|
||||||
delete cur->second;
|
delete cur->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// std_enums are destroyed above
|
||||||
}
|
}
|
||||||
|
|
||||||
const VTypeEnum*find_std_enum_name(perm_string name)
|
const VTypeEnum*find_std_enum_name(perm_string name)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@
|
||||||
class ActiveScope;
|
class ActiveScope;
|
||||||
|
|
||||||
void emit_std_types(ostream&out);
|
void emit_std_types(ostream&out);
|
||||||
int emit_packages(void);
|
|
||||||
void generate_global_types(ActiveScope*res);
|
void generate_global_types(ActiveScope*res);
|
||||||
bool is_global_type(perm_string type_name);
|
bool is_global_type(perm_string type_name);
|
||||||
void delete_global_types();
|
void delete_global_types();
|
||||||
|
|
|
||||||
|
|
@ -53,6 +53,18 @@ void SubprogramBody::set_statements(list<SequentialStmt*>*stmt)
|
||||||
statements_ = stmt;
|
statements_ = stmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int SubprogramBody::elaborate()
|
||||||
|
{
|
||||||
|
int errors = 0;
|
||||||
|
|
||||||
|
for (list<SequentialStmt*>::const_iterator cur = statements_->begin()
|
||||||
|
; cur != statements_->end() ; ++cur) {
|
||||||
|
errors += (*cur)->elaborate(0, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
return errors;
|
||||||
|
}
|
||||||
|
|
||||||
void SubprogramBody::write_to_stream(ostream&fd) const
|
void SubprogramBody::write_to_stream(ostream&fd) const
|
||||||
{
|
{
|
||||||
for (map<perm_string,Variable*>::const_iterator cur = new_variables_.begin()
|
for (map<perm_string,Variable*>::const_iterator cur = new_variables_.begin()
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ class SubprogramBody : public LineInfo, public ScopeBase {
|
||||||
void set_statements(std::list<SequentialStmt*>*statements);
|
void set_statements(std::list<SequentialStmt*>*statements);
|
||||||
inline bool empty_statements() const { return !statements_ || statements_->empty(); }
|
inline bool empty_statements() const { return !statements_ || statements_->empty(); }
|
||||||
|
|
||||||
|
int elaborate();
|
||||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||||
|
|
||||||
// Emit body as it would show up in a package.
|
// Emit body as it would show up in a package.
|
||||||
|
|
@ -89,6 +90,8 @@ class SubprogramHeader : public LineInfo {
|
||||||
|
|
||||||
inline perm_string name() const { return name_; }
|
inline perm_string name() const { return name_; }
|
||||||
|
|
||||||
|
int elaborate() { return (body_ ? body_->elaborate() : 0); }
|
||||||
|
|
||||||
// Function name used in the emission step. The main purpose of this
|
// Function name used in the emission step. The main purpose of this
|
||||||
// method is to handle functions offered by standard VHDL libraries.
|
// method is to handle functions offered by standard VHDL libraries.
|
||||||
// Allows to return different function names depending on the arguments
|
// Allows to return different function names depending on the arguments
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,7 @@ int Variable::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||||
|
|
||||||
VType::decl_t decl;
|
VType::decl_t decl;
|
||||||
type_elaborate_(decl);
|
type_elaborate_(decl);
|
||||||
if (peek_refcnt_sequ_() > 0 || !peek_type()->can_be_packed())
|
decl.reg_flag = true;
|
||||||
decl.reg_flag = true;
|
|
||||||
errors += decl.emit(out, peek_name());
|
errors += decl.emit(out, peek_name());
|
||||||
|
|
||||||
Expression*init_expr = peek_init_expr();
|
Expression*init_expr = peek_init_expr();
|
||||||
|
|
|
||||||
|
|
@ -108,21 +108,18 @@ VTypeArray::VTypeArray(const VType*element, const vector<VTypeArray::range_t>&r,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a VTypeArray range set from a list of parsed ranges.
|
* Create a VTypeArray range set from a list of parsed ranges.
|
||||||
* FIXME: We are copying pointers from the prange_t object into the
|
* FIXME: We are copying pointers from the ExpRange object into the
|
||||||
* range_t. This means that we cannot delete the prange_t object
|
* range_t. This means that we cannot delete the ExpRange object
|
||||||
* unless we invent a way to remove the pointers from that object. So
|
* unless we invent a way to remove the pointers from that object. So
|
||||||
* this is a memory leak. Something to fix.
|
* this is a memory leak. Something to fix.
|
||||||
*/
|
*/
|
||||||
VTypeArray::VTypeArray(const VType*element, std::list<prange_t*>*r, bool sv)
|
VTypeArray::VTypeArray(const VType*element, std::list<ExpRange*>*r, bool sv)
|
||||||
: etype_(element), ranges_(r->size()), signed_flag_(sv), parent_(NULL)
|
: etype_(element), ranges_(r->size()), signed_flag_(sv), parent_(NULL)
|
||||||
{
|
{
|
||||||
for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) {
|
for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) {
|
||||||
prange_t*curp = r->front();
|
ExpRange*curp = r->front();
|
||||||
r->pop_front();
|
r->pop_front();
|
||||||
Expression*msb = curp->msb();
|
ranges_[idx] = range_t(curp->msb(), curp->lsb(), curp->direction());
|
||||||
Expression*lsb = curp->lsb();
|
|
||||||
bool dir = curp->is_downto();
|
|
||||||
ranges_[idx] = range_t(msb, lsb, dir);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ class Architecture;
|
||||||
class ScopeBase;
|
class ScopeBase;
|
||||||
class Entity;
|
class Entity;
|
||||||
class Expression;
|
class Expression;
|
||||||
class prange_t;
|
class ExpRange;
|
||||||
class VTypeDef;
|
class VTypeDef;
|
||||||
class ScopeBase;
|
class ScopeBase;
|
||||||
|
|
||||||
|
|
@ -210,7 +210,7 @@ class VTypeArray : public VType {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VTypeArray(const VType*etype, const std::vector<range_t>&r, bool signed_vector = false);
|
VTypeArray(const VType*etype, const std::vector<range_t>&r, bool signed_vector = false);
|
||||||
VTypeArray(const VType*etype, std::list<prange_t*>*r, bool signed_vector = false);
|
VTypeArray(const VType*etype, std::list<ExpRange*>*r, bool signed_vector = false);
|
||||||
VTypeArray(const VType*etype, int msb, int lsb, bool signed_vector = false);
|
VTypeArray(const VType*etype, int msb, int lsb, bool signed_vector = false);
|
||||||
~VTypeArray();
|
~VTypeArray();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -169,10 +169,11 @@ static int get_default_format(const char *name)
|
||||||
int default_format;
|
int default_format;
|
||||||
|
|
||||||
switch(name[ strlen(name)-1 ]){
|
switch(name[ strlen(name)-1 ]){
|
||||||
/* writE/strobE or monitoR or displaY/fdisplaY or sformaT */
|
/* writE/strobE or monitoR or displaY/fdisplaY or sformaT/sformatF */
|
||||||
case 'e':
|
case 'e':
|
||||||
case 'r':
|
case 'r':
|
||||||
case 't':
|
case 't':
|
||||||
|
case 'f':
|
||||||
case 'y': default_format = vpiDecStrVal; break;
|
case 'y': default_format = vpiDecStrVal; break;
|
||||||
case 'h': default_format = vpiHexStrVal; break;
|
case 'h': default_format = vpiHexStrVal; break;
|
||||||
case 'o': default_format = vpiOctStrVal; break;
|
case 'o': default_format = vpiOctStrVal; break;
|
||||||
|
|
@ -620,10 +621,6 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||||
case 't':
|
case 't':
|
||||||
case 'T':
|
case 'T':
|
||||||
*idx += 1;
|
*idx += 1;
|
||||||
if (plus != 0) {
|
|
||||||
vpi_printf("WARNING: %s:%d: invalid format %s%s.\n",
|
|
||||||
info->filename, info->lineno, info->name, fmtb);
|
|
||||||
}
|
|
||||||
if (*idx >= info->nitems) {
|
if (*idx >= info->nitems) {
|
||||||
vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n",
|
vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n",
|
||||||
info->filename, info->lineno, info->name, fmtb);
|
info->filename, info->lineno, info->name, fmtb);
|
||||||
|
|
@ -647,6 +644,29 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
||||||
} else {
|
} else {
|
||||||
char *tbuf;
|
char *tbuf;
|
||||||
PLI_INT32 time_units = vpi_get(vpiTimeUnit, info->scope);
|
PLI_INT32 time_units = vpi_get(vpiTimeUnit, info->scope);
|
||||||
|
|
||||||
|
if (plus != 0) {
|
||||||
|
/* Icarus-specific extension to print out time units.
|
||||||
|
* It is needed by vhdlpp to correctly implement time'image(). */
|
||||||
|
PLI_INT32 time_prec = vpi_get(vpiTimePrecision, info->scope);
|
||||||
|
|
||||||
|
if(time_units < -12)
|
||||||
|
timeformat_info.suff = strdup(" fs");
|
||||||
|
else if(time_units < -9)
|
||||||
|
timeformat_info.suff = strdup(" ps");
|
||||||
|
else if(time_units < -6)
|
||||||
|
timeformat_info.suff = strdup(" ns");
|
||||||
|
else if(time_units < -3)
|
||||||
|
timeformat_info.suff = strdup(" us");
|
||||||
|
else if(time_units < 0)
|
||||||
|
timeformat_info.suff = strdup(" ms");
|
||||||
|
else
|
||||||
|
timeformat_info.suff = strdup(" s");
|
||||||
|
|
||||||
|
/* Adjust shift for get_time(), so the number indeed matches the unit */
|
||||||
|
time_units += (3 + (time_units % 3)) % 3 + (time_prec - time_units);
|
||||||
|
}
|
||||||
|
|
||||||
unsigned swidth, free_flag = 0;
|
unsigned swidth, free_flag = 0;
|
||||||
unsigned suff_len = strlen(timeformat_info.suff);
|
unsigned suff_len = strlen(timeformat_info.suff);
|
||||||
char *cp;
|
char *cp;
|
||||||
|
|
@ -1238,7 +1258,8 @@ static PLI_INT32 sys_display_compiletf(ICARUS_VPI_CONST PLI_BYTE8*name)
|
||||||
return sys_common_compiletf(name, 0, 0);
|
return sys_common_compiletf(name, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This implements the $display/$fdisplay and the $write/$fwrite based tasks. */
|
/* This implements the $sformatf, $display/$fdisplay
|
||||||
|
* and the $write/$fwrite based tasks. */
|
||||||
static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
{
|
{
|
||||||
vpiHandle callh, argv, scope;
|
vpiHandle callh, argv, scope;
|
||||||
|
|
@ -1246,6 +1267,7 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
char* result;
|
char* result;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
PLI_UINT32 fd_mcd;
|
PLI_UINT32 fd_mcd;
|
||||||
|
s_vpi_value val;
|
||||||
|
|
||||||
callh = vpi_handle(vpiSysTfCall, 0);
|
callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
argv = vpi_iterate(vpiArgument, callh);
|
argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
|
@ -1254,7 +1276,6 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
if(name[1] == 'f') {
|
if(name[1] == 'f') {
|
||||||
errno = 0;
|
errno = 0;
|
||||||
vpiHandle arg = vpi_scan(argv);
|
vpiHandle arg = vpi_scan(argv);
|
||||||
s_vpi_value val;
|
|
||||||
val.format = vpiIntVal;
|
val.format = vpiIntVal;
|
||||||
vpi_get_value(arg, &val);
|
vpi_get_value(arg, &val);
|
||||||
fd_mcd = val.value.integer;
|
fd_mcd = val.value.integer;
|
||||||
|
|
@ -1275,7 +1296,11 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
vpi_free_object(argv);
|
vpi_free_object(argv);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
} else if(strncmp(name,"$sformatf",9) == 0) {
|
||||||
|
/* return as a string */
|
||||||
|
fd_mcd = 0;
|
||||||
} else {
|
} else {
|
||||||
|
/* stdout */
|
||||||
fd_mcd = 1;
|
fd_mcd = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1293,13 +1318,21 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
/* Because %u and %z may put embedded NULL characters into the
|
/* Because %u and %z may put embedded NULL characters into the
|
||||||
* returned string strlen() may not match the real size! */
|
* returned string strlen() may not match the real size! */
|
||||||
result = get_display(&size, &info);
|
result = get_display(&size, &info);
|
||||||
my_mcd_rawwrite(fd_mcd, result, size);
|
|
||||||
if ((strncmp(name,"$display",8) == 0) ||
|
|
||||||
(strncmp(name,"$fdisplay",9) == 0)) my_mcd_rawwrite(fd_mcd, "\n", 1);
|
|
||||||
|
|
||||||
|
if(fd_mcd > 0) {
|
||||||
|
my_mcd_rawwrite(fd_mcd, result, size);
|
||||||
|
if ((strncmp(name,"$display",8) == 0) ||
|
||||||
|
(strncmp(name,"$fdisplay",9) == 0)) my_mcd_rawwrite(fd_mcd, "\n", 1);
|
||||||
|
} else {
|
||||||
|
/* Return as a string ($sformatf) */
|
||||||
|
val.format = vpiStringVal;
|
||||||
|
val.value.str = result;
|
||||||
|
vpi_put_value(callh, &val, 0, vpiNoDelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(result);
|
||||||
free(info.filename);
|
free(info.filename);
|
||||||
free(info.items);
|
free(info.items);
|
||||||
free(result);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1665,7 +1698,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
if (argv == 0) {
|
if (argv == 0) {
|
||||||
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("%s requires at least two argument.\n", name);
|
vpi_printf("%s requires at least two arguments.\n", name);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1686,7 +1719,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
if (arg == 0) {
|
if (arg == 0) {
|
||||||
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh),
|
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
(int)vpi_get(vpiLineNo, callh));
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
vpi_printf("%s requires at least two argument.\n", name);
|
vpi_printf("%s requires at least two arguments.\n", name);
|
||||||
vpi_control(vpiFinish, 1);
|
vpi_control(vpiFinish, 1);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1754,6 +1787,46 @@ static PLI_INT32 sys_sformat_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PLI_INT32 sys_sformatf_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
||||||
|
{
|
||||||
|
vpiHandle callh = vpi_handle(vpiSysTfCall, 0);
|
||||||
|
vpiHandle argv = vpi_iterate(vpiArgument, callh);
|
||||||
|
vpiHandle arg;
|
||||||
|
PLI_INT32 type;
|
||||||
|
|
||||||
|
/* Check that there are arguments. */
|
||||||
|
if (argv == 0) {
|
||||||
|
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s requires at least one argument.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The first argument must be a string, a register or a SV string. */
|
||||||
|
arg = vpi_scan(argv);
|
||||||
|
if (arg == 0) {
|
||||||
|
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s requires at least one argument.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
type = vpi_get(vpiType, arg);
|
||||||
|
if (((type != vpiConstant && type != vpiParameter) ||
|
||||||
|
vpi_get(vpiConstType, arg) != vpiStringConst) &&
|
||||||
|
type != vpiReg && type != vpiStringVar) {
|
||||||
|
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, callh),
|
||||||
|
(int)vpi_get(vpiLineNo, callh));
|
||||||
|
vpi_printf("%s's first argument must be a string or a register.\n", name);
|
||||||
|
vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sys_check_args(callh, argv, name, 0, 0)) vpi_control(vpiFinish, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static PLI_INT32 sys_end_of_compile(p_cb_data cb_data)
|
static PLI_INT32 sys_end_of_compile(p_cb_data cb_data)
|
||||||
{
|
{
|
||||||
(void)cb_data; /* Parameter is not used. */
|
(void)cb_data; /* Parameter is not used. */
|
||||||
|
|
@ -2434,6 +2507,16 @@ void sys_display_register(void)
|
||||||
res = vpi_register_systf(&tf_data);
|
res = vpi_register_systf(&tf_data);
|
||||||
vpip_make_systf_system_defined(res);
|
vpip_make_systf_system_defined(res);
|
||||||
|
|
||||||
|
tf_data.type = vpiSysFunc;
|
||||||
|
tf_data.sysfunctype = vpiStringFunc;
|
||||||
|
tf_data.tfname = "$sformatf";
|
||||||
|
tf_data.calltf = sys_display_calltf;
|
||||||
|
tf_data.compiletf = sys_sformatf_compiletf;
|
||||||
|
tf_data.sizetf = 0;
|
||||||
|
tf_data.user_data = "$sformatf";
|
||||||
|
res = vpi_register_systf(&tf_data);
|
||||||
|
vpip_make_systf_system_defined(res);
|
||||||
|
|
||||||
/*============================ timeformat */
|
/*============================ timeformat */
|
||||||
tf_data.type = vpiSysTask;
|
tf_data.type = vpiSysTask;
|
||||||
tf_data.tfname = "$timeformat";
|
tf_data.tfname = "$timeformat";
|
||||||
|
|
|
||||||
|
|
@ -24,3 +24,5 @@ $table_model vpiSysFuncReal
|
||||||
|
|
||||||
$ivl_string_method$len vpiSysFuncInt
|
$ivl_string_method$len vpiSysFuncInt
|
||||||
$ivl_string_method$to_vec vpiSysFuncVoid
|
$ivl_string_method$to_vec vpiSysFuncVoid
|
||||||
|
|
||||||
|
$sformatf vpiSysFuncString
|
||||||
|
|
|
||||||
|
|
@ -840,6 +840,7 @@ instructions. The formats are:
|
||||||
%vpi_call/i <file-index> <lineno> <name>, <args>... ;
|
%vpi_call/i <file-index> <lineno> <name>, <args>... ;
|
||||||
%vpi_func <file-index> <lineno> <name>, <args>... ;
|
%vpi_func <file-index> <lineno> <name>, <args>... ;
|
||||||
%vpi_func/r <file-index> <lineno> <name>, <args>... ;
|
%vpi_func/r <file-index> <lineno> <name>, <args>... ;
|
||||||
|
%vpi_func/s <file-index> <lineno> <name>, <args>... ;
|
||||||
|
|
||||||
The <file-index> is an index into the string table. The indexed string
|
The <file-index> is an index into the string table. The indexed string
|
||||||
is the source code file name where this call appears. The <lineno> is
|
is the source code file name where this call appears. The <lineno> is
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,7 @@ static char* strdupnew(char const *str)
|
||||||
"%vpi_call/i" { return K_vpi_call_i; }
|
"%vpi_call/i" { return K_vpi_call_i; }
|
||||||
"%vpi_func" { return K_vpi_func; }
|
"%vpi_func" { return K_vpi_func; }
|
||||||
"%vpi_func/r" { return K_vpi_func_r; }
|
"%vpi_func/r" { return K_vpi_func_r; }
|
||||||
|
"%vpi_func/s" { return K_vpi_func_s; }
|
||||||
"%file_line" { return K_file_line; }
|
"%file_line" { return K_file_line; }
|
||||||
|
|
||||||
/* Handle the specialized variable access functions. */
|
/* Handle the specialized variable access functions. */
|
||||||
|
|
|
||||||
|
|
@ -1241,6 +1241,7 @@ stack when the call returns.
|
||||||
|
|
||||||
* %vpi_func <file> <line> <name> [, ...] {<vec4> <real> <str>}
|
* %vpi_func <file> <line> <name> [, ...] {<vec4> <real> <str>}
|
||||||
* %vpi_func/r <file> <line> <name> [, ...] {<vec4> <real> <str>}
|
* %vpi_func/r <file> <line> <name> [, ...] {<vec4> <real> <str>}
|
||||||
|
* %vpi_func/s <file> <line> <name> [, ...] {<vec4> <real> <str>}
|
||||||
|
|
||||||
This instruction is similar to %vpi_call, except that it is for
|
This instruction is similar to %vpi_call, except that it is for
|
||||||
calling system functions. The difference here is the return value from
|
calling system functions. The difference here is the return value from
|
||||||
|
|
|
||||||
|
|
@ -100,7 +100,7 @@ static struct __vpiModPath*modpath_dst = 0;
|
||||||
%token K_VAR_QUEUE
|
%token K_VAR_QUEUE
|
||||||
%token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
|
%token K_VAR_S K_VAR_STR K_VAR_I K_VAR_R K_VAR_2S K_VAR_2U
|
||||||
%token K_vpi_call K_vpi_call_w K_vpi_call_i
|
%token K_vpi_call K_vpi_call_w K_vpi_call_i
|
||||||
%token K_vpi_func K_vpi_func_r
|
%token K_vpi_func K_vpi_func_r K_vpi_func_s
|
||||||
%token K_ivl_version K_ivl_delay_selection
|
%token K_ivl_version K_ivl_delay_selection
|
||||||
%token K_vpi_module K_vpi_time_precision K_file_names K_file_line
|
%token K_vpi_module K_vpi_time_precision K_file_names K_file_line
|
||||||
%token K_PORT_INPUT K_PORT_OUTPUT K_PORT_INOUT K_PORT_MIXED K_PORT_NODIR
|
%token K_PORT_INPUT K_PORT_OUTPUT K_PORT_INOUT K_PORT_MIXED K_PORT_NODIR
|
||||||
|
|
@ -658,6 +658,10 @@ statement
|
||||||
{ compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4,
|
{ compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4,
|
||||||
$6.argc, $6.argv, $8, $9, $10); }
|
$6.argc, $6.argv, $8, $9, $10); }
|
||||||
|
|
||||||
|
| label_opt K_vpi_func_s T_NUMBER T_NUMBER T_STRING
|
||||||
|
argument_opt '{' T_NUMBER T_NUMBER T_NUMBER '}' ';'
|
||||||
|
{ compile_vpi_func_call($1, $5, -vpiStringVal, 0, $3, $4,
|
||||||
|
$6.argc, $6.argv, $8, $9, $10); }
|
||||||
|
|
||||||
/* Scope statements come in two forms. There are the scope
|
/* Scope statements come in two forms. There are the scope
|
||||||
declaration and the scope recall. The declarations create the
|
declaration and the scope recall. The declarations create the
|
||||||
|
|
|
||||||
193
vvp/vpi_tasks.cc
193
vvp/vpi_tasks.cc
|
|
@ -143,54 +143,25 @@ static vpiHandle systask_iter(int, vpiHandle ref)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct systask_def : public __vpiSysTaskCall {
|
struct systask_def : public __vpiSysTaskCall {
|
||||||
inline systask_def() { }
|
virtual ~systask_def() {};
|
||||||
int get_type_code(void) const { return vpiSysTaskCall; }
|
virtual int get_type_code(void) const { return vpiSysTaskCall; }
|
||||||
int vpi_get(int code) { return systask_get(code, this); }
|
virtual int vpi_get(int code) { return systask_get(code, this); }
|
||||||
char*vpi_get_str(int code) { return systask_get_str(code, this); }
|
virtual char*vpi_get_str(int code) { return systask_get_str(code, this); }
|
||||||
vpiHandle vpi_handle(int code) { return systask_handle(code, this); }
|
virtual vpiHandle vpi_handle(int code) { return systask_handle(code, this); }
|
||||||
vpiHandle vpi_iterate(int code){ return systask_iter(code, this); }
|
virtual vpiHandle vpi_iterate(int code){ return systask_iter(code, this); }
|
||||||
};
|
};
|
||||||
|
|
||||||
static vpiHandle sysfunc_put_rnet_value(vpiHandle ref, p_vpi_value vp, int)
|
struct sysfunc_def : public systask_def {
|
||||||
{
|
virtual ~sysfunc_def() {};
|
||||||
struct __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
virtual int get_type_code(void) const { return vpiSysFuncCall; }
|
||||||
|
virtual int vpi_get(int code) { return sysfunc_get(code, this); }
|
||||||
|
};
|
||||||
|
|
||||||
rfp->put_value = true;
|
struct sysfunc_real : public sysfunc_def {
|
||||||
|
|
||||||
double val;
|
|
||||||
switch (vp->format) {
|
|
||||||
|
|
||||||
case vpiRealVal:
|
|
||||||
val = vp->value.real;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
val = 0.0;
|
|
||||||
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
|
|
||||||
assert(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
rfp->fnet->send_real(val, vthread_get_wt_context());
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static vpiHandle sysfunc_put_no_value(vpiHandle, p_vpi_value, int)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct sysfunc_real : public __vpiSysTaskCall {
|
|
||||||
inline sysfunc_real() { }
|
|
||||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
|
||||||
int vpi_get(int code) { return sysfunc_get(code, this); }
|
|
||||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
||||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||||
vpiHandle vpi_handle(int code)
|
inline double return_value() const { return return_value_; }
|
||||||
{ return systask_handle(code, this); }
|
|
||||||
vpiHandle vpi_iterate(int code)
|
|
||||||
{ return systask_iter(code, this); }
|
|
||||||
|
|
||||||
|
private:
|
||||||
double return_value_;
|
double return_value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -211,18 +182,53 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
class sysfunc_vec4 : public __vpiSysTaskCall {
|
struct sysfunc_str : public sysfunc_def {
|
||||||
|
int vpi_get(int code);
|
||||||
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||||
|
inline const std::string& return_value() const { return return_value_; };
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string return_value_;
|
||||||
|
};
|
||||||
|
|
||||||
|
int sysfunc_str::vpi_get(int code)
|
||||||
|
{
|
||||||
|
switch (code) {
|
||||||
|
case vpiSize:
|
||||||
|
return return_value_.size();
|
||||||
|
|
||||||
|
case vpiLineNo:
|
||||||
|
return lineno;
|
||||||
|
|
||||||
|
case vpiUserDefn:
|
||||||
|
return defn->is_user_defn;
|
||||||
|
|
||||||
|
default:
|
||||||
|
return vpiUndefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vpiHandle sysfunc_str::vpi_put_value(p_vpi_value vp, int)
|
||||||
|
{
|
||||||
|
put_value = true;
|
||||||
|
|
||||||
|
switch (vp->format) {
|
||||||
|
case vpiStringVal:
|
||||||
|
return_value_ = std::string(vp->value.str);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
class sysfunc_vec4 : public sysfunc_def {
|
||||||
public:
|
public:
|
||||||
explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { }
|
explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { }
|
||||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
|
||||||
int vpi_get(int code);
|
int vpi_get(int code);
|
||||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
||||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||||
vpiHandle vpi_handle(int code)
|
|
||||||
{ return systask_handle(code, this); }
|
|
||||||
vpiHandle vpi_iterate(int code)
|
|
||||||
{ return systask_iter(code, this); }
|
|
||||||
|
|
||||||
inline const vvp_vector4_t& return_value() const { return return_value_; }
|
inline const vvp_vector4_t& return_value() const { return return_value_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -232,7 +238,6 @@ class sysfunc_vec4 : public __vpiSysTaskCall {
|
||||||
vpiHandle put_value_vector_(p_vpi_value vp);
|
vpiHandle put_value_vector_(p_vpi_value vp);
|
||||||
vpiHandle put_value_time_(p_vpi_value vp);
|
vpiHandle put_value_time_(p_vpi_value vp);
|
||||||
|
|
||||||
private:
|
|
||||||
vvp_vector4_t return_value_;
|
vvp_vector4_t return_value_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -388,48 +393,15 @@ vpiHandle sysfunc_vec4::vpi_put_value(p_vpi_value vp, int)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sysfunc_4net : public __vpiSysTaskCall {
|
struct sysfunc_4net : public sysfunc_def {
|
||||||
explicit inline sysfunc_4net(unsigned wid) : vwid_(wid) { }
|
explicit inline sysfunc_4net(unsigned wid) : vwid_(wid) { }
|
||||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
|
||||||
int vpi_get(int code);
|
int vpi_get(int code);
|
||||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
||||||
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||||
vpiHandle vpi_handle(int code)
|
|
||||||
{ return systask_handle(code, this); }
|
|
||||||
vpiHandle vpi_iterate(int code)
|
|
||||||
{ return systask_iter(code, this); }
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned vwid_;
|
unsigned vwid_;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct sysfunc_rnet : public __vpiSysTaskCall {
|
|
||||||
inline sysfunc_rnet() { }
|
|
||||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
|
||||||
int vpi_get(int code) { return sysfunc_get(code, this); }
|
|
||||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
||||||
vpiHandle vpi_put_value(p_vpi_value val, int flags)
|
|
||||||
{ return sysfunc_put_rnet_value(this, val, flags); }
|
|
||||||
vpiHandle vpi_handle(int code)
|
|
||||||
{ return systask_handle(code, this); }
|
|
||||||
vpiHandle vpi_iterate(int code)
|
|
||||||
{ return systask_iter(code, this); }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct sysfunc_no : public __vpiSysTaskCall {
|
|
||||||
inline sysfunc_no() { }
|
|
||||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
|
||||||
int vpi_get(int code) { return sysfunc_get(code, this); }
|
|
||||||
char* vpi_get_str(int code) { return systask_get_str(code, this); }
|
|
||||||
vpiHandle vpi_put_value(p_vpi_value val, int flags)
|
|
||||||
{ return sysfunc_put_no_value(this, val, flags); }
|
|
||||||
vpiHandle vpi_handle(int code)
|
|
||||||
{ return systask_handle(code, this); }
|
|
||||||
vpiHandle vpi_iterate(int code)
|
|
||||||
{ return systask_iter(code, this); }
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// support getting vpiSize for a system function call
|
// support getting vpiSize for a system function call
|
||||||
int sysfunc_4net::vpi_get(int code)
|
int sysfunc_4net::vpi_get(int code)
|
||||||
{
|
{
|
||||||
|
|
@ -547,6 +519,41 @@ vpiHandle sysfunc_4net::vpi_put_value(p_vpi_value vp, int)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct sysfunc_rnet : public sysfunc_def {
|
||||||
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
vpiHandle sysfunc_rnet::vpi_put_value(p_vpi_value vp, int)
|
||||||
|
{
|
||||||
|
put_value = true;
|
||||||
|
|
||||||
|
double value;
|
||||||
|
switch (vp->format) {
|
||||||
|
|
||||||
|
case vpiRealVal:
|
||||||
|
value = vp->value.real;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
value = 0.0;
|
||||||
|
fprintf(stderr, "Unsupported format %d.\n", (int)vp->format);
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
fnet->send_real(value, vthread_get_wt_context());
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct sysfunc_no : public sysfunc_def {
|
||||||
|
vpiHandle vpi_put_value(p_vpi_value val, int flags);
|
||||||
|
};
|
||||||
|
|
||||||
|
vpiHandle sysfunc_no::vpi_put_value(p_vpi_value, int)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* **** Manipulate the internal data structures. **** */
|
/* **** Manipulate the internal data structures. **** */
|
||||||
|
|
||||||
|
|
@ -845,6 +852,9 @@ vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_wid
|
||||||
} else if (val_code == -vpiVectorVal) {
|
} else if (val_code == -vpiVectorVal) {
|
||||||
obj = new sysfunc_vec4(return_width);
|
obj = new sysfunc_vec4(return_width);
|
||||||
|
|
||||||
|
} else if (val_code == -vpiStringVal) {
|
||||||
|
obj = new sysfunc_str;
|
||||||
|
|
||||||
} else if (val_code == 0 && fnet == 0) {
|
} else if (val_code == 0 && fnet == 0) {
|
||||||
obj = new sysfunc_no;
|
obj = new sysfunc_no;
|
||||||
|
|
||||||
|
|
@ -957,12 +967,15 @@ void vpip_execute_vpi_call(vthread_t thr, vpiHandle ref)
|
||||||
if (vpip_cur_task->string_stack > 0)
|
if (vpip_cur_task->string_stack > 0)
|
||||||
vthread_pop_str(thr, vpip_cur_task->string_stack);
|
vthread_pop_str(thr, vpip_cur_task->string_stack);
|
||||||
|
|
||||||
/* If the function has a real value, then push the value
|
/* If the function returns a value, then push the value
|
||||||
to the thread stack. */
|
to the appropriate thread stack. */
|
||||||
if (sysfunc_real*func_real = dynamic_cast<sysfunc_real*>(ref)) {
|
if (sysfunc_real*func_real = dynamic_cast<sysfunc_real*>(ref)) {
|
||||||
vthread_push_real(thr, func_real->return_value_);
|
vthread_push_real(thr, func_real->return_value());
|
||||||
}
|
}
|
||||||
if (sysfunc_vec4*func_vec4 = dynamic_cast<sysfunc_vec4*>(ref)) {
|
else if (sysfunc_str*func_string = dynamic_cast<sysfunc_str*>(ref)) {
|
||||||
|
vthread_push_str(thr, func_string->return_value());
|
||||||
|
}
|
||||||
|
else if (sysfunc_vec4*func_vec4 = dynamic_cast<sysfunc_vec4*>(ref)) {
|
||||||
vthread_push_vec4(thr, func_vec4->return_value());
|
vthread_push_vec4(thr, func_vec4->return_value());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -346,6 +346,11 @@ void vthread_push_real(struct vthread_s*thr, double val)
|
||||||
thr->push_real(val);
|
thr->push_real(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void vthread_push_str(struct vthread_s*thr, const string&val)
|
||||||
|
{
|
||||||
|
thr->push_str(val);
|
||||||
|
}
|
||||||
|
|
||||||
void vthread_pop_vec4(struct vthread_s*thr, unsigned depth)
|
void vthread_pop_vec4(struct vthread_s*thr, unsigned depth)
|
||||||
{
|
{
|
||||||
thr->pop_vec4(depth);
|
thr->pop_vec4(depth);
|
||||||
|
|
|
||||||
|
|
@ -113,6 +113,7 @@ extern vvp_context_item_t vthread_get_rd_context_item(unsigned context_idx);
|
||||||
* Access value stacks from thread space.
|
* Access value stacks from thread space.
|
||||||
*/
|
*/
|
||||||
extern void vthread_push_vec4(struct vthread_s*thr, const vvp_vector4_t&val);
|
extern void vthread_push_vec4(struct vthread_s*thr, const vvp_vector4_t&val);
|
||||||
|
extern void vthread_push_str(struct vthread_s*thr, const std::string&val);
|
||||||
extern void vthread_push_real(struct vthread_s*thr, double val);
|
extern void vthread_push_real(struct vthread_s*thr, double val);
|
||||||
|
|
||||||
extern void vthread_pop_vec4(struct vthread_s*thr, unsigned count);
|
extern void vthread_pop_vec4(struct vthread_s*thr, unsigned count);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue