From def9d0ea1d4d4d8441cce61bad22765806c837d1 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 29 May 2012 10:02:10 -0700 Subject: [PATCH] Basic infrastructure for compile-time function evaluation. --- Makefile.in | 3 +- eval_tree.cc | 8 ++- net_func_eval.cc | 133 +++++++++++++++++++++++++++++++++++++++++++++++ netlist.h | 30 +++++++++++ 4 files changed, 171 insertions(+), 3 deletions(-) create mode 100644 net_func_eval.cc diff --git a/Makefile.in b/Makefile.in index 57500f88e..bcebfa407 100644 --- a/Makefile.in +++ b/Makefile.in @@ -108,7 +108,8 @@ O = main.o async.o design_dump.o discipline.o dup_expr.o elaborate.o \ eval_tree.o expr_synth.o functor.o lexor.o lexor_keyword.o link_const.o \ load_module.o netlist.o netmisc.o nettypes.o net_analog.o net_assign.o \ net_design.o \ - netenum.o netstruct.o net_event.o net_expr.o net_func.o net_link.o net_modulo.o \ + netenum.o netstruct.o net_event.o net_expr.o net_func.o net_func_eval.o \ + net_link.o net_modulo.o \ net_nex_input.o net_nex_output.o net_proc.o net_scope.o net_tran.o \ net_udp.o pad_to_width.o parse.o parse_misc.o pform.o pform_analog.o \ pform_disciplines.o pform_dump.o pform_pclass.o pform_struct_type.o \ diff --git a/eval_tree.cc b/eval_tree.cc index bbce3cbc2..2db0f181c 100644 --- a/eval_tree.cc +++ b/eval_tree.cc @@ -1963,8 +1963,12 @@ NetExpr* NetEUFunc::eval_tree() } if (need_const_) { - cerr << get_fileline() << ": sorry: Constant user functions are " - "not yet supported." << endl; + NetFuncDef*def = func_->func_def(); + ivl_assert(*this, def); + + NetExpr*res = def->evaluate_function(*this, parms_); + return res; } + return 0; } diff --git a/net_func_eval.cc b/net_func_eval.cc new file mode 100644 index 000000000..662eca9bf --- /dev/null +++ b/net_func_eval.cc @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2012 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 + * General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +# include "netlist.h" +# include +# include "ivl_assert.h" + +using namespace std; + +NetExpr* NetFuncDef::evaluate_function(const LineInfo&loc, const std::vector&args) const +{ + // Make the context map; + map::iterator ptr; + mapcontext_map; + + // Put the return value into the map... + context_map[scope_->basename()] = 0; + // Load the input ports into the map... + ivl_assert(loc, ports_.size() == args.size()); + for (size_t idx = 0 ; idx < ports_.size() ; idx += 1) { + NetExpr*tmp = args[idx]->dup_expr(); + perm_string aname = ports_[idx]->name(); + context_map[aname] = tmp; + } + + // Perform the evaluation + bool flag = statement_->evaluate_function(loc, context_map); + + // Extract the result... + ptr = context_map.find(scope_->basename()); + NetExpr*res = ptr->second; + context_map.erase(ptr); + + + // Cleanup the rest of the context. + for (ptr = context_map.begin() ; ptr != context_map.end() ; ++ptr) { + delete ptr->second; + } + + // Done. + if (flag) + return res; + + delete res; + return 0; +} + +NetExpr* NetExpr::evaluate_function(const LineInfo&, + map&) const +{ + cerr << get_fileline() << ": sorry: I don't know how to evaluate this expression at compile time." << endl; + cerr << get_fileline() << ": : Expression type:" << typeid(*this).name() << endl; + + return 0; +} + +bool NetProc::evaluate_function(const LineInfo&, + map&) const +{ + cerr << get_fileline() << ": sorry: I don't know how to evaluate this statement at compile time." << endl; + cerr << get_fileline() << ": : Statement type:" << typeid(*this).name() << endl; + + return false; +} + +bool NetAssign::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + if (l_val_count() != 1) { + cerr << get_fileline() << ": sorry: I don't know how to evaluate " + "concatenated l-values here." << endl; + return false; + } + + const NetAssign_*lval = l_val(0); + + ivl_assert(loc, lval->word() == 0); + ivl_assert(loc, lval->get_base() == 0); + + NetExpr*rval_result = rval()->evaluate_function(loc, context_map); + if (rval_result == 0) + return false; + + map::iterator ptr = context_map.find(lval->name()); + if (ptr->second) + delete ptr->second; + ptr->second = rval_result; + + return true; +} + +/* + * Evaluating a NetBlock in a function is a simple matter of + * evaluating the statements in order. + */ +bool NetBlock::evaluate_function(const LineInfo&loc, + map&context_map) const +{ + bool flag = true; + NetProc*cur = last_; + do { + cur = cur->next_; + bool cur_flag = cur->evaluate_function(loc, context_map); + flag = flag && cur_flag; + } while (cur != last_); + + return flag; +} + + +NetExpr* NetEConst::evaluate_function(const LineInfo&, + map&) const +{ + NetEConst*res = new NetEConst(value_); + res->set_line(*this); + return res; +} diff --git a/netlist.h b/netlist.h index e1262a89a..e5eb200f8 100644 --- a/netlist.h +++ b/netlist.h @@ -28,6 +28,7 @@ # include # include # include +# include # include # include # include @@ -1715,6 +1716,14 @@ class NetExpr : public LineInfo { // any. This is a deep copy operation. virtual NetExpr*dup_expr() const =0; + // Evaluate the expression at compile time, a la within a + // constant function. This is used by the constant function + // evaluation function code, and the return value is an + // allocated constant, or nil if the expression cannot be + // evaluated for any reason. + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + // Get the Nexus that are the input to this // expression. Normally this descends down to the reference to // a signal that reads from its input. @@ -1776,6 +1785,9 @@ class NetEConst : public NetExpr { virtual NetNet*synthesize(Design*, NetScope*scope, NetExpr*); virtual NexusSet* nex_input(bool rem_out = true); + virtual NetExpr*evaluate_function(const LineInfo&loc, + std::map&ctx) const; + private: verinum value_; }; @@ -2244,6 +2256,15 @@ class NetProc : public virtual LineInfo { // target. The target returns true if OK, false for errors. virtual bool emit_proc(struct target_t*) const; + // This method is used by the NetFuncDef object to evaluate a + // constant function at compile time. The loc is the location + // of the function call, and is used for error messages. The + // ctx is a map of name to expression. This is for mapping + // identifiers to values. The function returns true if the + // processing succeeds, or false otherwise. + virtual bool evaluate_function(const LineInfo&loc, + std::map&ctx) const; + // This method is called by functors that want to scan a // process in search of matchable patterns. virtual int match_proc(struct proc_match_t*); @@ -2446,6 +2467,7 @@ class NetAssign : public NetAssignBase { virtual bool emit_proc(struct target_t*) const; virtual int match_proc(struct proc_match_t*); virtual void dump(ostream&, unsigned ind) const; + virtual bool evaluate_function(const LineInfo&loc, std::map&context_map) const; private: char op_; @@ -2495,6 +2517,8 @@ class NetBlock : public NetProc { const NetProc*proc_first() const; const NetProc*proc_next(const NetProc*cur) const; + bool evaluate_function(const LineInfo&loc, + std::map&ctx) const; // synthesize as asynchronous logic, and return true. bool synth_async(Design*des, NetScope*scope, @@ -2996,6 +3020,12 @@ class NetFuncDef { const NetNet*return_sig() const; + // When we want to evaluate the function during compile time, + // use this method to pass in the argument and get out a + // result. The result should be a constant. If the function + // cannot evaluate to a constant, this returns nil. + NetExpr* evaluate_function(const LineInfo&loc, const std::vector&args) const; + void dump(ostream&, unsigned ind) const; private: