Updates from Matthias Pfaller and Ian Dall.
This commit is contained in:
parent
5e5ebf658f
commit
0b85f48338
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
*
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue