From d60df2d75bc7362244647e0a0808d734ebe0a83d Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sat, 3 May 2008 21:54:42 -0700 Subject: [PATCH] Implement abs/min/max operators for real values. Implement in behavioral the abs/min/max operators for real values. The parser treats these builtin functions as operators, unary or binary, and elaborates them appropriately. Also add enough code generator support to handle real valued expressions in thread context. --- design_dump.cc | 17 +++++++++++++++++ elab_expr.cc | 6 ++++++ lexor_keyword.gperf | 3 +++ net_expr.cc | 21 +++++++++++++++++++++ netlist.cc | 1 + netlist.h | 21 +++++++++++++++++++++ parse.y | 28 +++++++++++++++++++++++++--- pform_dump.cc | 21 ++++++++++++++++++++- tgt-vvp/eval_real.c | 37 +++++++++++++++++++++++++++++++++++++ 9 files changed, 151 insertions(+), 4 deletions(-) diff --git a/design_dump.cc b/design_dump.cc index 074bbe25d..12c4a6e5a 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -1082,6 +1082,20 @@ void NetExpr::dump(ostream&o) const void NetEBinary::dump(ostream&o) const { + if (op_ == 'm' || op_ == 'M') { + if (op_ == 'm') + o << "min"; + else + o << "max"; + + o << "("; + left_->dump(o); + o << ", "; + right_->dump(o); + o << ")"; + return; + } + o << "("; left_->dump(o); o << ")"; @@ -1267,6 +1281,9 @@ void NetEUFunc::dump(ostream&o) const void NetEUnary::dump(ostream&o) const { switch (op_) { + case 'm': + o << "abs"; + break; case 'N': o << "~|"; break; diff --git a/elab_expr.cc b/elab_expr.cc index 564ace5fd..4a024df34 100644 --- a/elab_expr.cc +++ b/elab_expr.cc @@ -311,6 +311,12 @@ NetExpr* PEBinary::elaborate_expr_base_(Design*des, des->errors += 1; } break; + + case 'm': // min(l,r) + case 'M': // max(l,r) + tmp = new NetEBMinMax(op_, lp, rp); + tmp->set_line(*this); + break; } return tmp; diff --git a/lexor_keyword.gperf b/lexor_keyword.gperf index 7c641a1c9..554089607 100644 --- a/lexor_keyword.gperf +++ b/lexor_keyword.gperf @@ -11,6 +11,7 @@ %} struct lexor_keyword { const char*name; int mask; int tokenType; }; %% +abs, GN_KEYWORDS_VAMS_2_3, K_abs acos, GN_KEYWORDS_VAMS_2_3, K_acos acosh, GN_KEYWORDS_VAMS_2_3, K_acosh always, GN_KEYWORDS_1364_1995, K_always @@ -74,7 +75,9 @@ localparam, GN_KEYWORDS_1364_2001, K_localparam log, GN_KEYWORDS_VAMS_2_3, K_log logic, GN_KEYWORDS_ICARUS, K_logic macromodule, GN_KEYWORDS_1364_1995, K_macromodule +max, GN_KEYWORDS_VAMS_2_3, K_max medium, GN_KEYWORDS_1364_1995, K_medium +min, GN_KEYWORDS_VAMS_2_3, K_min module, GN_KEYWORDS_1364_1995, K_module nand, GN_KEYWORDS_1364_1995, K_nand negedge, GN_KEYWORDS_1364_1995, K_negedge diff --git a/net_expr.cc b/net_expr.cc index 8130c4cd6..2efb91f8f 100644 --- a/net_expr.cc +++ b/net_expr.cc @@ -219,6 +219,27 @@ ivl_variable_type_t NetEBDiv::expr_type() const return IVL_VT_LOGIC; } +NetEBMinMax::NetEBMinMax(char op, NetExpr*l, NetExpr*r) +: NetEBinary(op, l, r) +{ + expr_width( max(l->expr_width(), r->expr_width()) ); + cast_signed(l->has_sign() || r->has_sign()); +} + +NetEBMinMax::~NetEBMinMax() +{ +} + +ivl_variable_type_t NetEBMinMax::expr_type() const +{ + if (left_->expr_type() == IVL_VT_REAL) + return IVL_VT_REAL; + if (right_->expr_type() == IVL_VT_REAL) + return IVL_VT_REAL; + + return IVL_VT_LOGIC; +} + NetEBMult::NetEBMult(char op, NetExpr*l, NetExpr*r) : NetEBinary(op, l, r) { diff --git a/netlist.cc b/netlist.cc index 03b6be397..4d7e8a9c8 100644 --- a/netlist.cc +++ b/netlist.cc @@ -2294,6 +2294,7 @@ NetEUnary::NetEUnary(char op, NetExpr*ex) switch (op_) { case '-': case '+': + case 'm': // abs() cast_signed(ex->has_sign()); break; default: diff --git a/netlist.h b/netlist.h index 191c2b4b0..891864b84 100644 --- a/netlist.h +++ b/netlist.h @@ -2664,6 +2664,8 @@ class NetProcTop : public LineInfo, public Attrib { * r -- Right shift (>>) * R -- signed right shift (>>>) * X -- Bitwise exclusive NOR (~^) + * m -- min(a,b) + * M -- max(a,b) */ class NetEBinary : public NetExpr { @@ -2831,6 +2833,24 @@ class NetEBLogic : public NetEBinary { private: }; +/* + * Support the binary min(l,r) and max(l,r) operators. The opcodes + * supported are: + * + * m -- min + * M -- max + */ +class NetEBMinMax : public NetEBinary { + + public: + NetEBMinMax(char op, NetExpr*l, NetExpr*r); + ~NetEBMinMax(); + + virtual ivl_variable_type_t expr_type() const; + + private: + +}; /* * Support the binary multiplication (*) operator. @@ -3143,6 +3163,7 @@ class NetETernary : public NetExpr { * A -- Reduction NAND (~&) * N -- Reduction NOR (~|) * X -- Reduction NXOR (~^ or ^~) + * m -- abs(x) (i.e. "magnitude") */ class NetEUnary : public NetExpr { diff --git a/parse.y b/parse.y index b596dfbea..35a139fca 100644 --- a/parse.y +++ b/parse.y @@ -203,7 +203,7 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %token K_PO_POS K_PO_NEG K_POW %token K_PSTAR K_STARP %token K_LOR K_LAND K_NAND K_NOR K_NXOR K_TRIGGER -%token K_acos K_acosh K_asin K_asinh K_atan K_atanh K_atan2 +%token K_abs K_acos K_acosh K_asin K_asinh K_atan K_atanh K_atan2 %token K_always K_and K_assign K_begin K_bool K_buf K_bufif0 K_bufif1 K_case %token K_casex K_casez K_ceil K_cmos K_cos K_cosh %token K_deassign K_default K_defparam K_disable @@ -213,8 +213,8 @@ static PECallFunction*make_call_function(perm_string tn, PExpr*arg1, PExpr*arg2) %token K_for K_force K_forever K_fork K_function K_generate K_genvar %token K_highz0 K_highz1 K_hypot K_if K_ifnone %token K_initial K_inout K_input K_integer K_join K_large K_ln K_localparam -%token K_log K_logic K_macromodule -%token K_medium K_module K_nand K_negedge K_nmos K_nor K_not K_notif0 +%token K_log K_logic K_macromodule K_max +%token K_medium K_min K_module K_nand K_negedge K_nmos K_nor K_not K_notif0 %token K_notif1 K_or K_output K_parameter K_pmos K_posedge K_pow K_primitive %token K_pull0 K_pull1 K_pulldown K_pullup K_rcmos K_real K_realtime %token K_reg K_release K_repeat @@ -1254,6 +1254,28 @@ expr_primary $$ = tmp; } + /* These mathematical functions are conveniently expressed as unary + and binary expressions. They behave much like unary/binary + operators, even though they are parsed as functions. */ + + | K_abs '(' expression ')' + { PEUnary*tmp = new PEUnary('m', $3); + FILE_NAME(tmp,@1); + $$ = tmp; + } + + | K_max '(' expression ',' expression ')' + { PEBinary*tmp = new PEBinary('M', $3, $5); + FILE_NAME(tmp,@1); + $$ = tmp; + } + + | K_min '(' expression ',' expression ')' + { PEBinary*tmp = new PEBinary('m', $3, $5); + FILE_NAME(tmp,@1); + $$ = tmp; + } + /* Parenthesized expressions are primaries. */ | '(' expr_mintypmax ')' diff --git a/pform_dump.cc b/pform_dump.cc index fec687c26..d8efeab24 100644 --- a/pform_dump.cc +++ b/pform_dump.cc @@ -215,11 +215,30 @@ void PETernary::dump(ostream&out) const void PEUnary::dump(ostream&out) const { - out << op_ << "(" << *expr_ << ")"; + switch (op_) { + case 'm': + out << "abs"; + break; + default: + out << op_; + break; + } + out << "(" << *expr_ << ")"; } void PEBinary::dump(ostream&out) const { + /* Handle some special cases, where the operators are written + in function notation. */ + if (op_ == 'm') { + out << "min(" << *left_ << "," << *right_ << ")"; + return; + } + if (op_ == 'M') { + out << "min(" << *left_ << "," << *right_ << ")"; + return; + } + out << "(" << *left_ << ")"; switch (op_) { case 'a': diff --git a/tgt-vvp/eval_real.c b/tgt-vvp/eval_real.c index 768d60d0c..cb3fda4f6 100644 --- a/tgt-vvp/eval_real.c +++ b/tgt-vvp/eval_real.c @@ -112,6 +112,24 @@ static int draw_binary_real(ivl_expr_t exp) case 'p': fprintf(vvp_out, " %%pow/wr %d, %d;\n", l, r); break; + + case 'm': { // min(l,r) + int lab_out = local_count++; + fprintf(vvp_out, " %%cmp/wr %d, %d;\n", r, l); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out); + fprintf(vvp_out, " %%mov/wr %d, %d;\n", l, r); + fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); + break; + } + + case 'M': { // max(l,r) + int lab_out = local_count++; + fprintf(vvp_out, " %%cmp/wr %d, %d;\n", l, r); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", thread_count, lab_out); + fprintf(vvp_out, " %%mov/wr %d, %d;\n", l, r); + fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); + break; + } default: fprintf(stderr, "XXXX draw_binary_real(%c)\n", ivl_expr_opcode(exp)); @@ -420,6 +438,25 @@ static int draw_unary_real(ivl_expr_t exp) return res; } + if (ivl_expr_opcode(exp) == 'm') { /* abs(sube) */ + unsigned lab_positive = local_count++; + unsigned lab_out = local_count++; + int res = allocate_word(); + fprintf(vvp_out, " %%loadi/wr %d, 0, 0; load 0.0 -- %d = abs(%d)\n", + res, res, sub); + fprintf(vvp_out, " %%cmp/wr %d, %d;\n", sub, res); + fprintf(vvp_out, " %%jmp/0xz T_%d.%d, 5;\n", + thread_count, lab_positive); + fprintf(vvp_out, " %%sub/wr %d, %d;\n", res, sub); + fprintf(vvp_out, " %%jmp T_%d.%d;\n", thread_count, lab_out); + fprintf(vvp_out, "T_%d.%d %%mov/wr %d, %d;\n", + thread_count, lab_positive, res, sub); + fprintf(vvp_out, "T_%d.%d ;\n", thread_count, lab_out); + + clr_word(sub); + return res; + } + fprintf(vvp_out, "; XXXX unary (%c)\n", ivl_expr_opcode(exp)); fprintf(stderr, "XXXX evaluate unary (%c)\n", ivl_expr_opcode(exp)); return 0;