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.
This commit is contained in:
parent
6d433364ac
commit
d60df2d75b
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
21
net_expr.cc
21
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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -2294,6 +2294,7 @@ NetEUnary::NetEUnary(char op, NetExpr*ex)
|
|||
switch (op_) {
|
||||
case '-':
|
||||
case '+':
|
||||
case 'm': // abs()
|
||||
cast_signed(ex->has_sign());
|
||||
break;
|
||||
default:
|
||||
|
|
|
|||
21
netlist.h
21
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 {
|
||||
|
||||
|
|
|
|||
28
parse.y
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 ')'
|
||||
|
|
|
|||
|
|
@ -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':
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue