Detect and elaborate AMS access functions.
Detect function call expressions that turn out to be calls to the access function of a nature. Elaborate the access function and stub the emit code. This gets the access function just short of the code generator.
This commit is contained in:
parent
25a27f9dd9
commit
9f04641fc7
1
PExpr.h
1
PExpr.h
|
|
@ -731,6 +731,7 @@ class PECallFunction : public PExpr {
|
|||
bool check_call_matches_definition_(Design*des, NetScope*dscope) const;
|
||||
|
||||
NetExpr* elaborate_sfunc_(Design*des, NetScope*scope, int expr_wid) const;
|
||||
NetExpr* elaborate_access_func_(Design*des, NetScope*scope, int expr_wid) const;
|
||||
NetNet* elaborate_net_sfunc_(Design*des, NetScope*scope,
|
||||
unsigned width,
|
||||
const NetExpr* rise,
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@
|
|||
# include <iomanip>
|
||||
# include "netlist.h"
|
||||
# include "compiler.h"
|
||||
# include "discipline.h"
|
||||
# include "ivl_assert.h"
|
||||
|
||||
static ostream& operator<< (ostream&o, NetBlock::Type t)
|
||||
|
|
@ -1182,6 +1183,12 @@ void NetExpr::dump(ostream&o) const
|
|||
o << "(?" << typeid(*this).name() << "?)";
|
||||
}
|
||||
|
||||
void NetEAccess::dump(ostream&o) const
|
||||
{
|
||||
o << nature_->name() << "." << nature_->access() << "(";
|
||||
o << ")";
|
||||
}
|
||||
|
||||
void NetEBinary::dump(ostream&o) const
|
||||
{
|
||||
if (op_ == 'm' || op_ == 'M') {
|
||||
|
|
|
|||
|
|
@ -71,5 +71,7 @@ class discipline_t : public LineInfo {
|
|||
|
||||
extern map<perm_string,nature_t*> natures;
|
||||
extern map<perm_string,discipline_t*> disciplines;
|
||||
// Map access function name to the nature that it accesses.
|
||||
extern map<perm_string,nature_t*> access_function_nature;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,6 +21,15 @@
|
|||
|
||||
# include "netlist.h"
|
||||
# include <cassert>
|
||||
# include "ivl_assert.h"
|
||||
|
||||
NetEAccess* NetEAccess::dup_expr() const
|
||||
{
|
||||
NetEAccess*tmp = new NetEAccess(nature_);
|
||||
ivl_assert(*this, tmp);
|
||||
tmp->set_line(*this);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetEBComp* NetEBComp::dup_expr() const
|
||||
{
|
||||
|
|
|
|||
31
elab_expr.cc
31
elab_expr.cc
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
# include "pform.h"
|
||||
# include "netlist.h"
|
||||
# include "discipline.h"
|
||||
# include "netmisc.h"
|
||||
# include "util.h"
|
||||
# include "ivl_assert.h"
|
||||
|
|
@ -601,6 +602,26 @@ NetExpr* PECallFunction::elaborate_sfunc_(Design*des, NetScope*scope, int expr_w
|
|||
return fun;
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_access_func_(Design*des, NetScope*scope,
|
||||
int expr_wid) const
|
||||
{
|
||||
// Hierarchical names cannot be access functions.
|
||||
if (path_.size() != 1)
|
||||
return 0;
|
||||
|
||||
perm_string access_name = peek_tail_name(path_);
|
||||
nature_t*nature = access_function_nature[access_name];
|
||||
|
||||
// If the name doesn't match any access functions, then give up.
|
||||
if (nature == 0)
|
||||
return 0;
|
||||
|
||||
NetEAccess*tmp = new NetEAccess(nature);
|
||||
tmp->set_line(*this);
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
||||
int expr_wid, bool) const
|
||||
{
|
||||
|
|
@ -609,15 +630,21 @@ NetExpr* PECallFunction::elaborate_expr(Design*des, NetScope*scope,
|
|||
|
||||
NetFuncDef*def = des->find_function(scope, path_);
|
||||
if (def == 0) {
|
||||
// Not a user defined function. Maybe it is an access
|
||||
// function for a nature? If so then elaborate it that way.
|
||||
NetExpr*tmp = elaborate_access_func_(des, scope, expr_wid);
|
||||
if (tmp != 0)
|
||||
return tmp;
|
||||
|
||||
cerr << get_fileline() << ": error: No function " << path_ <<
|
||||
" in this context (" << scope_path(scope) << ")." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
}
|
||||
assert(def);
|
||||
ivl_assert(*this, def);
|
||||
|
||||
NetScope*dscope = def->scope();
|
||||
assert(dscope);
|
||||
ivl_assert(*this, dscope);
|
||||
|
||||
if (! check_call_matches_definition_(des, dscope))
|
||||
return 0;
|
||||
|
|
|
|||
8
emit.cc
8
emit.cc
|
|
@ -198,8 +198,7 @@ bool NetProc::emit_proc(struct target_t*tgt) const
|
|||
|
||||
bool NetAssign::emit_proc(struct target_t*tgt) const
|
||||
{
|
||||
tgt->proc_assign(this);
|
||||
return true;
|
||||
return tgt->proc_assign(this);
|
||||
}
|
||||
|
||||
bool NetAssignNB::emit_proc(struct target_t*tgt) const
|
||||
|
|
@ -461,6 +460,11 @@ int Design::emit(struct target_t*tgt) const
|
|||
return rc;
|
||||
}
|
||||
|
||||
void NetEAccess::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_access_func(this);
|
||||
}
|
||||
|
||||
void NetEBinary::expr_scan(struct expr_scan_t*tgt) const
|
||||
{
|
||||
tgt->expr_binary(this);
|
||||
|
|
|
|||
14
net_expr.cc
14
net_expr.cc
|
|
@ -588,3 +588,17 @@ ivl_variable_type_t NetESFunc::expr_type() const
|
|||
{
|
||||
return type_;
|
||||
}
|
||||
|
||||
NetEAccess::NetEAccess(nature_t*nat)
|
||||
: nature_(nat)
|
||||
{
|
||||
}
|
||||
|
||||
NetEAccess::~NetEAccess()
|
||||
{
|
||||
}
|
||||
|
||||
ivl_variable_type_t NetEAccess::expr_type() const
|
||||
{
|
||||
return IVL_VT_REAL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,6 +62,11 @@ NexusSet* NetEConcat::nex_input(bool rem_out)
|
|||
return result;
|
||||
}
|
||||
|
||||
NexusSet* NetEAccess::nex_input(bool rem_out)
|
||||
{
|
||||
return new NexusSet;
|
||||
}
|
||||
|
||||
/*
|
||||
* A constant has not inputs, so always return an empty set.
|
||||
*/
|
||||
|
|
|
|||
21
netlist.h
21
netlist.h
|
|
@ -68,6 +68,7 @@ class NetTaskDef;
|
|||
class NetEvTrig;
|
||||
class NetEvWait;
|
||||
|
||||
class nature_t;
|
||||
|
||||
struct target;
|
||||
struct functor_t;
|
||||
|
|
@ -2873,6 +2874,26 @@ class NetEUFunc : public NetExpr {
|
|||
NetEUFunc& operator= (const NetEUFunc&);
|
||||
};
|
||||
|
||||
/*
|
||||
* A call to a nature access function for a branch.
|
||||
*/
|
||||
class NetEAccess : public NetExpr {
|
||||
|
||||
public:
|
||||
explicit NetEAccess(nature_t*nat);
|
||||
~NetEAccess();
|
||||
|
||||
virtual ivl_variable_type_t expr_type() const;
|
||||
virtual void dump(ostream&) const;
|
||||
|
||||
virtual void expr_scan(struct expr_scan_t*) const;
|
||||
virtual NetEAccess*dup_expr() const;
|
||||
virtual NexusSet* nex_input(bool rem_out = true);
|
||||
|
||||
private:
|
||||
nature_t*nature_;
|
||||
};
|
||||
|
||||
/*
|
||||
* A call to a user defined task is elaborated into this object. This
|
||||
* contains a pointer to the elaborated task definition, but is a
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
map<perm_string,nature_t*> natures;
|
||||
map<perm_string,discipline_t*> disciplines;
|
||||
map<perm_string,nature_t*> access_function_nature;
|
||||
|
||||
static perm_string nature_name = perm_string::perm_string();
|
||||
static perm_string nature_access = perm_string::perm_string();
|
||||
|
|
@ -62,9 +63,24 @@ void pform_end_nature(const struct vlltype&loc)
|
|||
}
|
||||
|
||||
nature_t*tmp = new nature_t(nature_name, nature_access);
|
||||
FILE_NAME(tmp, loc);
|
||||
|
||||
natures[nature_name] = tmp;
|
||||
|
||||
FILE_NAME(tmp, loc);
|
||||
// Make sure the access function is not used by multiple
|
||||
// different natures.
|
||||
if (nature_t*dup_access_nat = access_function_nature[nature_access]) {
|
||||
cerr << tmp->get_fileline() << ": error: "
|
||||
<< "Access function name " << nature_access
|
||||
<< " is already used by nature " << dup_access_nat->name()
|
||||
<< " declared at " << dup_access_nat->get_fileline()
|
||||
<< "." << endl;
|
||||
error_count += 1;
|
||||
}
|
||||
|
||||
// Map the access functio back to the nature so that
|
||||
// expressions that use the access function can find it.
|
||||
access_function_nature[nature_access] = tmp;
|
||||
|
||||
nature_name = perm_string::perm_string();
|
||||
nature_access = perm_string::perm_string();
|
||||
|
|
|
|||
|
|
@ -149,6 +149,15 @@ ivl_expr_t dll_target::expr_from_value_(const verinum&val)
|
|||
return expr;
|
||||
}
|
||||
|
||||
void dll_target::expr_access_func(const NetEAccess*net)
|
||||
{
|
||||
assert(expr_ == 0);
|
||||
|
||||
cerr << net->get_fileline() << ": internal error: "
|
||||
<< "Nature access functions not implemented yet." << endl;
|
||||
|
||||
}
|
||||
|
||||
void dll_target::expr_binary(const NetEBinary*net)
|
||||
{
|
||||
assert(expr_ == 0);
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
bool dll_target::process(const NetProcTop*net)
|
||||
{
|
||||
bool rc_flag = true;
|
||||
|
||||
ivl_process_t obj = (struct ivl_process_s*)
|
||||
calloc(1, sizeof(struct ivl_process_s));
|
||||
|
||||
|
|
@ -70,7 +72,7 @@ bool dll_target::process(const NetProcTop*net)
|
|||
assert(stmt_cur_ == 0);
|
||||
stmt_cur_ = (struct ivl_statement_s*)calloc(1, sizeof*stmt_cur_);
|
||||
assert(stmt_cur_);
|
||||
net->statement()->emit_proc(this);
|
||||
rc_flag = net->statement()->emit_proc(this) && rc_flag;
|
||||
|
||||
assert(stmt_cur_);
|
||||
obj->stmt_ = stmt_cur_;
|
||||
|
|
@ -80,7 +82,7 @@ bool dll_target::process(const NetProcTop*net)
|
|||
obj->next_ = des_.threads_;
|
||||
des_.threads_ = obj;
|
||||
|
||||
return true;
|
||||
return rc_flag;
|
||||
}
|
||||
|
||||
void dll_target::task_def(const NetScope*net)
|
||||
|
|
@ -190,7 +192,7 @@ void dll_target::make_assign_lvals_(const NetAssignBase*net)
|
|||
|
||||
/*
|
||||
*/
|
||||
void dll_target::proc_assign(const NetAssign*net)
|
||||
bool dll_target::proc_assign(const NetAssign*net)
|
||||
{
|
||||
assert(stmt_cur_);
|
||||
assert(stmt_cur_->type_ == IVL_ST_NONE);
|
||||
|
|
@ -214,6 +216,8 @@ void dll_target::proc_assign(const NetAssign*net)
|
|||
stmt_cur_->u_.assign_.delay = expr_;
|
||||
expr_ = 0;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -399,6 +403,8 @@ bool dll_target::proc_cassign(const NetCAssign*net)
|
|||
|
||||
bool dll_target::proc_condit(const NetCondit*net)
|
||||
{
|
||||
bool rc_flag = true;
|
||||
|
||||
assert(stmt_cur_);
|
||||
assert(stmt_cur_->type_ == IVL_ST_NONE);
|
||||
FILE_NAME(stmt_cur_, net);
|
||||
|
|
@ -410,18 +416,20 @@ bool dll_target::proc_condit(const NetCondit*net)
|
|||
assert(expr_ == 0);
|
||||
net->expr()->expr_scan(this);
|
||||
stmt_cur_->u_.condit_.cond_ = expr_;
|
||||
if (expr_ == 0)
|
||||
rc_flag = false;
|
||||
expr_ = 0;
|
||||
|
||||
ivl_statement_t save_cur_ = stmt_cur_;
|
||||
|
||||
stmt_cur_ = save_cur_->u_.condit_.stmt_+0;
|
||||
bool flag = net->emit_recurse_if(this);
|
||||
rc_flag = net->emit_recurse_if(this) && rc_flag;
|
||||
|
||||
stmt_cur_ = save_cur_->u_.condit_.stmt_+1;
|
||||
flag = flag && net->emit_recurse_else(this);
|
||||
rc_flag = net->emit_recurse_else(this) && rc_flag;
|
||||
|
||||
stmt_cur_ = save_cur_;
|
||||
return flag;
|
||||
return rc_flag;
|
||||
}
|
||||
|
||||
bool dll_target::proc_deassign(const NetDeassign*net)
|
||||
|
|
|
|||
3
t-dll.h
3
t-dll.h
|
|
@ -111,7 +111,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
|||
/* These methods and members are used for forming the
|
||||
statements of a thread. */
|
||||
struct ivl_statement_s*stmt_cur_;
|
||||
void proc_assign(const NetAssign*);
|
||||
bool proc_assign(const NetAssign*);
|
||||
void proc_assign_nb(const NetAssignNB*);
|
||||
bool proc_block(const NetBlock*);
|
||||
void proc_case(const NetCase*);
|
||||
|
|
@ -134,6 +134,7 @@ struct dll_target : public target_t, public expr_scan_t {
|
|||
void task_def(const NetScope*);
|
||||
|
||||
struct ivl_expr_s*expr_;
|
||||
void expr_access_func(const NetEAccess*);
|
||||
void expr_binary(const NetEBinary*);
|
||||
void expr_concat(const NetEConcat*);
|
||||
void expr_const(const NetEConst*);
|
||||
|
|
|
|||
|
|
@ -243,10 +243,11 @@ bool target_t::process(const NetProcTop*top)
|
|||
return top->statement()->emit_proc(this);
|
||||
}
|
||||
|
||||
void target_t::proc_assign(const NetAssign*)
|
||||
bool target_t::proc_assign(const NetAssign*)
|
||||
{
|
||||
cerr << "target (" << typeid(*this).name() << "): "
|
||||
"Unhandled procedural assignment." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
void target_t::proc_assign_nb(const NetAssignNB*)
|
||||
|
|
@ -377,6 +378,12 @@ expr_scan_t::~expr_scan_t()
|
|||
{
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_access_func(const NetEAccess*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
"unhandled expr_access_func." << endl;
|
||||
}
|
||||
|
||||
void expr_scan_t::expr_const(const NetEConst*)
|
||||
{
|
||||
cerr << "expr_scan_t (" << typeid(*this).name() << "): "
|
||||
|
|
|
|||
3
target.h
3
target.h
|
|
@ -105,7 +105,7 @@ struct target_t {
|
|||
virtual bool process(const NetProcTop*);
|
||||
|
||||
/* Various kinds of process nodes are dispatched through these. */
|
||||
virtual void proc_assign(const NetAssign*);
|
||||
virtual bool proc_assign(const NetAssign*);
|
||||
virtual void proc_assign_nb(const NetAssignNB*);
|
||||
virtual bool proc_block(const NetBlock*);
|
||||
virtual void proc_case(const NetCase*);
|
||||
|
|
@ -133,6 +133,7 @@ struct target_t {
|
|||
of expressions. */
|
||||
struct expr_scan_t {
|
||||
virtual ~expr_scan_t();
|
||||
virtual void expr_access_func(const NetEAccess*);
|
||||
virtual void expr_const(const NetEConst*);
|
||||
virtual void expr_param(const NetEConstParam*);
|
||||
virtual void expr_rparam(const NetECRealParam*);
|
||||
|
|
|
|||
|
|
@ -49,10 +49,23 @@ static void show_binary_expression(ivl_expr_t net, unsigned ind)
|
|||
const char*sign = ivl_expr_signed(net)? "signed" : "unsigned";
|
||||
const char*vt = vt_type_string(net);
|
||||
|
||||
ivl_expr_t oper1 = ivl_expr_oper1(net);
|
||||
ivl_expr_t oper2 = ivl_expr_oper2(net);
|
||||
|
||||
fprintf(out, "%*s<\"%c\" width=%u, %s, type=%s>\n", ind, "",
|
||||
ivl_expr_opcode(net), width, sign, vt);
|
||||
show_expression(ivl_expr_oper1(net), ind+3);
|
||||
show_expression(ivl_expr_oper2(net), ind+3);
|
||||
if (oper1) {
|
||||
show_expression(oper1, ind+3);
|
||||
} else {
|
||||
fprintf(out, "%*sERROR: Missing operand 1\n", ind+3, "");
|
||||
stub_errors += 1;
|
||||
}
|
||||
if (oper2) {
|
||||
show_expression(oper2, ind+3);
|
||||
} else {
|
||||
fprintf(out, "%*sERROR: Missing operand 2\n", ind+3, "");
|
||||
stub_errors += 1;
|
||||
}
|
||||
|
||||
switch (ivl_expr_opcode(net)) {
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue