From cc7187c1725ea09855e3a9002e7b32f8f4424576 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 4 May 2008 22:00:01 -0700 Subject: [PATCH 1/4] Add support for abs() in logic threads. Add the code generator code to handle the abs() function in signed logic. Handle some of the interesting special cases as well. --- tgt-stub/expression.c | 26 +++++++++++++++++++++++--- tgt-vvp/eval_expr.c | 26 ++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 3 deletions(-) diff --git a/tgt-stub/expression.c b/tgt-stub/expression.c index 2de7b787e..fe197c30a 100644 --- a/tgt-stub/expression.c +++ b/tgt-stub/expression.c @@ -160,6 +160,28 @@ static void show_ternary_expression(ivl_expr_t net, unsigned ind) } } +void show_unary_expression(ivl_expr_t net, unsigned ind) +{ + unsigned width = ivl_expr_width(net); + const char*sign = ivl_expr_signed(net)? "signed" : "unsigned"; + const char*vt = vt_type_string(net); + + char name[8]; + switch (ivl_expr_opcode(net)) { + default: + snprintf(name, sizeof name, "%c", ivl_expr_opcode(net)); + break; + + case 'm': + snprintf(name, sizeof name, "abs()"); + break; + } + + fprintf(out, "%*s\n", ind, "", + name, width, sign, vt); + show_expression(ivl_expr_oper1(net), ind+4); +} + void show_expression(ivl_expr_t net, unsigned ind) { unsigned idx; @@ -252,9 +274,7 @@ void show_expression(ivl_expr_t net, unsigned ind) break; case IVL_EX_UNARY: - fprintf(out, "%*s\n", ind, "", - ivl_expr_opcode(net), width, sign, vt); - show_expression(ivl_expr_oper1(net), ind+4); + show_unary_expression(net, ind); break; case IVL_EX_UFUNC: diff --git a/tgt-vvp/eval_expr.c b/tgt-vvp/eval_expr.c index 04848e572..bca49cc0a 100644 --- a/tgt-vvp/eval_expr.c +++ b/tgt-vvp/eval_expr.c @@ -2456,6 +2456,32 @@ static struct vector_info draw_unary_expr(ivl_expr_t exp, unsigned wid) } break; + case 'm': /* abs() */ + res = draw_eval_expr_wid(sub, wid, 0); + + if (!ivl_expr_signed(sub)) + break; + + if (res.base == 0 || res.base == 2 || res.base == 3) + break; + + /* Handle the special case of a -1 constant. Make the + result a 1. */ + if (res.base == 1) { + res.base = allocate_vector(wid); + fprintf(vvp_out, " %%movi %d, 1, %u;\n", + res.base, res.wid); + break; + } + + fprintf(vvp_out, " %%cmpi/s %d, 0, %u;\n", res.base, res.wid); + fprintf(vvp_out, " %%jmp/0xz T_%u.%u, 5;\n", thread_count, local_count); + fprintf(vvp_out, " %%inv %d, %u;\n", res.base, res.wid); + fprintf(vvp_out, " %%addi %d, 1, %u;\n", res.base, res.wid); + fprintf(vvp_out, "T_%u.%u ;\n", thread_count, local_count); + local_count += 1; + break; + default: fprintf(stderr, "vvp error: unhandled unary: %c\n", ivl_expr_opcode(exp)); From a43f336c6cf398541c418bf4e9fc6e793f7ea44f Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Sun, 4 May 2008 22:10:54 -0700 Subject: [PATCH 2/4] Include va_math if compiling Verilog-AMS The va_math module implements functions that are optional in base Verilog but included in Verilog-AMS. So automatically include the module if -gverilog-ams is given. --- driver/main.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/driver/main.c b/driver/main.c index 32a40cf27..953262012 100644 --- a/driver/main.c +++ b/driver/main.c @@ -734,6 +734,13 @@ int main(int argc, char **argv) how to handle them. */ fprintf(iconfig_file, "sys_func:%s%csystem.sft\n", base, sep); + /* If verilog-ams is enabled, then include the va_math module + as well. */ + if (strcmp(gen_verilog_ams,"verilog-ams") == 0) { + fprintf(iconfig_file, "sys_func:%s%cva_math.sft\n", base, sep); + fprintf(iconfig_file, "module:va_math\n"); + } + if (mtm != 0) fprintf(iconfig_file, "-T:%s\n", mtm); fprintf(iconfig_file, "generation:%s\n", generation); fprintf(iconfig_file, "generation:%s\n", gen_specify); From e91243e1c601232ab26d104109896089dfea610b Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Mon, 5 May 2008 22:00:39 -0700 Subject: [PATCH 3/4] Elaborate abs() is continuous assign expressions. In continuous assign expressions, the abs() operator can't easily be burried in generic unary handling, so add the IVL_LPM_ABS type and generate it as needed. --- design_dump.cc | 9 +++++++++ elab_net.cc | 28 +++++++++++++++++++++++++++- emit.cc | 6 ++++++ functor.cc | 9 +++++++++ functor.h | 3 +++ ivl_target.h | 1 + netlist.cc | 18 ++++++++++++++++++ netlist.h | 21 +++++++++++++++++++++ t-dll-api.cc | 6 ++++++ t-dll.cc | 32 ++++++++++++++++++++++++++++++++ t-dll.h | 1 + target.cc | 6 ++++++ target.h | 1 + tgt-stub/stub.c | 30 ++++++++++++++++++++++++++++++ 14 files changed, 170 insertions(+), 1 deletion(-) diff --git a/design_dump.cc b/design_dump.cc index 12c4a6e5a..82eb6919f 100644 --- a/design_dump.cc +++ b/design_dump.cc @@ -247,6 +247,15 @@ void NetObj::dump_obj_attr(ostream&o, unsigned ind) const } } +void NetAbs::dump_node(ostream&o, unsigned ind) const +{ + o << setw(ind) << "" << "Absolute value (NetAbs): " << name() + << " width=" << width() << " pin_count=" << pin_count() + << endl; + dump_node_pins(o, ind+4); + dump_obj_attr(o, ind+4); +} + void NetAddSub::dump_node(ostream&o, unsigned ind) const { o << setw(ind) << "" << "Adder (NetAddSub): " << name() diff --git a/elab_net.cc b/elab_net.cc index c1b628e5c..d3c542b16 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -3212,6 +3212,32 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope, connect(gate->pin(0), sig->pin(0)); break; + case 'm': // abs(sub_sig) + // If this expression is self determined, get its width + // from the sub_expression. + if (owidth == 0) + owidth = sub_sig->vector_width(); + + if (sub_sig->vector_width() < owidth) + sub_sig = pad_to_width(des, sub_sig, owidth); + + sig = new NetNet(scope, scope->local_symbol(), + NetNet::WIRE, owidth); + sig->set_line(*this); + sig->data_type(sub_sig->data_type()); + sig->local_flag(true); + + NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), sub_sig->vector_width()); + tmp->set_line(*this); + des->add_node(tmp); + tmp->rise_time(rise); + tmp->fall_time(fall); + tmp->decay_time(decay); + + connect(tmp->pin(1), sub_sig->pin(0)); + connect(tmp->pin(0), sig->pin(0)); + break; + case 'N': // Reduction NOR case '!': // Reduction NOT reduction=true; rtype = NetUReduce::NOR; break; @@ -3290,7 +3316,7 @@ NetNet* PEUnary::elaborate_net(Design*des, NetScope*scope, break; default: - cerr << "internal error: Unhandled UNARY '" << op_ << "'" << endl; + cerr << get_fileline() << ": internal error: Unhandled UNARY '" << op_ << "'" << endl; sig = 0; } diff --git a/emit.cc b/emit.cc index f94d0403b..c52190684 100644 --- a/emit.cc +++ b/emit.cc @@ -49,6 +49,12 @@ bool NetUDP::emit_node(struct target_t*tgt) const return true; } +bool NetAbs::emit_node(struct target_t*tgt) const +{ + tgt->lpm_abs(this); + return true; +} + bool NetAddSub::emit_node(struct target_t*tgt) const { tgt->lpm_add_sub(this); diff --git a/functor.cc b/functor.cc index f318ef80d..406d0ff9f 100644 --- a/functor.cc +++ b/functor.cc @@ -40,6 +40,10 @@ void functor_t::process(class Design*, class NetProcTop*) { } +void functor_t::lpm_abs(class Design*, class NetAbs*) +{ +} + void functor_t::lpm_add_sub(class Design*, class NetAddSub*) { } @@ -174,6 +178,11 @@ void NetNode::functor_node(Design*, functor_t*) { } +void NetAbs::functor_node(Design*des, functor_t*fun) +{ + fun->lpm_abs(des, this); +} + void NetAddSub::functor_node(Design*des, functor_t*fun) { fun->lpm_add_sub(des, this); diff --git a/functor.h b/functor.h index 31e204261..d3b9b5088 100644 --- a/functor.h +++ b/functor.h @@ -48,6 +48,9 @@ struct functor_t { /* This method is called for each process in the design. */ virtual void process(class Design*des, class NetProcTop*); + /* This method is called for each structural abs(). */ + virtual void lpm_abs(class Design*des, class NetAbs*); + /* This method is called for each structural adder. */ virtual void lpm_add_sub(class Design*des, class NetAddSub*); diff --git a/ivl_target.h b/ivl_target.h index 6beca4af4..bdd983a75 100644 --- a/ivl_target.h +++ b/ivl_target.h @@ -228,6 +228,7 @@ typedef enum ivl_logic_e { /* This is the type of an LPM object. */ typedef enum ivl_lpm_type_e { + IVL_LPM_ABS = 32, IVL_LPM_ADD = 0, IVL_LPM_ARRAY = 30, IVL_LPM_CONCAT = 16, diff --git a/netlist.cc b/netlist.cc index 4d7e8a9c8..45fee8f34 100644 --- a/netlist.cc +++ b/netlist.cc @@ -1046,6 +1046,24 @@ const verinum& NetFF::sset_value() const } +NetAbs::NetAbs(NetScope*s, perm_string n, unsigned w) +: NetNode(s, n, 2), width_(w) +{ + pin(0).set_dir(Link::OUTPUT); + pin(0).set_name(perm_string::literal("Result"), 0); + pin(1).set_dir(Link::INPUT); + pin(1).set_name(perm_string::literal("DataA"), 0); +} + +NetAbs::~NetAbs() +{ +} + +unsigned NetAbs::width() const +{ + return width_; +} + /* * The NetAddSub class represents an LPM_ADD_SUB device. The pinout is * assigned like so: diff --git a/netlist.h b/netlist.h index 891864b84..341947241 100644 --- a/netlist.h +++ b/netlist.h @@ -578,6 +578,27 @@ class NetNet : public NetObj { vector delay_paths_; }; +/* + * This class implements the LPM_ABS component. The node has a single + * input, a signe expression, that it converts to the absolute + * value. The gate is simple: pin(0) is the output and pin(1) is the input. + */ +class NetAbs : public NetNode { + + public: + NetAbs(NetScope*s, perm_string n, unsigned width); + ~NetAbs(); + + unsigned width() const; + + virtual void dump_node(ostream&, unsigned ind) const; + virtual bool emit_node(struct target_t*) const; + virtual void functor_node(Design*des, functor_t*fun); + + private: + unsigned width_; +}; + /* * This class implements the LPM_ADD_SUB component as described in the * EDIF LPM Version 2 1 0 standard. It is used as a structural diff --git a/t-dll-api.cc b/t-dll-api.cc index db8dd8b64..64b079ada 100644 --- a/t-dll-api.cc +++ b/t-dll-api.cc @@ -864,6 +864,10 @@ extern "C" ivl_nexus_t ivl_lpm_data(ivl_lpm_t net, unsigned idx) { assert(net); switch (net->type) { + case IVL_LPM_ABS: + assert(idx == 0); + return net->u_.arith.a; + case IVL_LPM_ADD: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: @@ -1002,6 +1006,7 @@ extern "C" ivl_nexus_t ivl_lpm_q(ivl_lpm_t net, unsigned idx) assert(net); switch (net->type) { + case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_DIVIDE: case IVL_LPM_MOD: @@ -1118,6 +1123,7 @@ extern "C" int ivl_lpm_signed(ivl_lpm_t net) case IVL_LPM_FF: case IVL_LPM_MUX: return 0; + case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_CMP_EEQ: case IVL_LPM_CMP_EQ: diff --git a/t-dll.cc b/t-dll.cc index edade0859..9dba1b907 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1303,6 +1303,38 @@ void dll_target::udp(const NetUDP*net) scope_add_logic(scope, obj); } +void dll_target::lpm_abs(const NetAbs*net) +{ + ivl_lpm_t obj = new struct ivl_lpm_s; + obj->type = IVL_LPM_ABS; + obj->name = net->name(); // NetAddSub names are permallocated. + assert(net->scope()); + obj->scope = find_scope(des_, net->scope()); + assert(obj->scope); + + obj->u_.arith.signed_flag = 0; + obj->width = net->width(); + + const Nexus*nex; + /* the output is pin(0) */ + nex = net->pin(0).nexus(); + assert(nex->t_cookie()); + + obj->u_.arith.q = nex->t_cookie(); + nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); + + nex = net->pin(0).nexus(); + assert(nex->t_cookie()); + + /* pin(1) is the input data. */ + obj->u_.arith.a = nex->t_cookie(); + nexus_lpm_add(obj->u_.arith.a, obj, 0, IVL_DR_HiZ, IVL_DR_HiZ); + + make_lpm_delays_(obj, net); + + scope_add_lpm(obj->scope, obj); +} + void dll_target::lpm_add_sub(const NetAddSub*net) { ivl_lpm_t obj = new struct ivl_lpm_s; diff --git a/t-dll.h b/t-dll.h index 9d7440ada..7e8e7e58b 100644 --- a/t-dll.h +++ b/t-dll.h @@ -70,6 +70,7 @@ struct dll_target : public target_t, public expr_scan_t { bool ureduce(const NetUReduce*); void net_case_cmp(const NetCaseCmp*); void udp(const NetUDP*); + void lpm_abs(const NetAbs*); void lpm_add_sub(const NetAddSub*); bool lpm_array_dq(const NetArrayDq*); void lpm_clshift(const NetCLShift*); diff --git a/target.cc b/target.cc index 9c1f88b95..379a91754 100644 --- a/target.cc +++ b/target.cc @@ -81,6 +81,12 @@ bool target_t::ureduce(const NetUReduce*) return false; } +void target_t::lpm_abs(const NetAbs*) +{ + cerr << "target (" << typeid(*this).name() << "): " + "Unhandled NetAbs." << endl; +} + void target_t::lpm_add_sub(const NetAddSub*) { cerr << "target (" << typeid(*this).name() << "): " diff --git a/target.h b/target.h index e6e1b8546..c68ffc2f0 100644 --- a/target.h +++ b/target.h @@ -68,6 +68,7 @@ struct target_t { virtual bool func_def(const NetScope*); /* LPM style components are handled here. */ + virtual void lpm_abs(const NetAbs*); virtual void lpm_add_sub(const NetAddSub*); virtual bool lpm_array_dq(const NetArrayDq*); virtual void lpm_clshift(const NetCLShift*); diff --git a/tgt-stub/stub.c b/tgt-stub/stub.c index 917b4b43d..7b455d171 100644 --- a/tgt-stub/stub.c +++ b/tgt-stub/stub.c @@ -175,6 +175,32 @@ static void show_lpm_arithmetic_pins(ivl_lpm_t net) fprintf(out, " DataB: %s\n", nex? ivl_nexus_name(nex) : ""); } +static void show_lpm_abs(ivl_lpm_t net) +{ + unsigned width = ivl_lpm_width(net); + + fprintf(out, " LPM_ABS %s: \n", + ivl_lpm_basename(net), width); + + ivl_nexus_t nex; + nex = ivl_lpm_q(net, 0); + fprintf(out, " Q: %s\n", ivl_nexus_name(ivl_lpm_q(net, 0))); + + nex = ivl_lpm_data(net, 0); + fprintf(out, " D: %s\n", nex? ivl_nexus_name(nex) : ""); + if (nex == 0) { + fprintf(out, " ERROR: missing input\n"); + stub_errors += 1; + return; + } + + if (width_of_nexus(nex) != width) { + fprintf(out, " ERROR: D width (%d) is wrong\n", + width_of_nexus(nex)); + stub_errors += 1; + } +} + static void show_lpm_add(ivl_lpm_t net) { unsigned width = ivl_lpm_width(net); @@ -796,6 +822,10 @@ static void show_lpm(ivl_lpm_t net) switch (ivl_lpm_type(net)) { + case IVL_LPM_ABS: + show_lpm_abs(net); + break; + case IVL_LPM_ADD: show_lpm_add(net); break; From 523de1b69c85334111d9e424159e400f3f7b3106 Mon Sep 17 00:00:00 2001 From: Stephen Williams Date: Tue, 6 May 2008 20:37:00 -0700 Subject: [PATCH 4/4] Handle the abs() function in net context. In net context we have to create a node that does the abs() function for us. Elaborate that node and handle it all the way down to vvp. --- elab_net.cc | 12 ++++++++++++ t-dll.cc | 2 +- tgt-vvp/vvp_scope.c | 16 ++++++++++++++++ vvp/arith.cc | 35 +++++++++++++++++++++++++++++++++++ vvp/arith.h | 11 +++++++++++ vvp/compile.cc | 15 +++++++++++++++ vvp/compile.h | 2 ++ vvp/lexor.lex | 1 + vvp/parse.y | 11 ++++++++++- 9 files changed, 103 insertions(+), 2 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index d3c542b16..1f0abdfba 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -3491,6 +3491,18 @@ NetNet* PEUnary::elab_net_unary_real_(Design*des, NetScope*scope, des->errors += 1; break; + case 'm': // abs() + NetAbs*tmp = new NetAbs(scope, scope->local_symbol(), 1); + tmp->set_line(*this); + tmp->rise_time(rise); + tmp->fall_time(fall); + tmp->decay_time(decay); + des->add_node(tmp); + + connect(tmp->pin(0), sig->pin(0)); + connect(tmp->pin(1), sub_sig->pin(0)); + break; + case '-': NetAddSub*sub = new NetAddSub(scope, scope->local_symbol(), 1); sub->attribute(perm_string::literal("LPM_Direction"), diff --git a/t-dll.cc b/t-dll.cc index 9dba1b907..91db2dac5 100644 --- a/t-dll.cc +++ b/t-dll.cc @@ -1323,7 +1323,7 @@ void dll_target::lpm_abs(const NetAbs*net) obj->u_.arith.q = nex->t_cookie(); nexus_lpm_add(obj->u_.arith.q, obj, 0, IVL_DR_STRONG, IVL_DR_STRONG); - nex = net->pin(0).nexus(); + nex = net->pin(1).nexus(); assert(nex->t_cookie()); /* pin(1) is the input data. */ diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 2f8e98f24..066da1b12 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -679,6 +679,7 @@ static char* draw_net_input_drive(ivl_nexus_t nex, ivl_nexus_ptr_t nptr) if (lpm) switch (ivl_lpm_type(lpm)) { case IVL_LPM_FF: + case IVL_LPM_ABS: case IVL_LPM_ADD: case IVL_LPM_ARRAY: case IVL_LPM_CONCAT: @@ -1693,6 +1694,17 @@ static const char* draw_lpm_output_delay(ivl_lpm_t net) return dly; } +static void draw_lpm_abs(ivl_lpm_t net) +{ + const char*src_table[1]; + draw_lpm_data_inputs(net, 0, 1, src_table); + + const char*dly = draw_lpm_output_delay(net); + + fprintf(vvp_out, "L_%p%s .abs %s;\n", + net, dly, src_table[0]); +} + static void draw_lpm_add(ivl_lpm_t net) { const char*src_table[2]; @@ -2338,6 +2350,10 @@ static void draw_lpm_in_scope(ivl_lpm_t net) { switch (ivl_lpm_type(net)) { + case IVL_LPM_ABS: + draw_lpm_abs(net); + return; + case IVL_LPM_ADD: case IVL_LPM_SUB: case IVL_LPM_MULT: diff --git a/vvp/arith.cc b/vvp/arith.cc index 0fd3041e4..c7b827bbc 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -55,6 +55,41 @@ void vvp_arith_::dispatch_operand_(vvp_net_ptr_t ptr, vvp_vector4_t bit) } +vvp_arith_abs::vvp_arith_abs() +{ +} + +vvp_arith_abs::~vvp_arith_abs() +{ +} + +void vvp_arith_abs::recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit) +{ + vvp_vector4_t out (bit.size(), BIT4_0);; + + vvp_bit4_t cmp = compare_gtge_signed(bit, out, BIT4_1); + switch (cmp) { + case BIT4_1: // bit >= 0 + out = bit; + break; + case BIT4_0: // bit < 0 + out = ~bit; + out += 1; + break; + default: // There's an X. + out = vvp_vector4_t(bit.size(), BIT4_X); + break; + } + + vvp_send_vec4(ptr.ptr()->out, out); +} + +void vvp_arith_abs::recv_real(vvp_net_ptr_t ptr, double bit) +{ + double out = fabs(bit); + vvp_send_real(ptr.ptr()->out, out); +} + // Division vvp_arith_div::vvp_arith_div(unsigned wid, bool signed_flag) diff --git a/vvp/arith.h b/vvp/arith.h index acc85b263..41ccf5371 100644 --- a/vvp/arith.h +++ b/vvp/arith.h @@ -49,6 +49,17 @@ class vvp_arith_ : public vvp_net_fun_t { vvp_vector4_t x_val_; }; +class vvp_arith_abs : public vvp_net_fun_t { + public: + explicit vvp_arith_abs(); + ~vvp_arith_abs(); + + void recv_vec4(vvp_net_ptr_t ptr, const vvp_vector4_t&bit); + void recv_real(vvp_net_ptr_t ptr, double bit); + + private: +}; + class vvp_arith_div : public vvp_arith_ { public: diff --git a/vvp/compile.cc b/vvp/compile.cc index a8f2dc033..0cb0a9426 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -941,6 +941,21 @@ template void make_arith(T_ *arith, char*label, free(argv); } +void compile_arith_abs(char*label, unsigned argc, struct symb_s*argv) +{ + vvp_arith_abs*arith = new vvp_arith_abs; + + vvp_net_t* ptr = new vvp_net_t; + ptr->fun = arith; + + define_functor_symbol(label, ptr); + free(label); + + assert(argc == 1); + inputs_connect(ptr, argc, argv); + free(argv); +} + void compile_arith_div(char*label, long wid, bool signed_flag, unsigned argc, struct symb_s*argv) { diff --git a/vvp/compile.h b/vvp/compile.h index b8e61a38b..21b863ee7 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -149,6 +149,8 @@ extern void compile_part_select_var(char*label, char*src, */ extern void compile_arith_pow(char*label, long width, bool signed_flag, unsigned argc, struct symb_s*argv); +extern void compile_arith_abs(char*label, + unsigned argc, struct symb_s*argv); extern void compile_arith_div(char*label, long width, bool signed_flag, unsigned argc, struct symb_s*argv); extern void compile_arith_mod(char*label, long width, diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 3c7222313..46032abc5 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -87,6 +87,7 @@ ".alias" { return K_ALIAS; } ".alias/real" { return K_ALIAS_R; } ".alias/s" { return K_ALIAS_S; } +".abs" { return K_ARITH_ABS; } ".arith/div" { return K_ARITH_DIV; } ".arith/div.r" { return K_ARITH_DIV_R; } ".arith/div.s" { return K_ARITH_DIV_S; } diff --git a/vvp/parse.y b/vvp/parse.y index c2521712d..5dd08a3ae 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -66,7 +66,8 @@ static struct __vpiModPath*modpath_dst = 0; }; %token K_ALIAS K_ALIAS_S K_ALIAS_R -%token K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD K_ARITH_MOD_R +%token K_ARITH_ABS K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD +%token K_ARITH_MOD_R %token K_ARITH_MULT K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R %token K_ARITH_SUM K_ARITH_SUM_R K_ARITH_POW K_ARITH_POW_R K_ARITH_POW_S %token K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT @@ -248,6 +249,14 @@ statement symbols ';' { compile_concat($1, $4, $5, $6, $7, $10.cnt, $10.vect); } + /* The ABS statement is a special arithmetic node that takes 1 + input. Re-use the symbols rule. */ + + | T_LABEL K_ARITH_ABS symbols ';' + { struct symbv_s obj = $3; + compile_arith_abs($1, obj.cnt, obj.vect); + } + /* Arithmetic statements generate functor arrays of a given width that take like size input vectors. */