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:
Stephen Williams 2008-07-30 18:01:41 -07:00
parent 25a27f9dd9
commit 9f04641fc7
16 changed files with 161 additions and 16 deletions

View File

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

View File

@ -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') {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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() << "): "

View File

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

View File

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