From 0b85f483387c7422a6de554e5b1d6ec7c6357f57 Mon Sep 17 00:00:00 2001 From: phil Date: Fri, 3 May 1996 23:19:26 +0000 Subject: [PATCH] Updates from Matthias Pfaller and Ian Dall. --- sys/arch/pc532/fpu/ieee_handler.c | 100 +++++++++++-------- sys/arch/pc532/fpu/ieee_handler.h | 5 +- sys/arch/pc532/fpu/ieee_invop.c | 153 +++++++++++++++++++----------- 3 files changed, 159 insertions(+), 99 deletions(-) diff --git a/sys/arch/pc532/fpu/ieee_handler.c b/sys/arch/pc532/fpu/ieee_handler.c index e3268436d0c4..acd342117202 100644 --- a/sys/arch/pc532/fpu/ieee_handler.c +++ b/sys/arch/pc532/fpu/ieee_handler.c @@ -1,4 +1,4 @@ -/* $NetBSD: ieee_handler.c,v 1.1 1996/04/04 06:36:18 phil Exp $ */ +/* $NetBSD: ieee_handler.c,v 1.2 1996/05/03 23:19:26 phil Exp $ */ /* * IEEE floating point support for NS32081 and NS32381 fpus. @@ -24,31 +24,55 @@ * decodes floating point instructions. * * HISTORY + * 23-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Advance pc past trapping instruction always. + * + * 13-Apr-96 Matthias Pfaller + * Fix up test for denormalized result in canonical_to_size(). + * + * 13-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Clean up types in get_operand(). + * + * 13-Apr-96 Matthias Pfaller + * Remove redundant status test code from fetch_data(). Fix + * register relative and PC relative address decoding. + * + * 02-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Make zero floats get canonicalized to doubles properly. + * + * 02-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Notice that default_trap_handle() has a side effect of changing + * state->FSR. + * + * 02-Apr-96 Matthias Pfaller + * Add NetBSD kernel support. + * * 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au) * First release. - * - */ + * */ #include #include #include "ieee_internal.h" -#include #if defined(KERNEL) || defined(_KERNEL) -# ifdef __NetBSD__ -# include -# define longjmp(x, y) longjmp(&x) -# define setjmp(x) setjmp(&x) -# define AT void * -# else +# ifdef MACH # include # define setjmp _setjmp # define longjmp _longjmp # define AT vm_offset_t +# elif defined(__NetBSD__) /* MACH */ +# include +# include +# define longjmp(x, y) longjmp(&x) +# define setjmp(x) setjmp(&x) +# define AT void * # endif # define get_dword(addr) ({long _t; COPYIN((addr), (vm_offset_t) &_t, sizeof(long)); _t;}) #else /* KERNEL */ +# include # include +# define AT vm_offset_t # ifdef DEBUG # include # endif @@ -242,7 +266,7 @@ static int canonical_to_size(struct operand *op) { else { mantissa = t.d_bits.mantissa << 3; mantissa |= (t.d_bits.mantissa2 >> 29) & 7; - if(exp <= 0) { + if(exp <= 0 && (mantissa != 0 || t.d_bits.exp != 0)) { /* Denormalize */ mantissa |= 0x800000; mantissa >>= -exp; @@ -276,14 +300,20 @@ static void canonicalise_op(struct operand *op) { op->data.d_bits.exp = (t.f_bits.exp == 0xff)? 0x7ff: t.f_bits.exp + EXP_DBIAS - EXP_FBIAS; op->data.d_bits.mantissa = t.f_bits.mantissa >> 3; op->data.d_bits.mantissa2 = (t.f_bits.mantissa & 7) << 29; - if (t.f_bits.exp == 0 && t.f_bits.mantissa != 0) { - /* Was a subnormal float. Subnormal floats can always be converted - * to normal doubles. - */ - int norm; - op->data.d_bits.exp = 0; - norm = ieee_normalize(&(op->data)); - op->data.d_bits.exp = EXP_DBIAS - EXP_FBIAS + norm; + if (t.f_bits.exp == 0) { + if (t.f_bits.mantissa == 0) { + /* Float is zero */ + op->data.d_bits.exp = 0; + } + else { + /* Was a subnormal float. Subnormal floats can always be converted + * to normal doubles. + */ + int norm; + op->data.d_bits.exp = 0; + norm = ieee_normalize(&(op->data)); + op->data.d_bits.exp = EXP_DBIAS - EXP_FBIAS + norm; + } } } } @@ -305,7 +335,7 @@ static struct { vm_offset_t base; char *max; char buf[MAX_LEN]; -#if defined(_KERNEL) && defined(__NetBSD__) +#if defined(_KERNEL) && defined(__NetBSD__) && !defined(MACH) label_t copyfail; #else jmp_buf copyfail; @@ -345,18 +375,13 @@ static int fetch_data (char *addr) { vm_offset_t u_end_addr = copyin_buffer.base + addr - copyin_buffer.buf; vm_offset_t k_addr = (vm_offset_t) copyin_buffer.max; int n; - int status; int n_page = ns532_round_page(u_end_addr) - copyin_buffer.base + copyin_buffer.buf - copyin_buffer.max; int n_max = MAX_LEN + copyin_buffer.buf - copyin_buffer.max; int n_min = addr - copyin_buffer.max + 1; n = MIN(n_max, MAX(n_min, MIN(FETCH_CHUNK, n_page))); - status = COPYIN(u_addr, k_addr, n); + COPYIN(u_addr, k_addr, n); DP(2, "fetch_data: addr = 0x%x, from 0x%x, to 0x%x, n = %d\n", addr, u_addr, k_addr, n); - if (status != 0) { - longjmp (copyin_buffer.copyfail, 1); - } - else - copyin_buffer.max += n; + copyin_buffer.max += n; return 1; } @@ -418,7 +443,7 @@ static int get_operand(char **buf, unsigned char gen, unsigned char index, struc /* Register relative disp(R0 -- R7) */ /* rn out of state, then get data out of res_addr */ disp1 = get_displacement (buf); - addr = (disp1 + reg_addr(gen & 7, state)); + addr = (disp1 + *(unsigned int *)reg_addr(gen & 7, state)); break; case 0x10: case 0x11: @@ -474,25 +499,22 @@ static int get_operand(char **buf, unsigned char gen, unsigned char index, struc case 0x18: /* Memory space disp(FP) */ disp1 = get_displacement (buf); - addr = (disp1 + (unsigned int) state->FP); + addr = (disp1 + (vm_offset_t) state->FP); break; case 0x19: /* Memory space disp(SP) */ disp1 = get_displacement (buf); - addr = (disp1 + (unsigned int) state->SP); + addr = (disp1 + (vm_offset_t) state->SP); break; case 0x1a: /* Memory space disp(SB) */ disp1 = get_displacement (buf); - addr = (disp1 + (unsigned int) state->SB); + addr = (disp1 + (vm_offset_t) state->SB); break; case 0x1b: /* Memory space disp(PC) */ - { - vm_offset_t disp_addr = BUF_TO_UADDR(*buf); - disp1 = get_displacement (buf); - addr = disp1 + disp_addr; - } + disp1 = get_displacement (buf); + addr = disp1 + (vm_offset_t) state->PC; break; case 0x1c: case 0x1d: @@ -680,6 +702,7 @@ int ieee_handle_exception(state *state) if(user_trap == FPC_TT_NONE) { user_trap = default_trap_handle(&op1, &op2, &f0_op, xopcode, state); + fsr = state->FSR; /* May have been side effected */ /* user_trap now has traps generated during emulation. Correct ieee * results already calculated, but must see whether we need to @@ -728,9 +751,6 @@ int ieee_handle_exception(state *state) } if(user_trap == FPC_TT_NONE) { - /* Otherwise the user trap must step over the instruction if it wants - * to resume - */ if(res) { #ifdef DEBUG if (ieee_handler_debug > 1) { @@ -739,8 +759,8 @@ int ieee_handle_exception(state *state) #endif store_result(res); } - state->PC = BUF_TO_UADDR(buf); } + state->PC = BUF_TO_UADDR(buf); SET_FSR(ofsr); state->FSR = fsr; return user_trap; diff --git a/sys/arch/pc532/fpu/ieee_handler.h b/sys/arch/pc532/fpu/ieee_handler.h index 05efd7b39633..6d3bb424bb6c 100644 --- a/sys/arch/pc532/fpu/ieee_handler.h +++ b/sys/arch/pc532/fpu/ieee_handler.h @@ -1,4 +1,4 @@ -/* $NetBSD: ieee_handler.h,v 1.1 1996/04/04 06:36:20 phil Exp $ */ +/* $NetBSD: ieee_handler.h,v 1.2 1996/05/03 23:19:27 phil Exp $ */ /* * IEEE floating point support for NS32081 and NS32381 fpus. @@ -24,6 +24,9 @@ * or unix signal handler version. * * HISTORY + * 02-Apr-96 Matthias Pfaller ) + * Add NetBSD kernel support. + * * 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au) * First release. * diff --git a/sys/arch/pc532/fpu/ieee_invop.c b/sys/arch/pc532/fpu/ieee_invop.c index 2d72359e5dfb..eadc9809b07d 100644 --- a/sys/arch/pc532/fpu/ieee_invop.c +++ b/sys/arch/pc532/fpu/ieee_invop.c @@ -1,4 +1,4 @@ -/* $NetBSD: ieee_invop.c,v 1.1 1996/04/04 06:36:25 phil Exp $ */ +/* $NetBSD: ieee_invop.c,v 1.2 1996/05/03 23:19:28 phil Exp $ */ /* * IEEE floating point support for NS32081 and NS32381 fpus. @@ -23,6 +23,22 @@ * Handle operations which generated reserved operand traps. * * HISTORY + * 23-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Don't change sign of NaN operands of NEGF and SUBF. + * + * 23-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Operations on signaling NaN's always produce a quiet NaN. + * + * 08-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Generate correct return value so flags get set properly. + * + * 05-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Get subnormal number divided by subnormal number right. + * Get infinty multiplied by zero right. + * + * 02-Apr-96 Ian Dall (Ian.Dall@dsto.defence.gov.au) + * Make 0/0 produce NaN. + * * 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au) * First release. * @@ -50,6 +66,7 @@ static int nan_2(union t_conv data1, union t_conv *data2) } break; } + data2->d_bits.mantissa |= 0x80000; /* Make sure it is a quiet NaN */ return 1; } @@ -70,8 +87,10 @@ static int add_iv (struct operand *op1, struct operand *op2) case 2: return ret; case 3: - if(op1->data.d_bits.sign != op2->data.d_bits.sign) + if(op1->data.d_bits.sign != op2->data.d_bits.sign) { op2->data = qnan; + return FPC_TT_INVOP; + } return ret; } /* Must be subnormals */ @@ -102,9 +121,22 @@ static int div_iv (struct operand *op1, struct operand *op2) return ret; case 3: op2->data = qnan; - return ret; + return FPC_TT_INVOP; } - /* Must be subnormals */ + if(ISZERO(op1->data)) { + if (ISZERO(op2->data)) { + /* Must be 0/0 */ + op2->data = qnan; + return FPC_TT_INVOP; + } + else { + /* Must be subnorm/0 */ + op2->data = infty; + op2->data.d_bits.sign = sign1 ^ sign2; + return FPC_TT_DIV0; + } + } + /* Must be subnorm/subnorm */ return ieee_div(op1->data.d, &op2->data.d); } @@ -122,12 +154,21 @@ static int mul_iv (struct operand *op1, struct operand *op2) case 0: break; case 1: /* oo * n */ - { - op2->data = ISZERO(op1->data)? qnan: op1->data; + if (ISZERO(op2->data)) { + op2->data = qnan; + return FPC_TT_INVOP; + } + else { + op2->data = op1->data; op2->data.d_bits.sign = sign1 ^ sign2; return ret; } case 2: /* n * oo */ + if (ISZERO(op1->data)) { + op2->data = qnan; + return FPC_TT_INVOP; + } + /* Fall through */ case 3: /* oo * oo */ op2->data.d_bits.sign = sign1 ^ sign2; return ret; @@ -235,60 +276,56 @@ int ieee_invop(struct operand *op1, struct operand *op2, int user_trap = FPC_TT_NONE; unsigned int fsr = state->FSR; - - /* Source is Infty, NaN or Subnormal (or 0 if dividing 0 by 0) */ - fsr |= FPC_IVF; - if (fsr & FPC_IVE) { - /* Users trap handler will fix it */ - user_trap = FPC_TT_INVOP; - } - else { - /* - * Figure out right thing to do. - */ - switch(xopcode) { - case NEGF: + /* Don't fiddle with fsr. The FPC_TT_INVOP bit should only be set + * if we attempt to *generate* a NaN. This is achieved by returning + * FPC_TT_INVOP when we generate a NaN. + */ + /* + * Figure out right thing to do. + */ + switch(xopcode) { + case NEGF: + if(! ISNAN(op1->data)) op1->data.d_bits.sign ^= 1; - /* Fall through */ - case MOVF: - case MOVLF: - case MOVFL: - op2->data = op1->data; - break; - case CMPF: - cmp_iv(op1, op2, state); - break; - case SUBF: + /* Fall through */ + case MOVF: + case MOVLF: + case MOVFL: + op2->data = op1->data; + break; + case CMPF: + cmp_iv(op1, op2, state); + break; + case SUBF: + if(! ISNAN(op1->data)) op1->data.d_bits.sign ^= 1; - /* Fall through */ - case ADDF: - user_trap = add_iv(op1, op2); - break; - case MULF: - user_trap = mul_iv(op1, op2); - break; - case DIVF: - user_trap = div_iv(op1, op2); - break; - case ROUNDFI: - case TRUNCFI: - case FLOORFI: - user_trap = round_iv(op1, op2, xopcode); - break; - case SCALBF: - user_trap = scalb_iv(op1, op2); - break; - case LOGBF: - user_trap = logb_iv(op1, op2); - break; - case DOTF: - user_trap = dot_iv(op1, op2, f0_op); - break; - case POLYF: - user_trap = poly_iv(op1, op2, f0_op); - break; - } + /* Fall through */ + case ADDF: + user_trap = add_iv(op1, op2); + break; + case MULF: + user_trap = mul_iv(op1, op2); + break; + case DIVF: + user_trap = div_iv(op1, op2); + break; + case ROUNDFI: + case TRUNCFI: + case FLOORFI: + user_trap = round_iv(op1, op2, xopcode); + break; + case SCALBF: + user_trap = scalb_iv(op1, op2); + break; + case LOGBF: + user_trap = logb_iv(op1, op2); + break; + case DOTF: + user_trap = dot_iv(op1, op2, f0_op); + break; + case POLYF: + user_trap = poly_iv(op1, op2, f0_op); + break; } - state->FSR = fsr; return user_trap; }