diff --git a/vvp/codes.h b/vvp/codes.h index 10f74ec53..3b4d44d6a 100644 --- a/vvp/codes.h +++ b/vvp/codes.h @@ -19,7 +19,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: codes.h,v 1.65 2004/05/19 03:26:24 steve Exp $" +#ident "$Id: codes.h,v 1.66 2004/06/19 15:52:53 steve Exp $" #endif @@ -86,6 +86,7 @@ extern bool of_LOAD_WR(vthread_t thr, vvp_code_t code); extern bool of_LOAD_X(vthread_t thr, vvp_code_t code); extern bool of_LOADI_WR(vthread_t thr, vvp_code_t code); extern bool of_MOD(vthread_t thr, vvp_code_t code); +extern bool of_MOD_S(vthread_t thr, vvp_code_t code); extern bool of_MOV(vthread_t thr, vvp_code_t code); extern bool of_MUL(vthread_t thr, vvp_code_t code); extern bool of_MUL_WR(vthread_t thr, vvp_code_t code); @@ -169,6 +170,9 @@ extern vvp_code_t codespace_null(void); /* * $Log: codes.h,v $ + * Revision 1.66 2004/06/19 15:52:53 steve + * Add signed modulus operator. + * * Revision 1.65 2004/05/19 03:26:24 steve * Support delayed/non-blocking assignment to reals and others. * diff --git a/vvp/compile.cc b/vvp/compile.cc index 3c17ea71c..ef13dab83 100644 --- a/vvp/compile.cc +++ b/vvp/compile.cc @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: compile.cc,v 1.172 2004/06/16 16:33:26 steve Exp $" +#ident "$Id: compile.cc,v 1.173 2004/06/19 15:52:53 steve Exp $" #endif # include "arith.h" @@ -133,6 +133,7 @@ const static struct opcode_table_s opcode_table[] = { { "%load/x", of_LOAD_X, 3, {OA_BIT1, OA_FUNC_PTR, OA_BIT2} }, { "%loadi/wr",of_LOADI_WR,3,{OA_BIT1, OA_NUMBER, OA_BIT2} }, { "%mod", of_MOD, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, + { "%mod/s", of_MOD_S, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%mov", of_MOV, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%mul", of_MUL, 3, {OA_BIT1, OA_BIT2, OA_NUMBER} }, { "%mul/wr", of_MUL_WR, 2, {OA_BIT1, OA_BIT2, OA_NONE} }, @@ -1578,6 +1579,9 @@ void compile_param_string(char*label, char*name, char*str, char*value) /* * $Log: compile.cc,v $ + * Revision 1.173 2004/06/19 15:52:53 steve + * Add signed modulus operator. + * * Revision 1.172 2004/06/16 16:33:26 steve * Add structural equality compare nodes. * diff --git a/vvp/opcodes.txt b/vvp/opcodes.txt index 38ef8a385..3896a0551 100644 --- a/vvp/opcodes.txt +++ b/vvp/opcodes.txt @@ -1,7 +1,7 @@ /* * Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com) * - * $Id: opcodes.txt,v 1.54 2004/05/19 03:26:24 steve Exp $ + * $Id: opcodes.txt,v 1.55 2004/06/19 15:52:53 steve Exp $ */ @@ -387,13 +387,15 @@ value. The sign bit is OR-ed into the value at bit 0x2000, and is removed from the before calculating the real value. -* %mod , , +* %mod , , +* %mod/s , , This instruction calculates the modulus %r of the left operand, and replaces the left operand with the result. The gives the width of the left and the right vectors, and the left vector is completely replaced with the result. +The /s form does signed %. * %mov , , diff --git a/vvp/vthread.cc b/vvp/vthread.cc index 007347107..4647fdd1e 100644 --- a/vvp/vthread.cc +++ b/vvp/vthread.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2001-2003 Stephen Williams (steve@icarus.com) + * Copyright (c) 2001-2004 Stephen Williams (steve@icarus.com) * * This source code is free software; you can redistribute it * and/or modify it in source code form under the terms of the GNU @@ -17,7 +17,7 @@ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ #ifdef HAVE_CVS_IDENT -#ident "$Id: vthread.cc,v 1.119 2004/06/04 23:26:34 steve Exp $" +#ident "$Id: vthread.cc,v 1.120 2004/06/19 15:52:53 steve Exp $" #endif # include "config.h" @@ -1652,70 +1652,49 @@ bool of_LOADI_WR(vthread_t thr, vvp_code_t cp) return true; } -bool of_MOD(vthread_t thr, vvp_code_t cp) +static void do_verylong_mod(vthread_t thr, vvp_code_t cp, + bool left_is_neg, bool right_is_neg) { - assert(cp->bit_idx[0] >= 4); + bool out_is_neg = left_is_neg != right_is_neg; + int len=cp->number; + unsigned char *a, *z, *t; + a = new unsigned char[len+1]; + z = new unsigned char[len+1]; + t = new unsigned char[len+1]; -if(cp->number <= 8*sizeof(unsigned long)) { - unsigned idx1 = cp->bit_idx[0]; - unsigned idx2 = cp->bit_idx[1]; - unsigned long lv = 0, rv = 0; + unsigned char carry; + unsigned char temp; - for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { - unsigned lb = thr_get_bit(thr, idx1); - unsigned rb = thr_get_bit(thr, idx2); - - if ((lb | rb) & 2) - goto x_out; - - lv |= lb << idx; - rv |= rb << idx; - - idx1 += 1; - if (idx2 >= 4) - idx2 += 1; - } - - if (rv == 0) - goto x_out; - - lv %= rv; - - for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { - thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1) ? 1 : 0); - lv >>= 1; - } - - return true; - -} else { - - int len=cp->number; - unsigned char *a, *z, *t; - a = new unsigned char[len+1]; - z = new unsigned char[len+1]; - t = new unsigned char[len+1]; - - unsigned char carry; - unsigned char temp; - - int mxa = -1, mxz = -1; - int i; - int current, copylen; + int mxa = -1, mxz = -1; + int i; + int current, copylen; unsigned idx1 = cp->bit_idx[0]; unsigned idx2 = cp->bit_idx[1]; + unsigned lb_carry = left_is_neg? 1 : 0; + unsigned rb_carry = right_is_neg? 1 : 0; for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { unsigned lb = thr_get_bit(thr, idx1); unsigned rb = thr_get_bit(thr, idx2); if ((lb | rb) & 2) { - delete []t; - delete []z; - delete []a; - goto x_out; - } + delete []t; + delete []z; + delete []a; + goto x_out; + } + + if (left_is_neg) { + lb = (1-lb) + lb_carry; + lb_carry = (lb & ~1)? 1 : 0; + lb &= 1; + } + if (right_is_neg) { + rb = (1-rb) + rb_carry; + rb_carry = (rb & ~1)? 1 : 0; + rb &= 1; + } z[idx]=lb; a[idx]=1-rb; // for 2s complement add.. @@ -1724,72 +1703,182 @@ if(cp->number <= 8*sizeof(unsigned long)) { if (idx2 >= 4) idx2 += 1; } + z[len]=0; a[len]=1; - for(i=len-1;i>=0;i--) - { - if(!a[i]) - { - mxa=i; break; - } - } - - for(i=len-1;i>=0;i--) - { - if(z[i]) - { - mxz=i; break; - } - } + for(i=len-1;i>=0;i--) { + if(!a[i]) { + mxa=i; + break; + } + } - if((mxa>mxz)||(mxa==-1)) - { - if(mxa==-1) { - delete []t; - delete []z; - delete []a; - goto x_out; - } - - goto tally; - } + for(i=len-1;i>=0;i--) { + if(z[i]) { + mxz=i; + break; + } + } - copylen = mxa + 2; - current = mxz - mxa; - - while(current > -1) - { - carry = 1; - for(i=0;i>1); - } - - if(carry) - { - for(i=0;imxz)||(mxa==-1)) { + if(mxa==-1) { + delete []t; + delete []z; + delete []a; + goto x_out; + } -tally: + goto tally; + } + + copylen = mxa + 2; + current = mxz - mxa; + + while(current > -1) { + carry = 1; + for(i=0;i>1); + } + + if(carry) { + for(i=0;inumber ; idx += 1) { - thr_put_bit(thr, cp->bit_idx[0]+idx, z[idx]); + unsigned ob = z[idx]; + if (out_is_neg) { + ob = (1-ob) + carry; + carry = (ob & ~1)? 1 : 0; + ob = ob & 1; + } + thr_put_bit(thr, cp->bit_idx[0]+idx, ob); } delete []t; delete []z; delete []a; + return; + + x_out: + for (unsigned idx = 0 ; idx < cp->number ; idx += 1) + thr_put_bit(thr, cp->bit_idx[0]+idx, 2); + + return; +} + +bool of_MOD(vthread_t thr, vvp_code_t cp) +{ + assert(cp->bit_idx[0] >= 4); + + if(cp->number <= 8*sizeof(unsigned long long)) { + unsigned idx1 = cp->bit_idx[0]; + unsigned idx2 = cp->bit_idx[1]; + unsigned long long lv = 0, rv = 0; + + for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { + unsigned long long lb = thr_get_bit(thr, idx1); + unsigned long long rb = thr_get_bit(thr, idx2); + + if ((lb | rb) & 2) + goto x_out; + + lv |= lb << idx; + rv |= rb << idx; + + idx1 += 1; + if (idx2 >= 4) + idx2 += 1; + } + + if (rv == 0) + goto x_out; + + lv %= rv; + + for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { + thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1) ? 1 : 0); + lv >>= 1; + } + + return true; + + } else { + do_verylong_mod(thr, cp, false, false); + return true; + } + + x_out: + for (unsigned idx = 0 ; idx < cp->number ; idx += 1) + thr_put_bit(thr, cp->bit_idx[0]+idx, 2); + return true; } +bool of_MOD_S(vthread_t thr, vvp_code_t cp) +{ + assert(cp->bit_idx[0] >= 4); + + /* Handle the case that we can fit the bits into a long-long + variable. We cause use native % to do the work. */ + if(cp->number <= 8*sizeof(long long)) { + unsigned idx1 = cp->bit_idx[0]; + unsigned idx2 = cp->bit_idx[1]; + long long lv = 0, rv = 0; + + for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { + long long lb = thr_get_bit(thr, idx1); + long long rb = thr_get_bit(thr, idx2); + + if ((lb | rb) & 2) + goto x_out; + + lv |= lb << idx; + rv |= rb << idx; + + idx1 += 1; + if (idx2 >= 4) + idx2 += 1; + } + + if (rv == 0) + goto x_out; + + /* Sign extend the signed operands. */ + if (lv & (1 << (cp->number-1))) + lv |= -1LL << cp->number; + if (rv & (1 << (cp->number-1))) + rv |= -1LL << cp->number; + + lv %= rv; + + for (unsigned idx = 0 ; idx < cp->number ; idx += 1) { + thr_put_bit(thr, cp->bit_idx[0]+idx, (lv&1) ? 1 : 0); + lv >>= 1; + } + + return true; + + } else { + + bool left_is_neg + = thr_get_bit(thr,cp->bit_idx[0]+cp->number-1) == 1; + bool right_is_neg + = thr_get_bit(thr,cp->bit_idx[1]+cp->number-1) == 1; + do_verylong_mod(thr, cp, left_is_neg, right_is_neg); + return true; + } + x_out: for (unsigned idx = 0 ; idx < cp->number ; idx += 1) thr_put_bit(thr, cp->bit_idx[0]+idx, 2); @@ -2785,6 +2874,9 @@ bool of_JOIN_UFUNC(vthread_t thr, vvp_code_t cp) /* * $Log: vthread.cc,v $ + * Revision 1.120 2004/06/19 15:52:53 steve + * Add signed modulus operator. + * * Revision 1.119 2004/06/04 23:26:34 steve * Pick sign bit from the right place in the exponent number. *