Permalink
Browse files

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.
  • Loading branch information...
1 parent 6d43336 commit d60df2d75bc7362244647e0a0808d734ebe0a83d @steveicarus committed May 4, 2008
Showing with 151 additions and 4 deletions.
  1. +17 −0 design_dump.cc
  2. +6 −0 elab_expr.cc
  3. +3 −0 lexor_keyword.gperf
  4. +21 −0 net_expr.cc
  5. +1 −0 netlist.cc
  6. +21 −0 netlist.h
  7. +25 −3 parse.y
  8. +20 −1 pform_dump.cc
  9. +37 −0 tgt-vvp/eval_real.c
View
@@ -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;
View
@@ -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;
View
@@ -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
View
@@ -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)
{
View
@@ -2294,6 +2294,7 @@ NetEUnary::NetEUnary(char op, NetExpr*ex)
switch (op_) {
case '-':
case '+':
+ case 'm': // abs()
cast_signed(ex->has_sign());
break;
default:
View
@@ -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 {
View
28 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 ')'
View
@@ -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':
View
@@ -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;

0 comments on commit d60df2d

Please sign in to comment.