From 9f04641fc780e4856fc0faa8ec977970e1b70b88 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Wed, 30 Jul 2008 18:01:41 -0700 Subject: [PATCH] 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. --- PExpr.h | 1 + design_dump.cc | 7 +++++++ discipline.h | 2 ++ dup_expr.cc | 9 +++++++++ elab_expr.cc | 31 +++++++++++++++++++++++++++++-- emit.cc | 8 ++++++-- net_expr.cc | 14 ++++++++++++++ net_nex_input.cc | 5 +++++ netlist.h | 21 +++++++++++++++++++++ pform_disciplines.cc | 18 +++++++++++++++++- t-dll-expr.cc | 9 +++++++++ t-dll-proc.cc | 20 ++++++++++++++------ t-dll.h | 3 ++- target.cc | 9 ++++++++- target.h | 3 ++- tgt-stub/expression.c | 17 +++++++++++++++-- 16 files changed, 161 insertions(+), 16 deletions(-) diff --git a/PExpr.h b/PExpr.h index 7450e3e03..01ffa23e3 100644 --- a/PExpr.h +++ b/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, diff --git a/design_dump.cc b/design_dump.cc index ca8e71d8e..98378628f 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -27,6 +27,7 @@ # include # 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') { diff --git a/discipline.h b/discipline.h index 30932d49d..a79e538d2 100644 --- a/discipline.h +++ b/discipline.h @@ -71,5 +71,7 @@ class discipline_t : public LineInfo { extern map natures; extern map disciplines; + // Map access function name to the nature that it accesses. +extern map access_function_nature; #endif diff --git a/dup_expr.cc b/dup_expr.cc index 7a8ec8a76..96a721543 100644 --- a/dup_expr.cc +++ b/dup_expr.cc @@ -21,6 +21,15 @@ # include "netlist.h" # include +# 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 { diff --git a/elab_expr.cc b/elab_expr.cc index 6f8470dbf..9f3cc228b 100644 --- a/elab_expr.cc +++ b/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; diff --git a/emit.cc b/emit.cc index 4e2b652b6..785520a12 100644 --- a/emit.cc +++ b/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); diff --git a/net_expr.cc b/net_expr.cc index 92594ea3d..4d3818099 100644 --- a/net_expr.cc +++ b/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; +} diff --git a/net_nex_input.cc b/net_nex_input.cc index 2a68c2a8b..622621b05 100644 --- a/net_nex_input.cc +++ b/net_nex_input.cc @@ -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. */ diff --git a/netlist.h b/netlist.h index d6e01bab2..d3af7febd 100644 --- a/netlist.h +++ b/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 diff --git a/pform_disciplines.cc b/pform_disciplines.cc index 82f78708b..cca4cc0ac 100644 --- a/pform_disciplines.cc +++ b/pform_disciplines.cc @@ -25,6 +25,7 @@ map natures; map disciplines; +map 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(); diff --git a/t-dll-expr.cc b/t-dll-expr.cc index 958e5d0f2..51f9d4ea9 100644 --- a/t-dll-expr.cc +++ b/t-dll-expr.cc @@ -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); diff --git a/t-dll-proc.cc b/t-dll-proc.cc index 5d843e9d4..c75034e1e 100644 --- a/t-dll-proc.cc +++ b/t-dll-proc.cc @@ -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) diff --git a/t-dll.h b/t-dll.h index 5bc4c3fb4..98acadff7 100644 --- a/t-dll.h +++ b/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*); diff --git a/target.cc b/target.cc index 10e900027..fef82cedb 100644 --- a/target.cc +++ b/target.cc @@ -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() << "): " diff --git a/target.h b/target.h index 03fba0886..bed4815e6 100644 --- a/target.h +++ b/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*); diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 823d359a6..791b14b75 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -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)) {