Updates from Matthias Pfaller and Ian Dall.

This commit is contained in:
phil 1996-05-03 23:19:26 +00:00
parent 5e5ebf658f
commit 0b85f48338
3 changed files with 159 additions and 99 deletions

View File

@ -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 <leo@dachau.marco.de>
* 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 <leo@dachau.marco.de>
* 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 <leo@dachau.marco.de>
* Add NetBSD kernel support.
*
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
* First release.
*
*/
* */
#include <sys/types.h>
#include <stddef.h>
#include "ieee_internal.h"
#include <machine/param.h>
#if defined(KERNEL) || defined(_KERNEL)
# ifdef __NetBSD__
# include <sys/systm.h>
# define longjmp(x, y) longjmp(&x)
# define setjmp(x) setjmp(&x)
# define AT void *
# else
# ifdef MACH
# include <setjmp.h>
# define setjmp _setjmp
# define longjmp _longjmp
# define AT vm_offset_t
# elif defined(__NetBSD__) /* MACH */
# include <machine/param.h>
# include <sys/systm.h>
# 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 <machine/param.h>
# include <setjmp.h>
# define AT vm_offset_t
# ifdef DEBUG
# include <stdio.h>
# 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;

View File

@ -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 <leo@dachau.marco.de>)
* Add NetBSD kernel support.
*
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
* First release.
*

View File

@ -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;
}