From f049426f259ef276f332a9091a46e8fe481a751e Mon Sep 17 00:00:00 2001 From: Cary R Date: Wed, 30 Jan 2008 18:32:27 -0800 Subject: [PATCH] Add support for real % in a continuous assignment. This patch adds conditional support (2001X) for the real modulus operator in a continuous assignment. --- elab_net.cc | 22 +++++++++++++++------- tgt-vvp/vvp_scope.c | 2 +- vvp/arith.cc | 17 +++++++++++++++++ vvp/arith.h | 8 ++++++++ vvp/compile.cc | 12 ++++++++++++ vvp/compile.h | 1 + vvp/lexor.lex | 1 + vvp/parse.y | 12 +++++++++--- 8 files changed, 64 insertions(+), 11 deletions(-) diff --git a/elab_net.cc b/elab_net.cc index 62667d493..1d32cb056 100644 --- a/elab_net.cc +++ b/elab_net.cc @@ -828,20 +828,28 @@ NetNet* PEBinary::elaborate_net_mod_(Design*des, NetScope*scope, des->errors += 1; } - if (lsig->data_type() == IVL_VT_REAL) { - cerr << get_fileline() << ": error: The modulus operator " - "is not supported for real values." << endl; + /* The % operator does not support real arguments in baseline + Verilog. But we allow it in our extended form of Verilog. */ + if (generation_flag < GN_VER2001X && lsig->data_type() == IVL_VT_REAL) { + cerr << get_fileline() << ": error: Modulus operator may not " + "have REAL operands." << endl; des->errors += 1; } /* rwidth is result width. */ unsigned rwidth = lwidth; if (rwidth == 0) { - rwidth = lsig->vector_width(); - if (rsig->vector_width() > rwidth) - rwidth = rsig->vector_width(); + /* Reals are always 1 wide and lsig/rsig types match here. */ + if (lsig->data_type() == IVL_VT_REAL) { + lwidth = 1; + rwidth = 1; + } else { + rwidth = lsig->vector_width(); + if (rsig->vector_width() > rwidth) + rwidth = rsig->vector_width(); - lwidth = rwidth; + lwidth = rwidth; + } } NetModulo*mod = new NetModulo(scope, scope->local_symbol(), rwidth, diff --git a/tgt-vvp/vvp_scope.c b/tgt-vvp/vvp_scope.c index 2d8d113b1..c064b365f 100644 --- a/tgt-vvp/vvp_scope.c +++ b/tgt-vvp/vvp_scope.c @@ -1701,7 +1701,7 @@ static void draw_lpm_add(ivl_lpm_t net) break; case IVL_LPM_MOD: if (dto == IVL_VT_REAL) - assert(0); /* Not supported for reals, */ + type = "mod.r"; else type = "mod"; break; diff --git a/vvp/arith.cc b/vvp/arith.cc index a12b0d4be..27d94720f 100644 --- a/vvp/arith.cc +++ b/vvp/arith.cc @@ -805,6 +805,23 @@ void vvp_arith_div_real::recv_real(vvp_net_ptr_t ptr, double bit) vvp_send_real(ptr.ptr()->out, val); } +/* Real modulus. */ +vvp_arith_mod_real::vvp_arith_mod_real() +{ +} + +vvp_arith_mod_real::~vvp_arith_mod_real() +{ +} + +void vvp_arith_mod_real::recv_real(vvp_net_ptr_t ptr, double bit) +{ + dispatch_operand_(ptr, bit); + + double val = fmod(op_a_, op_b_); + vvp_send_real(ptr.ptr()->out, val); +} + /* Real summation. */ vvp_arith_sum_real::vvp_arith_sum_real() { diff --git a/vvp/arith.h b/vvp/arith.h index 82b3596ea..4579a923d 100644 --- a/vvp/arith.h +++ b/vvp/arith.h @@ -231,6 +231,14 @@ class vvp_arith_div_real : public vvp_arith_real_ { void recv_real(vvp_net_ptr_t ptr, double bit); }; +class vvp_arith_mod_real : public vvp_arith_real_ { + + public: + explicit vvp_arith_mod_real(); + ~vvp_arith_mod_real(); + void recv_real(vvp_net_ptr_t ptr, double bit); +}; + class vvp_arith_mult_real : public vvp_arith_real_ { public: diff --git a/vvp/compile.cc b/vvp/compile.cc index 4ebef8da0..33cc27641 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -956,6 +956,18 @@ void compile_arith_mod(char*label, long wid, make_arith(arith, label, argc, argv); } +void compile_arith_mod_r(char*label, unsigned argc, struct symb_s*argv) +{ + if (argc != 2) { + fprintf(stderr, "%s .arith/mod.r has wrong number of symbols\n", label); + compile_errors += 1; + return; + } + + vvp_arith_real_ *arith = new vvp_arith_mod_real; + make_arith(arith, label, argc, argv); +} + void compile_arith_mult(char*label, long wid, unsigned argc, struct symb_s*argv) { diff --git a/vvp/compile.h b/vvp/compile.h index b6a120446..44e82e4a7 100644 --- a/vvp/compile.h +++ b/vvp/compile.h @@ -173,6 +173,7 @@ extern void compile_arith_mult_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_arith_pow_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_arith_div_r(char*label, unsigned argc, struct symb_s*argv); +extern void compile_arith_mod_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_arith_sum_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_arith_sub_r(char*label, unsigned argc, struct symb_s*argv); extern void compile_cmp_eq_r(char*label, unsigned argc, struct symb_s*argv); diff --git a/vvp/lexor.lex b/vvp/lexor.lex index 9364ab094..9af366a34 100644 --- a/vvp/lexor.lex +++ b/vvp/lexor.lex @@ -91,6 +91,7 @@ ".arith/div.r" { return K_ARITH_DIV_R; } ".arith/div.s" { return K_ARITH_DIV_S; } ".arith/mod" { return K_ARITH_MOD; } +".arith/mod.r" { return K_ARITH_MOD_R; } ".arith/mult" { return K_ARITH_MULT; } ".arith/mult.r" { return K_ARITH_MULT_R; } ".arith/pow.r" { return K_ARITH_POW_R; } diff --git a/vvp/parse.y b/vvp/parse.y index 292d05444..6cdb62549 100644 --- a/vvp/parse.y +++ b/vvp/parse.y @@ -66,9 +66,10 @@ 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_MULT -%token K_ARITH_MULT_R K_ARITH_SUB K_ARITH_SUB_R K_ARITH_SUM K_ARITH_SUM_R -%token K_ARITH_POW_R K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT +%token K_ARITH_DIV K_ARITH_DIV_R K_ARITH_DIV_S K_ARITH_MOD 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_R +%token K_ARRAY K_ARRAY_I K_ARRAY_R K_ARRAY_S K_ARRAY_PORT %token K_CMP_EEQ K_CMP_EQ K_CMP_EQ_R K_CMP_NEE K_CMP_NE K_CMP_NE_R %token K_CMP_GE K_CMP_GE_R K_CMP_GE_S K_CMP_GT K_CMP_GT_R K_CMP_GT_S %token K_CONCAT K_DEBUG K_DELAY K_DFF @@ -270,6 +271,11 @@ statement compile_arith_mod($1, $3, obj.cnt, obj.vect); } + | T_LABEL K_ARITH_MOD_R T_NUMBER ',' symbols ';' + { struct symbv_s obj = $5; + compile_arith_mod_r($1, obj.cnt, obj.vect); + } + | T_LABEL K_ARITH_MULT T_NUMBER ',' symbols ';' { struct symbv_s obj = $5; compile_arith_mult($1, $3, obj.cnt, obj.vect);