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
|
||||
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"
|
||||
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
|
||||
|
|
|
|||
|
|
@ -2838,7 +2838,7 @@ NetExpr* PEConcat::elaborate_expr(Design*des, NetScope*scope,
|
|||
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 "
|
||||
<< "may not have zero width in this context." << endl;
|
||||
des->errors += 1;
|
||||
|
|
|
|||
|
|
@ -75,6 +75,10 @@ EXTERN_C_START
|
|||
/********* task/function properties **********/
|
||||
#define vpiOtherFunc 6
|
||||
|
||||
/* Icarus-specific function type to use string as the return type */
|
||||
#define vpiStringFunc 10
|
||||
#define vpiSysFuncString vpiSysFuncString
|
||||
|
||||
EXTERN_C_END
|
||||
|
||||
#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
|
||||
* 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_);
|
||||
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();
|
||||
if (!lsig) {
|
||||
cerr << get_fileline() << ": error: "
|
||||
|
|
@ -218,6 +226,8 @@ bool NetAssignBase::synth_async(Design*des, NetScope*scope,
|
|||
rsig = tmp;
|
||||
}
|
||||
|
||||
rsig = crop_to_width(des, rsig, lsig->vector_width());
|
||||
|
||||
if (nex_out.pin_count() > 1) {
|
||||
NexusSet 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
|
||||
for the inputs of the FF bank. */
|
||||
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
|
||||
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;
|
||||
}
|
||||
|
||||
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",
|
||||
path, name, stype);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -519,3 +519,14 @@ void draw_vpi_rfunc_call(ivl_expr_t 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
|
||||
* 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. */
|
||||
if (ivl_expr_width(le)==use_wid && test_immediate_vec4_ok(le)) {
|
||||
ivl_expr_t tmp = le;
|
||||
re = le;
|
||||
le = tmp;
|
||||
le = re;
|
||||
re = tmp;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
||||
|
|
@ -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)
|
||||
string_ex_pop(expr);
|
||||
else
|
||||
fallback_eval(expr);
|
||||
draw_sfunc_string(expr);
|
||||
break;
|
||||
|
||||
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_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);
|
||||
|
||||
|
|
|
|||
|
|
@ -137,7 +137,7 @@ GenerateStatement::~GenerateStatement()
|
|||
}
|
||||
|
||||
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),
|
||||
lsb_(rang->lsb()), msb_(rang->msb())
|
||||
{
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class GenerateStatement;
|
|||
class SequentialStmt;
|
||||
class Signal;
|
||||
class named_expr_t;
|
||||
class prange_t;
|
||||
class ExpRange;
|
||||
|
||||
/*
|
||||
* The Architecture class carries the contents (name, statements,
|
||||
|
|
@ -142,7 +142,7 @@ class ForGenerate : public GenerateStatement {
|
|||
|
||||
public:
|
||||
ForGenerate(perm_string gname, perm_string genvar,
|
||||
prange_t*rang, std::list<Architecture::Statement*>&s);
|
||||
ExpRange*rang, std::list<Architecture::Statement*>&s);
|
||||
~ForGenerate();
|
||||
|
||||
int elaborate(Entity*ent, Architecture*arc);
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
# include "entity.h"
|
||||
# include "expression.h"
|
||||
# include "sequential.h"
|
||||
# include "subprogram.h"
|
||||
# include <typeinfo>
|
||||
# include <cassert>
|
||||
|
||||
|
|
@ -59,6 +60,11 @@ int Architecture::elaborate(Entity*entity)
|
|||
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
|
||||
// initalization and clean-up actions
|
||||
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.
|
||||
const ExpAttribute*op1 = dynamic_cast<const ExpAttribute*>(op1_raw);
|
||||
const ExpObjAttribute*op1 = dynamic_cast<const ExpObjAttribute*>(op1_raw);
|
||||
if (op1 == 0)
|
||||
return -1;
|
||||
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
|
||||
out << " -- imported types" << endl;
|
||||
|
|
@ -251,9 +251,16 @@ void ExpAggregate::choice_t::dump(ostream&out, int indent) const
|
|||
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;
|
||||
base_->dump(out, indent+4);
|
||||
}
|
||||
|
|
@ -442,13 +449,6 @@ void named_expr_t::dump(ostream&out, int indent) const
|
|||
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
|
||||
{
|
||||
out << typeid(*this).name();
|
||||
|
|
|
|||
|
|
@ -54,29 +54,88 @@ bool Expression::symbolic_compare(const Expression*) const
|
|||
return false;
|
||||
}
|
||||
|
||||
ExpAttribute::ExpAttribute(ExpName*bas, perm_string nam)
|
||||
: base_(bas), name_(nam)
|
||||
ExpAttribute::ExpAttribute(perm_string nam, list<Expression*>*args)
|
||||
: name_(nam), args_(args)
|
||||
{
|
||||
}
|
||||
|
||||
ExpAttribute::~ExpAttribute()
|
||||
{
|
||||
/* Different attributes can point to the same base so we cannot delete this here.
|
||||
* Look at the vhdl_range test with valgrind to see this issue. */
|
||||
// delete base_;
|
||||
if(args_) {
|
||||
for(list<Expression*>::iterator it = args_->begin();
|
||||
it != args_->end(); ++it) {
|
||||
delete *it;
|
||||
}
|
||||
}
|
||||
|
||||
delete args_;
|
||||
}
|
||||
|
||||
Expression*ExpAttribute::clone() const
|
||||
{
|
||||
return new ExpAttribute(static_cast<ExpName*>(base_->clone()), name_);
|
||||
list<Expression*>*ExpAttribute::clone_args() const {
|
||||
list<Expression*>*new_args = NULL;
|
||||
|
||||
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);
|
||||
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)
|
||||
: operand1_(op1), operand2_(op2)
|
||||
{
|
||||
|
|
@ -88,14 +147,14 @@ ExpBinary::~ExpBinary()
|
|||
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)
|
||||
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
@ -203,7 +262,7 @@ ExpAggregate::choice_t::choice_t(const choice_t&other)
|
|||
expr_.reset(e->clone());
|
||||
|
||||
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()
|
||||
|
|
@ -221,7 +280,7 @@ Expression*ExpAggregate::choice_t::simple_expression(bool detach_flag)
|
|||
return res;
|
||||
}
|
||||
|
||||
prange_t*ExpAggregate::choice_t::range_expressions(void)
|
||||
ExpRange*ExpAggregate::choice_t::range_expressions(void)
|
||||
{
|
||||
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_;
|
||||
return true;
|
||||
|
|
@ -535,6 +594,7 @@ ExpName::ExpName(perm_string nn, list<Expression*>*indices)
|
|||
ExpName::ExpName(perm_string nn, Expression*msb, Expression*lsb)
|
||||
: name_(nn), index_(msb), lsb_(lsb)
|
||||
{
|
||||
ivl_assert(*this, !msb || msb != lsb);
|
||||
}
|
||||
|
||||
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)
|
||||
: prefix_(prefix), name_(nn), index_(msb), lsb_(lsb)
|
||||
{
|
||||
ivl_assert(*this, !msb || msb != lsb);
|
||||
}
|
||||
|
||||
ExpName::~ExpName()
|
||||
|
|
@ -712,3 +773,75 @@ double ExpTime::to_fs() const
|
|||
|
||||
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 <vector>
|
||||
|
||||
class prange_t;
|
||||
class Entity;
|
||||
class ExpRange;
|
||||
class ScopeBase;
|
||||
class SubprogramHeader;
|
||||
class VType;
|
||||
|
|
@ -107,8 +106,8 @@ class Expression : public LineInfo {
|
|||
// to constant literal values. Return true and set the val
|
||||
// argument if the evaluation works, or return false if it
|
||||
// cannot be done.
|
||||
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
|
||||
virtual bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||
virtual bool evaluate(Entity*, ScopeBase*, int64_t&) const { return false; }
|
||||
bool evaluate(ScopeBase*scope, int64_t&val) const { return evaluate(NULL, scope, val); }
|
||||
|
||||
// The symbolic compare returns true if the two expressions
|
||||
// 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 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); }
|
||||
|
||||
protected:
|
||||
|
|
@ -205,8 +204,8 @@ class ExpBinary : public Expression {
|
|||
int emit_operand1(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_operand2(ScopeBase*scope, int64_t&val) const;
|
||||
bool eval_operand1(Entity*ent, 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
|
||||
{ operand1_->write_to_stream(out); }
|
||||
|
|
@ -239,7 +238,7 @@ class ExpAggregate : public Expression {
|
|||
// Create a named choice
|
||||
explicit choice_t(perm_string name);
|
||||
// discreate_range choice
|
||||
explicit choice_t(prange_t*ran);
|
||||
explicit choice_t(ExpRange*ran);
|
||||
|
||||
choice_t(const choice_t&other);
|
||||
|
||||
|
|
@ -249,15 +248,15 @@ class ExpAggregate : public Expression {
|
|||
bool others() const;
|
||||
// Return expression if this represents a simple_expression.
|
||||
Expression*simple_expression(bool detach_flag =true);
|
||||
// Return prange_t if this represents a range_expression
|
||||
prange_t*range_expressions(void);
|
||||
// Return ExpRange if this represents a range_expression
|
||||
ExpRange*range_expressions(void);
|
||||
|
||||
void write_to_stream(std::ostream&fd);
|
||||
void dump(ostream&out, int indent) const;
|
||||
|
||||
private:
|
||||
std::auto_ptr<Expression>expr_;
|
||||
std::auto_ptr<prange_t> range_;
|
||||
std::auto_ptr<ExpRange> range_;
|
||||
private: // not implemented
|
||||
choice_t& operator= (const choice_t&);
|
||||
};
|
||||
|
|
@ -343,7 +342,7 @@ class ExpArithmetic : public ExpBinary {
|
|||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||
void write_to_stream(std::ostream&fd) const;
|
||||
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;
|
||||
|
||||
private:
|
||||
|
|
@ -356,18 +355,60 @@ class ExpArithmetic : public ExpBinary {
|
|||
class ExpAttribute : public Expression {
|
||||
|
||||
public:
|
||||
ExpAttribute(ExpName*base, perm_string name);
|
||||
~ExpAttribute();
|
||||
ExpAttribute(perm_string name,std::list<Expression*>*args);
|
||||
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;
|
||||
|
||||
inline perm_string peek_attribute() const { return name_; }
|
||||
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;
|
||||
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
|
||||
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);
|
||||
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
|
||||
bool evaluate(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);
|
||||
|
||||
private:
|
||||
ExpName*base_;
|
||||
perm_string name_;
|
||||
const VType*base_;
|
||||
};
|
||||
|
||||
class ExpBitstring : public Expression {
|
||||
|
|
@ -440,7 +480,6 @@ class ExpConcat : public Expression {
|
|||
int elaborate_expr(Entity*ent, ScopeBase*scope, const VType*ltype);
|
||||
void write_to_stream(std::ostream&fd) const;
|
||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||
virtual bool evaluate(ScopeBase*scope, int64_t&val) const;
|
||||
bool is_primary(void) const;
|
||||
void dump(ostream&out, int indent = 0) const;
|
||||
void visit(ExprVisitor& func);
|
||||
|
|
@ -583,7 +622,7 @@ class ExpInteger : public Expression {
|
|||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||
int emit_package(std::ostream&out);
|
||||
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;
|
||||
virtual ostream& dump_inline(ostream&out) const;
|
||||
|
||||
|
|
@ -665,7 +704,6 @@ class ExpName : public Expression {
|
|||
void write_to_stream(std::ostream&fd) const;
|
||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||
bool is_primary(void) const;
|
||||
bool evaluate(ScopeBase*scope, int64_t&val) const;
|
||||
bool evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const;
|
||||
bool symbolic_compare(const Expression*that) 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);
|
||||
void write_to_stream(std::ostream&fd) const;
|
||||
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;
|
||||
|
||||
private:
|
||||
|
|
@ -891,7 +929,6 @@ class ExpTime : public Expression {
|
|||
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);
|
||||
//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;
|
||||
|
||||
|
|
@ -902,6 +939,46 @@ class ExpTime : public Expression {
|
|||
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.
|
||||
int elaborate_argument(Expression*expr, const SubprogramHeader*subp,
|
||||
int idx, Entity*ent, ScopeBase*scope);
|
||||
|
|
|
|||
|
|
@ -117,3 +117,9 @@ void ExpTime::dump(ostream&out, int indent) const
|
|||
out << setw(indent) << "" << "Time ";
|
||||
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;
|
||||
}
|
||||
|
||||
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
|
||||
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;
|
||||
bool flag;
|
||||
|
||||
flag = index_->evaluate(scope, use_msb);
|
||||
flag = index_->evaluate(ent, scope, use_msb);
|
||||
ivl_assert(*this, flag);
|
||||
flag = lsb_->evaluate(scope, use_lsb);
|
||||
flag = lsb_->evaluate(ent, scope, use_lsb);
|
||||
ivl_assert(*this, flag);
|
||||
|
||||
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;
|
||||
|
||||
if (const InterfacePort*cur = ent->find_port(name_)) {
|
||||
if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) {
|
||||
cerr << get_fileline() << ": error: Assignment to "
|
||||
"input port " << name_ << "." << endl;
|
||||
return errors += 1;
|
||||
}
|
||||
if (ent) {
|
||||
if (const InterfacePort*cur = ent->find_port(name_)) {
|
||||
if (cur->mode != PORT_OUT && cur->mode != PORT_INOUT) {
|
||||
cerr << get_fileline() << ": error: Assignment to "
|
||||
"input port " << name_ << "." << endl;
|
||||
return errors += 1;
|
||||
}
|
||||
|
||||
if (is_sequ)
|
||||
ent->set_declaration_l_value(name_, is_sequ);
|
||||
if (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 "
|
||||
<< name_ << " from entity "
|
||||
<< ent->get_name() << "." << endl;
|
||||
return 1;
|
||||
cerr << get_fileline() << ": error: Assignment to generic "
|
||||
<< name_ << " from entity "
|
||||
<< ent->get_name() << "." << endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (Signal*sig = scope->find_signal(name_)) {
|
||||
// Tell the target signal that this may be a sequential l-value.
|
||||
if (is_sequ) sig->count_ref_sequ();
|
||||
if (!found_type && scope) {
|
||||
if (Signal*sig = scope->find_signal(name_)) {
|
||||
// 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_)) {
|
||||
// Tell the target signal that this may be a sequential l-value.
|
||||
if (is_sequ) var->count_ref_sequ();
|
||||
} else if (Variable*var = scope->find_variable(name_)) {
|
||||
// Tell the target signal that this may be a sequential l-value.
|
||||
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) {
|
||||
|
|
@ -318,7 +327,8 @@ int ExpName::elaborate_rval(Entity*ent, ScopeBase*scope, const InterfacePort*lva
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -393,7 +403,7 @@ const VType*ExpAggregate::fit_type(Entity*, ScopeBase*, const VTypeArray*host) c
|
|||
elements_[0]->map_choices(&ce[0]);
|
||||
|
||||
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);
|
||||
|
||||
Expression*use_msb = prange->msb();
|
||||
|
|
@ -573,23 +583,32 @@ const VType* ExpArithmetic::resolve_operand_types_(const VType*t1, const VType*t
|
|||
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 NULL;
|
||||
}
|
||||
|
||||
int ExpTypeAttribute::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
||||
{
|
||||
// This is just to mute warnings, there is nothing to elaborate here
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ExpAttribute::elaborate_expr(Entity*ent, ScopeBase*scope, const VType*)
|
||||
const VType* ExpTypeAttribute::probe_type(Entity*, ScopeBase*) const
|
||||
{
|
||||
int errors = 0;
|
||||
const VType*sub_type = base_->probe_type(ent, scope);
|
||||
errors += base_->elaborate_expr(ent, scope, sub_type);
|
||||
return errors;
|
||||
if(name_ == "image")
|
||||
return &primitive_STRING;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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 ExpInteger(1));
|
||||
|
||||
std::list<prange_t*> ranges;
|
||||
ranges.push_front(new prange_t(size, new ExpInteger(0), true));
|
||||
std::list<ExpRange*> ranges;
|
||||
ranges.push_front(new ExpRange(size, new ExpInteger(0), ExpRange::DOWNTO));
|
||||
const VType*array = new VTypeArray(types[1], &ranges);
|
||||
|
||||
return array;
|
||||
|
|
@ -912,31 +931,31 @@ const VType* ExpName::probe_type(Entity*ent, ScopeBase*scope) const
|
|||
|
||||
if(ent) {
|
||||
if (const InterfacePort*cur = ent->find_port(name_)) {
|
||||
ivl_assert(*this, cur->type);
|
||||
return cur->type;
|
||||
ivl_assert(*this, cur->type);
|
||||
return cur->type;
|
||||
}
|
||||
|
||||
if (const InterfacePort*cur = ent->find_generic(name_)) {
|
||||
ivl_assert(*this, cur->type);
|
||||
return cur->type;
|
||||
ivl_assert(*this, cur->type);
|
||||
return cur->type;
|
||||
}
|
||||
}
|
||||
|
||||
if(scope) {
|
||||
if (Signal*sig = scope->find_signal(name_))
|
||||
return sig->peek_type();
|
||||
return sig->peek_type();
|
||||
|
||||
if (Variable*var = scope->find_variable(name_))
|
||||
return var->peek_type();
|
||||
return var->peek_type();
|
||||
|
||||
const VType*type = 0;
|
||||
Expression*cval = 0;
|
||||
if (scope->find_constant(name_, type, cval))
|
||||
return type;
|
||||
return type;
|
||||
|
||||
Architecture*arc = dynamic_cast<Architecture*>(scope);
|
||||
if (arc && (type = arc->probe_genvar_type(name_))) {
|
||||
return type;
|
||||
return type;
|
||||
}
|
||||
|
||||
if (const InterfacePort*port = scope->find_param(name_)) {
|
||||
|
|
@ -1048,6 +1067,19 @@ int ExpTime::elaborate_expr(Entity*, ScopeBase*, const VType*)
|
|||
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 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
|
||||
// of the range and scan through the values, mapping the
|
||||
// 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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||
int ExpObjAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
// Try to evaluate first
|
||||
int64_t val;
|
||||
if(evaluate(scope, val)) {
|
||||
if(evaluate(ent, scope, val)) {
|
||||
out << val;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -365,12 +365,50 @@ int ExpAttribute::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
return errors;
|
||||
}
|
||||
|
||||
// Fallback
|
||||
out << "$ivl_attribute(";
|
||||
errors += base_->emit(out, ent, scope);
|
||||
out << ", \"" << name_ << "\")";
|
||||
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 errors = 0;
|
||||
|
|
@ -453,17 +491,16 @@ int ExpCharacter::emit_primitive_bit_(ostream&out, Entity*, ScopeBase*,
|
|||
int ExpCharacter::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||
{
|
||||
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)) {
|
||||
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_ << "\"";
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -583,7 +620,10 @@ int ExpFunc::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
{
|
||||
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
|
||||
// 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)
|
||||
{
|
||||
const VTypeArray*arr;
|
||||
const VType*type = peek_type();
|
||||
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);
|
||||
}
|
||||
|
||||
|
|
@ -1028,3 +1069,25 @@ int ExpTime::emit(ostream&out, Entity*, ScopeBase*)
|
|||
|
||||
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 <cmath>
|
||||
|
||||
bool Expression::evaluate(ScopeBase*, int64_t&) 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
|
||||
bool ExpArithmetic::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||
{
|
||||
int64_t val1, val2;
|
||||
bool rc;
|
||||
|
||||
rc = eval_operand1(scope, val1);
|
||||
rc = eval_operand1(ent, scope, val1);
|
||||
if (rc == false)
|
||||
return false;
|
||||
|
||||
rc = eval_operand2(scope, val2);
|
||||
rc = eval_operand2(ent, scope, val2);
|
||||
if (rc == false)
|
||||
return false;
|
||||
|
||||
|
|
@ -83,151 +73,110 @@ bool ExpArithmetic::evaluate(ScopeBase*scope, int64_t&val) const
|
|||
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
|
||||
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();
|
||||
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
|
||||
|
||||
if(!base_type) {
|
||||
const ExpName*name = NULL;
|
||||
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(scope && (name = dynamic_cast<const ExpName*>(base_))) {
|
||||
const perm_string& n = name->peek_name();
|
||||
if(const Variable*var = scope->find_variable(n))
|
||||
base_type = var->peek_type();
|
||||
else if(const Signal*sig = scope->find_signal(n))
|
||||
base_type = sig->peek_type();
|
||||
else if(const InterfacePort*port = scope->find_param(n))
|
||||
base_type = port->type;
|
||||
}
|
||||
}
|
||||
if (arr->dimensions() > 1) {
|
||||
cerr << endl << get_fileline() << ": error: "
|
||||
<< "Cannot apply the '" << name_
|
||||
<< " attribute to multidimensional arrays" << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
if(!base_type)
|
||||
return false; // I tried really hard, sorry
|
||||
if (arr->dimension(0).is_box())
|
||||
return false;
|
||||
|
||||
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;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
if(name_ == "length") {
|
||||
int64_t size = arr->get_width(scope);
|
||||
bool ExpAttribute::evaluate_type_attr(const VType*type, Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||
{
|
||||
if (name_ == "length" && test_array_type(type)) {
|
||||
int64_t size = type->get_width(scope);
|
||||
|
||||
if(size > 0)
|
||||
val = size;
|
||||
else
|
||||
return false;
|
||||
} else if(name_ == "left") {
|
||||
arr->dimension(0).msb()->evaluate(scope, val);
|
||||
} else if(name_ == "right") {
|
||||
arr->dimension(0).lsb()->evaluate(scope, val);
|
||||
} else ivl_assert(*this, false);
|
||||
|
||||
return true;
|
||||
if(size > 0) {
|
||||
val = size;
|
||||
return true;
|
||||
}
|
||||
} else if (name_ == "left" && test_array_type(type)) {
|
||||
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
|
||||
return arr->dimension(0).msb()->evaluate(ent, scope, val);
|
||||
} else if (name_ == "right" && test_array_type(type)) {
|
||||
const VTypeArray*arr = dynamic_cast<const VTypeArray*>(type);
|
||||
return arr->dimension(0).lsb()->evaluate(ent, scope, val);
|
||||
}
|
||||
|
||||
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
|
||||
return false;
|
||||
}
|
||||
const VType*base_type = base_->peek_type();
|
||||
|
||||
if (name_ == "left" || name_ == "right") {
|
||||
const VType*base_type = base_->peek_type();
|
||||
if (base_type == 0)
|
||||
base_type = base_->probe_type(ent, scope);
|
||||
if (base_type == NULL)
|
||||
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;
|
||||
}
|
||||
|
||||
bool ExpName::evaluate(ScopeBase*scope, int64_t&val) const
|
||||
bool ExpTypeAttribute::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||
{
|
||||
const VType*type;
|
||||
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);
|
||||
return evaluate_type_attr(base_, ent, scope, val);
|
||||
}
|
||||
|
||||
bool ExpName::evaluate(Entity*ent, ScopeBase*scope, int64_t&val) const
|
||||
{
|
||||
if (prefix_.get()) {
|
||||
cerr << get_fileline() << ": sorry: I don't know how to evaluate ExpName prefix parts." << endl;
|
||||
return false;
|
||||
cerr << get_fileline() << ": sorry: I don't know how to evaluate "
|
||||
<< "ExpName prefix parts." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
const InterfacePort*gen = ent->find_generic(name_);
|
||||
if (gen) {
|
||||
cerr << get_fileline() << ": sorry: I don't necessarily handle generic overrides." << endl;
|
||||
if (ent) {
|
||||
const InterfacePort*gen = ent->find_generic(name_);
|
||||
if (gen) {
|
||||
cerr << get_fileline() << ": sorry: I don't necessarily "
|
||||
<< "handle generic overrides." << endl;
|
||||
|
||||
// Evaluate the default expression and use that.
|
||||
if (gen->expr)
|
||||
return gen->expr->evaluate(ent, scope, val);
|
||||
// Evaluate the default expression and use that.
|
||||
if (gen->expr)
|
||||
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;
|
||||
bool rc;
|
||||
|
||||
rc = eval_operand1(scope, val1);
|
||||
rc = eval_operand1(ent, scope, val1);
|
||||
if (rc == false)
|
||||
return false;
|
||||
|
||||
rc = eval_operand2(scope, val2);
|
||||
rc = eval_operand2(ent, scope, val2);
|
||||
if (rc == false)
|
||||
return false;
|
||||
|
||||
|
|
@ -252,7 +201,7 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const
|
|||
return true;
|
||||
}
|
||||
|
||||
/*bool ExpTime::evaluate(ScopeBase*, int64_t&val) const
|
||||
/*bool ExpTime::evaluate(Entity*, ScopeBase*, int64_t&val) const
|
||||
{
|
||||
double v = to_fs();
|
||||
|
||||
|
|
@ -265,8 +214,4 @@ bool ExpShift::evaluate(ScopeBase*scope, int64_t&val) const
|
|||
val = v;
|
||||
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;
|
||||
}
|
||||
|
||||
if (prange_t*rp = range_expressions()) {
|
||||
rp->msb()->write_to_stream(fd);
|
||||
if (rp->is_downto())
|
||||
fd << " downto ";
|
||||
else
|
||||
fd << " to ";
|
||||
rp->msb()->write_to_stream(fd);
|
||||
if (ExpRange*rp = range_expressions()) {
|
||||
rp->write_to_stream(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
fd << "/* ERROR */";
|
||||
|
|
@ -111,7 +107,13 @@ void ExpArithmetic::write_to_stream(ostream&out) const
|
|||
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);
|
||||
fd << "'" << name_;
|
||||
|
|
@ -316,3 +318,19 @@ void ExpTime::write_to_stream(ostream&fd) const
|
|||
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;
|
||||
}
|
||||
|
||||
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_add_directory(const char*directory);
|
||||
|
||||
int elaborate_libraries(void);
|
||||
int emit_packages(void);
|
||||
|
||||
extern SubprogramHeader*library_find_subprogram(perm_string name);
|
||||
|
||||
#endif /* IVL_library_H */
|
||||
|
|
|
|||
|
|
@ -236,20 +236,27 @@ int main(int argc, char*argv[])
|
|||
return 3;
|
||||
}
|
||||
|
||||
errors = elaborate_libraries();
|
||||
if (errors > 0) {
|
||||
fprintf(stderr, "%d errors elaborating libraries.\n", errors);
|
||||
parser_cleanup();
|
||||
return 4;
|
||||
}
|
||||
|
||||
emit_std_types(cout);
|
||||
|
||||
errors = emit_packages();
|
||||
if (errors > 0) {
|
||||
fprintf(stderr, "%d errors emitting packages.\n", errors);
|
||||
parser_cleanup();
|
||||
return 4;
|
||||
return 5;
|
||||
}
|
||||
|
||||
errors = emit_entities();
|
||||
if (errors > 0) {
|
||||
fprintf(stderr, "%d errors emitting design.\n", errors);
|
||||
parser_cleanup();
|
||||
return 4;
|
||||
parser_cleanup();
|
||||
return 6;
|
||||
}
|
||||
|
||||
parser_cleanup();
|
||||
|
|
|
|||
|
|
@ -41,6 +41,18 @@ void Package::set_library(perm_string 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
|
||||
* 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;
|
||||
|
||||
int emit_package(std::ostream&fd) const;
|
||||
int elaborate();
|
||||
|
||||
private:
|
||||
perm_string from_library_;
|
||||
|
|
|
|||
|
|
@ -87,10 +87,6 @@ static ActiveScope*active_scope = new ActiveScope;
|
|||
static stack<ActiveScope*> scope_stack;
|
||||
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
|
||||
* 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;
|
||||
|
||||
prange_t* range;
|
||||
std::list<prange_t*>*range_list;
|
||||
ExpRange*range;
|
||||
std::list<ExpRange*>*range_list;
|
||||
ExpRange::range_dir_t range_dir;
|
||||
|
||||
ExpArithmetic::fun_t arithmetic_op;
|
||||
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. */
|
||||
|
||||
%type <flag> direction
|
||||
|
||||
%type <arithmetic_op> adding_operator
|
||||
%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_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> selected_names use_clause
|
||||
|
||||
|
|
@ -372,6 +367,7 @@ static void touchup_interface_for_functions(std::list<InterfacePort*>*ports)
|
|||
|
||||
%type <range> range
|
||||
%type <range_list> range_list index_constraint
|
||||
%type <range_dir> direction
|
||||
|
||||
%type <case_alt> case_statement_alternative
|
||||
%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
|
||||
: K_assert expression report_statement
|
||||
{ ReportStmt*report = dynamic_cast<ReportStmt*>($3);
|
||||
assert(report);
|
||||
AssertStmt*tmp = new AssertStmt($2, report->message().c_str(), report->severity());
|
||||
AssertStmt*tmp = new AssertStmt($2, report->message(), report->severity());
|
||||
delete report;
|
||||
FILE_NAME(tmp,@2);
|
||||
$$ = tmp;
|
||||
|
|
@ -752,8 +755,9 @@ composite_type_definition
|
|||
|
||||
/* unbounded_array_definition IEEE 1076-2008 P5.3.2.1 */
|
||||
| K_array '(' index_subtype_definition_list ')' K_of subtype_indication
|
||||
{ std::list<prange_t*> r;
|
||||
r.push_back(new prange_t(NULL, NULL, true)); // NULL boundaries indicate unbounded array type
|
||||
{ std::list<ExpRange*> r;
|
||||
// NULL boundaries indicate unbounded array type
|
||||
r.push_back(new ExpRange(NULL, NULL, ExpRange::DOWNTO));
|
||||
VTypeArray*tmp = new VTypeArray($6, &r);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
|
@ -983,8 +987,10 @@ design_units
|
|||
| design_unit
|
||||
;
|
||||
|
||||
/* Indicate the direction as a flag, with "downto" being TRUE. */
|
||||
direction : K_to { $$ = false; } | K_downto { $$ = true; } ;
|
||||
direction
|
||||
: K_to { $$ = ExpRange::TO; }
|
||||
| K_downto { $$ = ExpRange::DOWNTO; }
|
||||
;
|
||||
|
||||
element_association
|
||||
: choices ARROW expression
|
||||
|
|
@ -1258,8 +1264,8 @@ file_declaration
|
|||
|
||||
// add file_open() call in 'initial' block
|
||||
params.push_back(new ExpName(*cur));
|
||||
params.push_back($5->filename());
|
||||
params.push_back($5->kind());
|
||||
params.push_back($5->filename()->clone());
|
||||
params.push_back($5->kind()->clone());
|
||||
ProcedureCall*fopen_call = new ProcedureCall(perm_string::literal("file_open"), ¶ms);
|
||||
active_scope->add_initializer(fopen_call);
|
||||
|
||||
|
|
@ -1268,6 +1274,8 @@ file_declaration
|
|||
params.push_back(new ExpName(*cur));
|
||||
ProcedureCall*fclose_call = new ProcedureCall(perm_string::literal("file_close"), ¶ms);
|
||||
active_scope->add_finalizer(fclose_call);
|
||||
|
||||
delete $5;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1498,7 +1506,7 @@ index_constraint
|
|||
| '(' error ')'
|
||||
{ errormsg(@2, "Errors in the index constraint.\n");
|
||||
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
|
||||
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. */
|
||||
| IDENTIFIER '(' expression_list ')'
|
||||
| IDENTIFIER argument_list
|
||||
{ perm_string name = lex_strings.make($1);
|
||||
delete[]$1;
|
||||
if (active_scope->is_vector_name(name) || is_subprogram_param(name)) {
|
||||
ExpName*tmp = new ExpName(name, $3);
|
||||
ExpName*tmp = new ExpName(name, $2);
|
||||
$$ = tmp;
|
||||
} else {
|
||||
ExpFunc*tmp = new ExpFunc(name, $3);
|
||||
ExpFunc*tmp = new ExpFunc(name, $2);
|
||||
$$ = tmp;
|
||||
}
|
||||
FILE_NAME($$, @1);
|
||||
|
|
@ -1876,10 +1884,18 @@ prefix /* IEEE 1076-2008 P8.1 */
|
|||
primary
|
||||
: name
|
||||
{ $$ = $1; }
|
||||
| name '\'' IDENTIFIER
|
||||
{ perm_string name = lex_strings.make($3);
|
||||
ExpName*base = dynamic_cast<ExpName*> ($1);
|
||||
ExpAttribute*tmp = new ExpAttribute(base, name);
|
||||
| name '\'' IDENTIFIER argument_list_opt
|
||||
{ ExpAttribute*tmp = NULL;
|
||||
perm_string attr = lex_strings.make($3);
|
||||
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);
|
||||
delete[]$3;
|
||||
$$ = tmp;
|
||||
|
|
@ -1980,11 +1996,11 @@ procedure_call
|
|||
delete[] $1;
|
||||
$$ = 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 $3; // parameters are copied in this variant
|
||||
delete $2; // parameters are copied in this variant
|
||||
$$ = tmp;
|
||||
}
|
||||
| IDENTIFIER '(' error ')' ';'
|
||||
|
|
@ -2096,18 +2112,15 @@ process_sensitivity_list
|
|||
|
||||
range
|
||||
: simple_expression direction simple_expression
|
||||
{ prange_t* tmp = new prange_t($1, $3, $2);
|
||||
{ ExpRange* tmp = new ExpRange($1, $3, $2);
|
||||
$$ = tmp;
|
||||
}
|
||||
| name '\'' K_range
|
||||
{
|
||||
prange_t*tmp = NULL;
|
||||
ExpRange*tmp = NULL;
|
||||
ExpName*name = NULL;
|
||||
if((name = dynamic_cast<ExpName*>($1))) {
|
||||
ExpAttribute*left = new ExpAttribute(name, left_attr);
|
||||
ExpAttribute*right = new ExpAttribute(name, right_attr);
|
||||
tmp = new prange_t(left, right, true);
|
||||
tmp->set_auto_dir();
|
||||
tmp = new ExpRange(name, false);
|
||||
} else {
|
||||
errormsg(@1, "'range attribute can be used with named expressions only");
|
||||
}
|
||||
|
|
@ -2115,13 +2128,10 @@ range
|
|||
}
|
||||
| name '\'' K_reverse_range
|
||||
{
|
||||
prange_t*tmp = NULL;
|
||||
ExpRange*tmp = NULL;
|
||||
ExpName*name = NULL;
|
||||
if((name = dynamic_cast<ExpName*>($1))) {
|
||||
ExpAttribute*left = new ExpAttribute(name, left_attr);
|
||||
ExpAttribute*right = new ExpAttribute(name, right_attr);
|
||||
tmp = new prange_t(left, right, false);
|
||||
tmp->set_auto_dir();
|
||||
tmp = new ExpRange(name, true);
|
||||
} else {
|
||||
errormsg(@1, "'reverse_range attribute can be used with named expressions only");
|
||||
}
|
||||
|
|
@ -2131,12 +2141,12 @@ range
|
|||
|
||||
range_list
|
||||
: range
|
||||
{ list<prange_t*>*tmp = new list<prange_t*>;
|
||||
{ list<ExpRange*>*tmp = new list<ExpRange*>;
|
||||
tmp->push_back($1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| range_list ',' range
|
||||
{ list<prange_t*>*tmp = $1;
|
||||
{ list<ExpRange*>*tmp = $1;
|
||||
tmp->push_back($3);
|
||||
$$ = tmp;
|
||||
}
|
||||
|
|
@ -2185,10 +2195,9 @@ relation
|
|||
;
|
||||
|
||||
report_statement
|
||||
: K_report STRING_LITERAL severity_opt ';'
|
||||
: K_report expression severity_opt ';'
|
||||
{ ReportStmt*tmp = new ReportStmt($2, $3);
|
||||
FILE_NAME(tmp,@2);
|
||||
delete[]$2;
|
||||
$$ = 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,
|
||||
ScopeBase*scope, list<prange_t*>*ranges)
|
||||
ScopeBase*scope, list<ExpRange*>*ranges)
|
||||
{
|
||||
if (ranges->size() == 1) {
|
||||
prange_t*tmpr = ranges->front();
|
||||
Expression*lef = tmpr->expr_left();
|
||||
Expression*rig = tmpr->expr_right();
|
||||
ExpRange*tmpr = ranges->front();
|
||||
Expression*lef = tmpr->left();
|
||||
Expression*rig = tmpr->right();
|
||||
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");
|
||||
|
|
@ -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,
|
||||
ScopeBase*scope,
|
||||
Expression*range_left,
|
||||
bool downto,
|
||||
int direction,
|
||||
Expression*range_right)
|
||||
{
|
||||
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)) {
|
||||
subtype = new VTypeRangeConst(base_type, left_val, right_val);
|
||||
} else {
|
||||
subtype = new VTypeRangeExpr(base_type, range_left, range_right, downto);
|
||||
subtype = new VTypeRangeExpr(base_type, range_left, range_right, direction);
|
||||
}
|
||||
|
||||
return subtype;
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ class ActiveScope;
|
|||
class Architecture;
|
||||
class Expression;
|
||||
class Package;
|
||||
class prange_t;
|
||||
class ExpRange;
|
||||
class ScopeBase;
|
||||
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,
|
||||
ScopeBase*scope,
|
||||
std::list<prange_t*>*ranges);
|
||||
std::list<ExpRange*>*ranges);
|
||||
extern const VType* calculate_subtype_range(const YYLTYPE&loc, const char*base_name,
|
||||
ScopeBase*scope,
|
||||
Expression*range_left,
|
||||
bool downto,
|
||||
int direction,
|
||||
Expression*range_right);
|
||||
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -26,7 +26,8 @@
|
|||
class named_expr_t {
|
||||
|
||||
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_; }
|
||||
Expression* expr() const { return expr_; }
|
||||
|
|
@ -68,35 +69,6 @@ class instant_list_t {
|
|||
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 {
|
||||
ExpArithmetic::fun_t op;
|
||||
Expression*term;
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ void ScopeBase::cleanup()
|
|||
* objects from the other scopes untouched.
|
||||
*/
|
||||
delete_all(new_signals_);
|
||||
delete_all(new_variables_);
|
||||
delete_all(new_components_);
|
||||
delete_all(cur_types_);
|
||||
delete_all(cur_constants_);
|
||||
|
|
|
|||
|
|
@ -90,6 +90,8 @@ class ScopeBase {
|
|||
finalizers_.push_back(s);
|
||||
}
|
||||
|
||||
void dump_scope(ostream&out) const;
|
||||
|
||||
protected:
|
||||
void cleanup();
|
||||
|
||||
|
|
@ -154,9 +156,6 @@ class Scope : public ScopeBase {
|
|||
|
||||
ComponentBase* find_component(perm_string by_name);
|
||||
|
||||
public:
|
||||
void dump_scope(ostream&out) const;
|
||||
|
||||
protected:
|
||||
// Helper method for emitting signals in the scope.
|
||||
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();
|
||||
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();
|
||||
delete cur;
|
||||
}
|
||||
|
||||
delete param_list_;
|
||||
}
|
||||
|
||||
ReturnStmt::ReturnStmt(Expression*val)
|
||||
|
|
@ -238,7 +240,7 @@ void LoopStatement::visit(SeqStmtVisitor& func)
|
|||
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)
|
||||
{
|
||||
}
|
||||
|
|
@ -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)
|
||||
{
|
||||
if(sev == ReportStmt::UNSPECIFIED)
|
||||
severity_ = ReportStmt::NOTE;
|
||||
}
|
||||
|
||||
AssertStmt::AssertStmt(Expression*condition, const char*msg, ReportStmt::severity_t sev)
|
||||
: ReportStmt("", sev), cond_(condition)
|
||||
AssertStmt::AssertStmt(Expression*condition, Expression*msg, ReportStmt::severity_t sev)
|
||||
: ReportStmt(msg, sev), cond_(condition)
|
||||
{
|
||||
if(msg == NULL)
|
||||
msg_ = default_msg_;
|
||||
else
|
||||
msg_ = std::string(msg);
|
||||
msg_ = new ExpString(default_msg_);
|
||||
|
||||
if(sev == ReportStmt::UNSPECIFIED)
|
||||
severity_ = ReportStmt::ERROR;
|
||||
}
|
||||
|
||||
const std::string AssertStmt::default_msg_ = std::string("Assertion violation.");
|
||||
const char*AssertStmt::default_msg_ = "Assertion violation.";
|
||||
|
||||
WaitForStmt::WaitForStmt(Expression*delay)
|
||||
: delay_(delay)
|
||||
|
|
|
|||
|
|
@ -250,7 +250,7 @@ class WhileLoopStatement : public LoopStatement {
|
|||
class ForLoopStatement : public LoopStatement {
|
||||
public:
|
||||
ForLoopStatement(perm_string loop_name,
|
||||
perm_string index, prange_t*, list<SequentialStmt*>*);
|
||||
perm_string index, ExpRange*, list<SequentialStmt*>*);
|
||||
~ForLoopStatement();
|
||||
|
||||
int elaborate(Entity*ent, ScopeBase*scope);
|
||||
|
|
@ -264,7 +264,7 @@ class ForLoopStatement : public LoopStatement {
|
|||
int emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope);
|
||||
|
||||
perm_string it_;
|
||||
prange_t* range_;
|
||||
ExpRange* range_;
|
||||
};
|
||||
|
||||
class BasicLoopStatement : public LoopStatement {
|
||||
|
|
@ -280,24 +280,27 @@ class ReportStmt : public SequentialStmt {
|
|||
public:
|
||||
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() {}
|
||||
|
||||
void dump(ostream&out, int indent) const;
|
||||
int elaborate(Entity*ent, ScopeBase*scope);
|
||||
int emit(ostream&out, Entity*entity, ScopeBase*scope);
|
||||
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_; }
|
||||
|
||||
protected:
|
||||
std::string msg_;
|
||||
void dump_sev_msg(ostream&out, int indent) const;
|
||||
|
||||
Expression*msg_;
|
||||
severity_t severity_;
|
||||
};
|
||||
|
||||
class AssertStmt : public ReportStmt {
|
||||
public:
|
||||
AssertStmt(Expression*condition, const char*message,
|
||||
AssertStmt(Expression*condition, Expression*message,
|
||||
ReportStmt::severity_t severity = ReportStmt::ERROR);
|
||||
|
||||
void dump(ostream&out, int indent) const;
|
||||
|
|
@ -309,7 +312,7 @@ class AssertStmt : public ReportStmt {
|
|||
Expression*cond_;
|
||||
|
||||
// Message displayed when there is no report assigned.
|
||||
static const std::string default_msg_;
|
||||
static const char*default_msg_;
|
||||
};
|
||||
|
||||
class WaitForStmt : public SequentialStmt {
|
||||
|
|
|
|||
|
|
@ -169,16 +169,24 @@ void BasicLoopStatement::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+3) << "" << "severity: " << severity_ << endl;
|
||||
out << setw(indent+3) << "" << "message: " << msg_ << endl;
|
||||
dump_sev_msg(out, indent+3);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
out << setw(indent) << "" << "AssertStmt at file=" << get_fileline() << endl;
|
||||
out << setw(indent+3) << "" << "condition: ";
|
||||
cond_->dump(out, indent+3);
|
||||
ReportStmt::dump(out, indent+3);
|
||||
dump_sev_msg(out, indent+3);
|
||||
}
|
||||
|
||||
void WaitForStmt::dump(ostream&out, int indent) const
|
||||
|
|
|
|||
|
|
@ -217,9 +217,17 @@ int BasicLoopStatement::elaborate(Entity*, ScopeBase*)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int ReportStmt::elaborate(Entity*ent, ScopeBase*scope)
|
||||
{
|
||||
return msg_->elaborate_expr(ent, scope, &primitive_STRING);
|
||||
}
|
||||
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -383,10 +383,10 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
ivl_assert(*this, range_);
|
||||
|
||||
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;
|
||||
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();
|
||||
if (scope_name.nil()) {
|
||||
|
|
@ -403,48 +403,31 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
// determined during the run-time
|
||||
errors += emit_runtime_(out, ent, scope);
|
||||
} else {
|
||||
bool dir = range_->is_downto();
|
||||
ExpRange::range_dir_t dir = range_->direction();
|
||||
|
||||
if (!dir) {
|
||||
int64_t tmp = start_val;
|
||||
start_val = finish_val;
|
||||
finish_val = tmp;
|
||||
}
|
||||
if(dir == ExpRange::AUTO)
|
||||
dir = start_val < finish_val ? ExpRange::TO : ExpRange::DOWNTO;
|
||||
|
||||
if (dir && (start_val < finish_val)) {
|
||||
if(range_->is_auto_dir()) {
|
||||
dir = false;
|
||||
} else {
|
||||
out << "begin /* Degenerate loop at " << get_fileline()
|
||||
<< ": " << start_val
|
||||
<< " downto " << finish_val << " */ end" << endl
|
||||
<< "end" << endl;
|
||||
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;
|
||||
}
|
||||
if ((dir == ExpRange::DOWNTO && start_val < finish_val) ||
|
||||
(dir == ExpRange::TO && start_val > finish_val)) {
|
||||
out << "begin /* Degenerate loop at " << get_fileline()
|
||||
<< ": " << start_val;
|
||||
out << (dir == ExpRange::DOWNTO ? " downto " : " to ");
|
||||
out << finish_val << " */ end" << endl
|
||||
<< "end" << endl;
|
||||
return errors;
|
||||
}
|
||||
|
||||
out << "for (\\" << it_ << " = " << start_val << " ; ";
|
||||
|
||||
if (dir)
|
||||
if (dir == ExpRange::DOWNTO)
|
||||
out << "\\" << it_ << " >= " << finish_val;
|
||||
else
|
||||
out << "\\" << it_ << " <= " << finish_val;
|
||||
|
||||
out << "; \\" << it_ << " = \\" << it_;
|
||||
|
||||
if (dir)
|
||||
if (dir == ExpRange::DOWNTO)
|
||||
out << " - 1)";
|
||||
else
|
||||
out << " + 1)";
|
||||
|
|
@ -463,9 +446,7 @@ int ForLoopStatement::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
void ForLoopStatement::write_to_stream(ostream&fd)
|
||||
{
|
||||
fd << "for " << it_ << " in ";
|
||||
range_->expr_left()->write_to_stream(fd);
|
||||
fd << " to ";
|
||||
range_->expr_right()->write_to_stream(fd);
|
||||
range_->write_to_stream(fd);
|
||||
fd << " loop" << endl;
|
||||
write_to_stream_substatements(fd);
|
||||
fd << "end loop;" << endl;
|
||||
|
|
@ -476,41 +457,43 @@ int ForLoopStatement::emit_runtime_(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
int errors = 0;
|
||||
|
||||
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
|
||||
out << " ;\n(";
|
||||
errors += range_->expr_left()->emit(out, ent, scope);
|
||||
errors += range_->left()->emit(out, ent, scope);
|
||||
out << " < ";
|
||||
errors += range_->expr_right()->emit(out, ent, scope);
|
||||
errors += range_->right()->emit(out, ent, scope);
|
||||
out << " ? \\" << it_ << " <= ";
|
||||
errors += range_->expr_right()->emit(out, ent, scope);
|
||||
errors += range_->right()->emit(out, ent, scope);
|
||||
out << " : \\" << it_ << " >= ";
|
||||
errors += range_->expr_right()->emit(out, ent, scope);
|
||||
errors += range_->right()->emit(out, ent, scope);
|
||||
out << ");\n\\" << it_ << " = \\" << it_ << " + (";
|
||||
errors += range_->expr_left()->emit(out, ent, scope);
|
||||
errors += range_->left()->emit(out, ent, scope);
|
||||
out << " < ";
|
||||
errors += range_->expr_right()->emit(out, ent, scope);
|
||||
errors += range_->right()->emit(out, ent, scope);
|
||||
out << " ? 1 : -1))";
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
||||
int ReportStmt::emit(ostream&out, Entity*, ScopeBase*)
|
||||
int ReportStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
||||
{
|
||||
out << "$display(\"";
|
||||
out << "$display(\"** ";
|
||||
|
||||
switch(severity_)
|
||||
{
|
||||
case NOTE: out << "** Note: "; break;
|
||||
case WARNING: out << "** Warning: "; break;
|
||||
case ERROR: out << "** Error: "; break;
|
||||
case FAILURE: out << "** Failure: "; break;
|
||||
case NOTE: out << "Note"; break;
|
||||
case WARNING: out << "Warning"; break;
|
||||
case ERROR: out << "Error"; break;
|
||||
case FAILURE: out << "Failure"; break;
|
||||
case UNSPECIFIED: ivl_assert(*this, false); break;
|
||||
}
|
||||
|
||||
out << ExpString::escape_quot(msg_);
|
||||
out << " (" << get_fileline() << ")\");";
|
||||
out << ": \",";
|
||||
|
||||
msg_->emit(out, ent, scope);
|
||||
out << ",\" (" << get_fileline() << ")\");";
|
||||
|
||||
if(severity_ == FAILURE)
|
||||
out << "$finish();";
|
||||
|
|
@ -522,7 +505,8 @@ int ReportStmt::emit(ostream&out, Entity*, ScopeBase*)
|
|||
|
||||
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 ";
|
||||
switch(severity_)
|
||||
|
|
@ -563,7 +547,7 @@ int WaitForStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
|
||||
out << "#(";
|
||||
errors += delay_->emit(out, ent, scope);
|
||||
out << ")";
|
||||
out << ");" << std::endl;
|
||||
|
||||
return errors;
|
||||
}
|
||||
|
|
@ -586,6 +570,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
case UNTIL:
|
||||
if(!sens_list_.empty()) {
|
||||
out << "@(";
|
||||
|
||||
for(std::set<ExpName*>::iterator it = sens_list_.begin();
|
||||
it != sens_list_.end(); ++it) {
|
||||
if(it != sens_list_.begin())
|
||||
|
|
@ -594,7 +579,7 @@ int WaitStmt::emit(ostream&out, Entity*ent, ScopeBase*scope)
|
|||
(*it)->emit(out, ent, scope);
|
||||
}
|
||||
|
||||
out << ");";
|
||||
out << "); ";
|
||||
}
|
||||
|
||||
out << "wait(";
|
||||
|
|
|
|||
|
|
@ -46,20 +46,20 @@ const VTypeArray primitive_UNSIGNED(&primitive_STDLOGIC, vector<VTypeArra
|
|||
void generate_global_types(ActiveScope*res)
|
||||
{
|
||||
// boolean
|
||||
list<perm_string>*enum_BOOLEAN_vals = new list<perm_string>;
|
||||
enum_BOOLEAN_vals->push_back(perm_string::literal("false"));
|
||||
enum_BOOLEAN_vals->push_back(perm_string::literal("true"));
|
||||
VTypeEnum*enum_BOOLEAN = new VTypeEnum(enum_BOOLEAN_vals);
|
||||
list<perm_string> enum_BOOLEAN_vals;
|
||||
enum_BOOLEAN_vals.push_back(perm_string::literal("false"));
|
||||
enum_BOOLEAN_vals.push_back(perm_string::literal("true"));
|
||||
VTypeEnum*enum_BOOLEAN = new VTypeEnum(&enum_BOOLEAN_vals);
|
||||
type_BOOLEAN.set_definition(enum_BOOLEAN);
|
||||
std_types[type_BOOLEAN.peek_name()] = &type_BOOLEAN;
|
||||
std_enums.push_back(enum_BOOLEAN);
|
||||
|
||||
// file_open_kind
|
||||
list<perm_string>*enum_FILE_OPEN_KIND_vals = new list<perm_string>;
|
||||
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("append_mode"));
|
||||
VTypeEnum*enum_FILE_OPEN_KIND = new VTypeEnum(enum_FILE_OPEN_KIND_vals);
|
||||
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("write_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);
|
||||
type_FILE_OPEN_KIND.set_definition(enum_FILE_OPEN_KIND);
|
||||
std_types[type_FILE_OPEN_KIND.peek_name()] = &type_FILE_OPEN_KIND;
|
||||
std_enums.push_back(enum_FILE_OPEN_KIND);
|
||||
|
|
@ -80,10 +80,12 @@ void delete_global_types()
|
|||
{
|
||||
typedef_context_t typedef_ctx;
|
||||
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;
|
||||
}
|
||||
|
||||
// std_enums are destroyed above
|
||||
}
|
||||
|
||||
const VTypeEnum*find_std_enum_name(perm_string name)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@
|
|||
class ActiveScope;
|
||||
|
||||
void emit_std_types(ostream&out);
|
||||
int emit_packages(void);
|
||||
void generate_global_types(ActiveScope*res);
|
||||
bool is_global_type(perm_string type_name);
|
||||
void delete_global_types();
|
||||
|
|
|
|||
|
|
@ -53,6 +53,18 @@ void SubprogramBody::set_statements(list<SequentialStmt*>*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
|
||||
{
|
||||
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);
|
||||
inline bool empty_statements() const { return !statements_ || statements_->empty(); }
|
||||
|
||||
int elaborate();
|
||||
int emit(ostream&out, Entity*ent, ScopeBase*scope);
|
||||
|
||||
// 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_; }
|
||||
|
||||
int elaborate() { return (body_ ? body_->elaborate() : 0); }
|
||||
|
||||
// Function name used in the emission step. The main purpose of this
|
||||
// method is to handle functions offered by standard VHDL libraries.
|
||||
// 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;
|
||||
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());
|
||||
|
||||
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.
|
||||
* FIXME: We are copying pointers from the prange_t object into the
|
||||
* range_t. This means that we cannot delete the prange_t object
|
||||
* FIXME: We are copying pointers from the ExpRange object into the
|
||||
* range_t. This means that we cannot delete the ExpRange object
|
||||
* unless we invent a way to remove the pointers from that object. So
|
||||
* 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)
|
||||
{
|
||||
for (size_t idx = 0 ; idx < ranges_.size() ; idx += 1) {
|
||||
prange_t*curp = r->front();
|
||||
ExpRange*curp = r->front();
|
||||
r->pop_front();
|
||||
Expression*msb = curp->msb();
|
||||
Expression*lsb = curp->lsb();
|
||||
bool dir = curp->is_downto();
|
||||
ranges_[idx] = range_t(msb, lsb, dir);
|
||||
ranges_[idx] = range_t(curp->msb(), curp->lsb(), curp->direction());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ class Architecture;
|
|||
class ScopeBase;
|
||||
class Entity;
|
||||
class Expression;
|
||||
class prange_t;
|
||||
class ExpRange;
|
||||
class VTypeDef;
|
||||
class ScopeBase;
|
||||
|
||||
|
|
@ -210,7 +210,7 @@ class VTypeArray : public VType {
|
|||
|
||||
public:
|
||||
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();
|
||||
|
||||
|
|
|
|||
|
|
@ -169,10 +169,11 @@ static int get_default_format(const char *name)
|
|||
int default_format;
|
||||
|
||||
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 'r':
|
||||
case 't':
|
||||
case 'f':
|
||||
case 'y': default_format = vpiDecStrVal; break;
|
||||
case 'h': default_format = vpiHexStrVal; 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':
|
||||
*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) {
|
||||
vpi_printf("WARNING: %s:%d: missing argument for %s%s.\n",
|
||||
info->filename, info->lineno, info->name, fmtb);
|
||||
|
|
@ -647,6 +644,29 @@ static unsigned int get_format_char(char **rtn, int ljust, int plus,
|
|||
} else {
|
||||
char *tbuf;
|
||||
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 suff_len = strlen(timeformat_info.suff);
|
||||
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);
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
vpiHandle callh, argv, scope;
|
||||
|
|
@ -1246,6 +1267,7 @@ static PLI_INT32 sys_display_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
|||
char* result;
|
||||
unsigned int size;
|
||||
PLI_UINT32 fd_mcd;
|
||||
s_vpi_value val;
|
||||
|
||||
callh = vpi_handle(vpiSysTfCall, 0);
|
||||
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') {
|
||||
errno = 0;
|
||||
vpiHandle arg = vpi_scan(argv);
|
||||
s_vpi_value val;
|
||||
val.format = vpiIntVal;
|
||||
vpi_get_value(arg, &val);
|
||||
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);
|
||||
return 0;
|
||||
}
|
||||
} else if(strncmp(name,"$sformatf",9) == 0) {
|
||||
/* return as a string */
|
||||
fd_mcd = 0;
|
||||
} else {
|
||||
/* stdout */
|
||||
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
|
||||
* returned string strlen() may not match the real size! */
|
||||
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.items);
|
||||
free(result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -1665,7 +1698,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
|||
if (argv == 0) {
|
||||
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, 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);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1686,7 +1719,7 @@ static PLI_INT32 sys_sformat_compiletf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
|||
if (arg == 0) {
|
||||
vpi_printf("ERROR:%s:%d: ", vpi_get_str(vpiFile, 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);
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1754,6 +1787,46 @@ static PLI_INT32 sys_sformat_calltf(ICARUS_VPI_CONST PLI_BYTE8 *name)
|
|||
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)
|
||||
{
|
||||
(void)cb_data; /* Parameter is not used. */
|
||||
|
|
@ -2434,6 +2507,16 @@ void sys_display_register(void)
|
|||
res = vpi_register_systf(&tf_data);
|
||||
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 */
|
||||
tf_data.type = vpiSysTask;
|
||||
tf_data.tfname = "$timeformat";
|
||||
|
|
|
|||
|
|
@ -24,3 +24,5 @@ $table_model vpiSysFuncReal
|
|||
|
||||
$ivl_string_method$len vpiSysFuncInt
|
||||
$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_func <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
|
||||
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_func" { return K_vpi_func; }
|
||||
"%vpi_func/r" { return K_vpi_func_r; }
|
||||
"%vpi_func/s" { return K_vpi_func_s; }
|
||||
"%file_line" { return K_file_line; }
|
||||
|
||||
/* 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/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
|
||||
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_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_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_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
|
||||
|
|
@ -658,6 +658,10 @@ statement
|
|||
{ compile_vpi_func_call($1, $5, -vpiRealVal, 0, $3, $4,
|
||||
$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
|
||||
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 {
|
||||
inline systask_def() { }
|
||||
int get_type_code(void) const { return vpiSysTaskCall; }
|
||||
int vpi_get(int code) { return systask_get(code, this); }
|
||||
char*vpi_get_str(int code) { return systask_get_str(code, this); }
|
||||
vpiHandle vpi_handle(int code) { return systask_handle(code, this); }
|
||||
vpiHandle vpi_iterate(int code){ return systask_iter(code, this); }
|
||||
virtual ~systask_def() {};
|
||||
virtual int get_type_code(void) const { return vpiSysTaskCall; }
|
||||
virtual int vpi_get(int code) { return systask_get(code, this); }
|
||||
virtual char*vpi_get_str(int code) { return systask_get_str(code, this); }
|
||||
virtual vpiHandle vpi_handle(int code) { return systask_handle(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 __vpiSysTaskCall*rfp = dynamic_cast<__vpiSysTaskCall*>(ref);
|
||||
struct sysfunc_def : public systask_def {
|
||||
virtual ~sysfunc_def() {};
|
||||
virtual int get_type_code(void) const { return vpiSysFuncCall; }
|
||||
virtual int vpi_get(int code) { return sysfunc_get(code, this); }
|
||||
};
|
||||
|
||||
rfp->put_value = true;
|
||||
|
||||
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); }
|
||||
struct sysfunc_real : public sysfunc_def {
|
||||
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 double return_value() const { return return_value_; }
|
||||
|
||||
private:
|
||||
double return_value_;
|
||||
};
|
||||
|
||||
|
|
@ -211,18 +182,53 @@ vpiHandle sysfunc_real::vpi_put_value(p_vpi_value vp, int)
|
|||
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:
|
||||
explicit inline sysfunc_vec4(unsigned wid): return_value_(wid, BIT4_X) { }
|
||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
||||
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_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_; }
|
||||
|
||||
private:
|
||||
|
|
@ -232,7 +238,6 @@ class sysfunc_vec4 : public __vpiSysTaskCall {
|
|||
vpiHandle put_value_vector_(p_vpi_value vp);
|
||||
vpiHandle put_value_time_(p_vpi_value vp);
|
||||
|
||||
private:
|
||||
vvp_vector4_t return_value_;
|
||||
};
|
||||
|
||||
|
|
@ -388,48 +393,15 @@ vpiHandle sysfunc_vec4::vpi_put_value(p_vpi_value vp, int)
|
|||
return 0;
|
||||
}
|
||||
|
||||
struct sysfunc_4net : public __vpiSysTaskCall {
|
||||
struct sysfunc_4net : public sysfunc_def {
|
||||
explicit inline sysfunc_4net(unsigned wid) : vwid_(wid) { }
|
||||
int get_type_code(void) const { return vpiSysFuncCall; }
|
||||
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_handle(int code)
|
||||
{ return systask_handle(code, this); }
|
||||
vpiHandle vpi_iterate(int code)
|
||||
{ return systask_iter(code, this); }
|
||||
|
||||
private:
|
||||
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
|
||||
int sysfunc_4net::vpi_get(int code)
|
||||
{
|
||||
|
|
@ -547,6 +519,41 @@ vpiHandle sysfunc_4net::vpi_put_value(p_vpi_value vp, int)
|
|||
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. **** */
|
||||
|
||||
|
|
@ -845,6 +852,9 @@ vpiHandle vpip_build_vpi_call(const char*name, int val_code, unsigned return_wid
|
|||
} else if (val_code == -vpiVectorVal) {
|
||||
obj = new sysfunc_vec4(return_width);
|
||||
|
||||
} else if (val_code == -vpiStringVal) {
|
||||
obj = new sysfunc_str;
|
||||
|
||||
} else if (val_code == 0 && fnet == 0) {
|
||||
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)
|
||||
vthread_pop_str(thr, vpip_cur_task->string_stack);
|
||||
|
||||
/* If the function has a real value, then push the value
|
||||
to the thread stack. */
|
||||
/* If the function returns a value, then push the value
|
||||
to the appropriate thread stack. */
|
||||
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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -346,6 +346,11 @@ void vthread_push_real(struct vthread_s*thr, double 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)
|
||||
{
|
||||
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.
|
||||
*/
|
||||
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_pop_vec4(struct vthread_s*thr, unsigned count);
|
||||
|
|
|
|||
Loading…
Reference in New Issue