Initial check-in of the ieee fp support for the pc532.
ieee fp support by Ian Dall, NetBSD/pc532 integration by Matthias Pfaller. Includes setjmp/longjmp added to locore.s.
This commit is contained in:
parent
83f9bdc359
commit
dba4d32f68
@ -1,4 +1,4 @@
|
||||
# $NetBSD: KLONDIKE,v 1.3 1996/01/26 05:12:58 phil Exp $
|
||||
# $NetBSD: KLONDIKE,v 1.4 1996/04/04 06:36:03 phil Exp $
|
||||
#
|
||||
# KLONDIKE: Matthias Pfaller's pc532
|
||||
#
|
||||
@ -62,7 +62,7 @@ membus0 at root
|
||||
|
||||
ncr0 at membus?
|
||||
|
||||
scsibus0 at scsi?
|
||||
scsibus0 at ncr0
|
||||
|
||||
sd* at scsibus? target ? lun ? # SCSI disks
|
||||
st* at scsibus? target ? lun ? # SCSI tapes
|
||||
|
@ -1,4 +1,4 @@
|
||||
# $NetBSD: files.pc532,v 1.20 1996/03/17 01:38:52 thorpej Exp $
|
||||
# $NetBSD: files.pc532,v 1.21 1996/04/04 06:36:08 phil Exp $
|
||||
#
|
||||
# new style config file for pc532 architecture
|
||||
#
|
||||
@ -18,9 +18,9 @@ attach rd at membus
|
||||
file arch/pc532/dev/rd.c rd needs-count
|
||||
major {rd = 3}
|
||||
|
||||
#device timer
|
||||
#device timer
|
||||
#attach timer at membus
|
||||
#device clock
|
||||
#device clock
|
||||
#attach clock at membus
|
||||
file arch/pc532/pc532/clock.c # clock timer
|
||||
|
||||
@ -28,9 +28,9 @@ device scn: tty
|
||||
attach scn at membus
|
||||
file arch/pc532/dev/scn.c scn needs-flag
|
||||
|
||||
device lpt: ether, ifnet
|
||||
device lpt: ether, ifnet
|
||||
attach lpt at membus
|
||||
file arch/pc532/dev/lpt.c lpt needs-count
|
||||
file arch/pc532/dev/lpt.c lpt needs-count
|
||||
|
||||
include "../../../scsi/files.scsi"
|
||||
major {sd = 0}
|
||||
@ -42,7 +42,7 @@ attach ncr at membus
|
||||
file arch/pc532/dev/ncr.c ncr needs-count
|
||||
device oldncr: scsi
|
||||
attach oldncr at membus
|
||||
file arch/pc532/dev/oldncr.c oldncr needs-count
|
||||
file arch/pc532/dev/oldncr.c oldncr needs-count
|
||||
device dp: scsi
|
||||
attach dp at membus
|
||||
file arch/pc532/dev/dp.c dp needs-count
|
||||
@ -50,12 +50,18 @@ device aic: scsi
|
||||
attach aic at membus
|
||||
file arch/pc532/dev/aic.c aic needs-count
|
||||
|
||||
file arch/pc532/fpu/ieee_dze.c
|
||||
file arch/pc532/fpu/ieee_handler.c
|
||||
file arch/pc532/fpu/ieee_invop.c
|
||||
file arch/pc532/fpu/ieee_ovfl.c
|
||||
file arch/pc532/fpu/ieee_subnormal.c
|
||||
|
||||
file dev/cons.c
|
||||
file dev/cninit.c
|
||||
file arch/pc532/pc532/autoconf.c
|
||||
file arch/pc532/pc532/conf.c
|
||||
file arch/pc532/pc532/db_disasm.c ddb
|
||||
file arch/pc532/pc532/db_interface.c ddb
|
||||
file arch/pc532/pc532/db_interface.c ddb
|
||||
file arch/pc532/pc532/db_trace.c ddb
|
||||
file arch/pc532/pc532/disksubr.c disk
|
||||
file arch/pc532/pc532/icuinit.c
|
||||
|
69
sys/arch/pc532/fpu/fpu_status.h
Normal file
69
sys/arch/pc532/fpu/fpu_status.h
Normal file
@ -0,0 +1,69 @@
|
||||
/* $NetBSD: fpu_status.h,v 1.1 1996/04/04 06:36:14 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: fpu_status.h
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* FPU status register definitions
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _FPU_STATUS_H_
|
||||
#define _FPU_STATUS_H_
|
||||
/*
|
||||
* Control register
|
||||
*/
|
||||
#define FPC_RMB 0x00010000 /* register modify bit */
|
||||
#define FPC_SWF 0x0000fe00 /* reserved for software */
|
||||
#define FPC_RM 0x00000180 /* rounding mode */
|
||||
#define FPC_RM_NEAREST 0x00000000 /* round to nearest */
|
||||
#define FPC_RM_TOZERO 0x00000080 /* round towards zero */
|
||||
#define FPC_RM_TOPOS 0x00000100 /* round towards +infinity */
|
||||
#define FPC_RM_TONEG 0x00000180 /* round towards -infinity */
|
||||
#define FPC_IF 0x00000040 /* inexact result flag */
|
||||
#define FPC_IEN 0x00000020 /* inexact result trap enable */
|
||||
#define FPC_UF 0x00000010 /* underflow flag (else 0) */
|
||||
#define FPC_UEN 0x00000008 /* underflow trap enable */
|
||||
#define FPC_TT 0x00000007 /* trap type */
|
||||
#define FPC_TT_NONE 0x00000000 /* no exceptional condition */
|
||||
#define FPC_TT_UNDFL 0x00000001 /* underflow */
|
||||
#define FPC_TT_OVFL 0x00000002 /* overflow */
|
||||
#define FPC_TT_DIV0 0x00000003 /* divide by zero */
|
||||
#define FPC_TT_ILL 0x00000004 /* illegal instruction */
|
||||
#define FPC_TT_INVOP 0x00000005 /* invalid operation */
|
||||
#define FPC_TT_INEXACT 0x00000006 /* inexact result */
|
||||
|
||||
/* Bits in the SWF field used for software emulation */
|
||||
#define FPC_OVE 0x200 /* Overflow enable */
|
||||
#define FPC_OVF 0x400 /* Overflow flag */
|
||||
#define FPC_IVE 0x800 /* Invalid enable */
|
||||
#define FPC_IVF 0x1000 /* Invalid flag */
|
||||
#define FPC_DZE 0x2000 /* Divide by zero enable */
|
||||
#define FPC_DZF 0x4000 /* Divide by zero flag */
|
||||
#define FPC_UNDE 0x8000 /* Soft Underflow enable, requires FPC_UEN */
|
||||
|
||||
#define GET_SET_FSR(val) ({int _tmp; asm volatile("sfsr %0; lfsr %1" : "&=g" (_tmp): "g" (val)); _tmp;})
|
||||
#define GET_FSR() ({int _tmp; asm volatile("sfsr %0" : "=g" (_tmp)); _tmp;})
|
||||
#define SET_FSR(val) ({asm volatile("lfsr %0" :: "g" (val));})
|
||||
|
||||
#endif /* _FPU_STATUS_H_ */
|
60
sys/arch/pc532/fpu/ieee_dze.c
Normal file
60
sys/arch/pc532/fpu/ieee_dze.c
Normal file
@ -0,0 +1,60 @@
|
||||
/* $NetBSD: ieee_dze.c,v 1.1 1996/04/04 06:36:16 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: ieee_dze.c
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* Handle divide by zero, generating +-Infty as required.
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "ieee_internal.h"
|
||||
|
||||
int ieee_dze(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state)
|
||||
{
|
||||
int user_trap = FPC_TT_NONE;
|
||||
unsigned int fsr = state->FSR;
|
||||
DP(1, "Divide by zero trap: xopcode = 0x%x\n", xopcode);
|
||||
fsr |= FPC_DZF;
|
||||
if (fsr & FPC_DZE) {
|
||||
/* Users trap handler will fix it */
|
||||
user_trap = FPC_TT_DIV0;
|
||||
}
|
||||
else {
|
||||
/* Set dest to + or - infinity ? */
|
||||
int sign1 = op2->data.d_bits.sign;
|
||||
int sign2 = op1->data.d_bits.sign;
|
||||
op2->data = infty;
|
||||
op2->data.d_bits.sign = sign1 ^ sign2;
|
||||
switch(xopcode) {
|
||||
case LOGBF:
|
||||
/* logb(0) gives a divide by zero exception according to ieee.
|
||||
* No idea if the logbf instruction conforms, but just in case...
|
||||
*/
|
||||
op2->data.d_bits.sign = 1;
|
||||
}
|
||||
}
|
||||
state->FSR = fsr;
|
||||
return user_trap;
|
||||
}
|
747
sys/arch/pc532/fpu/ieee_handler.c
Normal file
747
sys/arch/pc532/fpu/ieee_handler.c
Normal file
@ -0,0 +1,747 @@
|
||||
/* $NetBSD: ieee_handler.c,v 1.1 1996/04/04 06:36:18 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: ieee_handler.c
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* Entry points for the ieee exception handling package.
|
||||
* decodes floating point instructions.
|
||||
*
|
||||
* HISTORY
|
||||
* 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
|
||||
# include <setjmp.h>
|
||||
# define setjmp _setjmp
|
||||
# define longjmp _longjmp
|
||||
# define AT vm_offset_t
|
||||
# endif
|
||||
# define get_dword(addr) ({long _t; COPYIN((addr), (vm_offset_t) &_t, sizeof(long)); _t;})
|
||||
#else /* KERNEL */
|
||||
# include <setjmp.h>
|
||||
# ifdef DEBUG
|
||||
# include <stdio.h>
|
||||
# endif
|
||||
|
||||
# define copyin(u,k,n) ({vm_offset_t _u = (u), _k = (k); memcpy((char *) _k, (char *) _u,n);0;})
|
||||
# define copyout(k,u,n) ({vm_offset_t _u = (u), _k = (k); memcpy((char *) _u, (char *) _k,n);0;})
|
||||
# define get_dword(addr) (* (unsigned int *) addr)
|
||||
|
||||
# define ns532_round_page(addr) (((addr) + NBPG - 1) & ~(NBPG - 1))
|
||||
|
||||
static void get_fstate(state *state) {
|
||||
asm("sfsr %0" : "=g" (state->FSR));
|
||||
asm("movl f0, %0" : "=m" (state->LREG(0)));
|
||||
asm("movl f1, %0" : "=m" (state->LREG(1)));
|
||||
asm("movl f2, %0" : "=m" (state->LREG(2)));
|
||||
asm("movl f3, %0" : "=m" (state->LREG(3)));
|
||||
asm("movl f4, %0" : "=m" (state->LREG(4)));
|
||||
asm("movl f5, %0" : "=m" (state->LREG(5)));
|
||||
asm("movl f6, %0" : "=m" (state->LREG(6)));
|
||||
asm("movl f7, %0" : "=m" (state->LREG(7)));
|
||||
}
|
||||
|
||||
static void set_fstate(state *state) {
|
||||
/* DON'T tell gcc we are clobbering fp registers, else it will
|
||||
* save and restore some, undoing our changes!
|
||||
*/
|
||||
asm("lfsr %0":: "g" (state->FSR));
|
||||
asm("movl %0, f0":: "m" (state->LREG(0)));
|
||||
asm("movl %0, f1":: "m" (state->LREG(1)));
|
||||
asm("movl %0, f2":: "m" (state->LREG(2)));
|
||||
asm("movl %0, f3":: "m" (state->LREG(3)));
|
||||
asm("movl %0, f4":: "m" (state->LREG(4)));
|
||||
asm("movl %0, f5":: "m" (state->LREG(5)));
|
||||
asm("movl %0, f6":: "m" (state->LREG(6)));
|
||||
asm("movl %0, f7":: "m" (state->LREG(7)));
|
||||
}
|
||||
|
||||
|
||||
int ieee_sig(int sig, int code, struct sigcontext *scp)
|
||||
{
|
||||
int ret;
|
||||
vm_offset_t orig_pc;
|
||||
state state;
|
||||
get_fstate(&state);
|
||||
state.scp = scp;
|
||||
orig_pc = state.PC;
|
||||
DP(1, "sig = 0x%x, code = 0x%x, pc = 0x%x, fsr = 0x%x\n", sig, code, state.PC, state.FSR);
|
||||
ret = ieee_handle_exception(&state);
|
||||
DP(1, " pc incremented by %d\n", state.PC - orig_pc);
|
||||
set_fstate(&state);
|
||||
return ret;
|
||||
}
|
||||
#endif /* KERNEL */
|
||||
|
||||
int ieee_handler_debug = 0;
|
||||
|
||||
#define COPYIN(U,K,N) ({if (copyin((AT)U, (AT)K, N) != 0) longjmp(copyin_buffer.copyfail, 1);0;})
|
||||
|
||||
/* Adressing modes. */
|
||||
#define Adrmod_index_byte 0x1c
|
||||
#define Adrmod_index_word 0x1d
|
||||
#define Adrmod_index_doubleword 0x1e
|
||||
#define Adrmod_index_quadword 0x1f
|
||||
|
||||
/* Is MODE an indexed addressing mode? */
|
||||
#define Adrmod_is_index(mode) \
|
||||
(mode == Adrmod_index_byte \
|
||||
|| mode == Adrmod_index_word \
|
||||
|| mode == Adrmod_index_doubleword \
|
||||
|| mode == Adrmod_index_quadword)
|
||||
|
||||
|
||||
/* Extract a bit field from a stream. Assume nbits less that
|
||||
* or equal to 8. Also assume little endian. Assume no alignment
|
||||
* restrictions on short.
|
||||
*/
|
||||
static inline int bit_extract(char *buffer, int offset, int nbits)
|
||||
{
|
||||
int start_byte = offset/8;
|
||||
int end_byte = (offset + nbits - 1)/8;
|
||||
return (((start_byte == end_byte? buffer[start_byte]:
|
||||
*(short *)(buffer + start_byte)) >> offset%8)
|
||||
& ((1 << nbits) - 1));
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
static int invalid_float(union t_conv *p, int size)
|
||||
{
|
||||
int val;
|
||||
if ( size == sizeof (float) )
|
||||
val = (p->f_bits.exp == 0xff
|
||||
|| (p->f_bits.exp == 0 && p->f_bits.mantissa != 0));
|
||||
else if ( size == sizeof (double) )
|
||||
val = (p->d_bits.exp == 0x7ff
|
||||
|| (p->d_bits.exp == 0 && (p->d_bits.mantissa != 0 || p->d_bits.mantissa2 != 0)));
|
||||
else
|
||||
val = 1;
|
||||
return (val);
|
||||
}
|
||||
|
||||
static void print_op(struct operand *op)
|
||||
{
|
||||
if (op->type == op_type_float) {
|
||||
if (invalid_float(&op->data, op->size)) {
|
||||
if (op->size == sizeof(double)) {
|
||||
printf("s: %d, e: %x, m1: %x, m2: %x", op->data.d_bits.sign, op->data.d_bits.exp, op->data.d_bits.mantissa, op->data.d_bits.mantissa2);
|
||||
}
|
||||
else {
|
||||
printf("s: %d, e: %x, m1: %x", op->data.f_bits.sign, op->data.f_bits.exp, op->data.f_bits.mantissa);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (op->size == sizeof(double))
|
||||
printf("%25.17e", op->data.d);
|
||||
else
|
||||
printf("%18.10e", op->data.f);
|
||||
}
|
||||
}
|
||||
else
|
||||
switch(op->size) {
|
||||
case 1:
|
||||
printf("%d", op->data.c);
|
||||
break;
|
||||
case 2:
|
||||
printf("%d", op->data.s);
|
||||
break;
|
||||
case 4:
|
||||
printf("%d", op->data.i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static const int regoffsets[] = {REGOFFSET(0), REGOFFSET(1), REGOFFSET(2),
|
||||
REGOFFSET(3), REGOFFSET(4), REGOFFSET(5),
|
||||
REGOFFSET(6), REGOFFSET(7)};
|
||||
|
||||
static inline void read_reg(int regno, struct operand *op, state *state) {
|
||||
vm_offset_t addr = REGBASE(state) + regoffsets[regno];
|
||||
switch(op->size) {
|
||||
case 1: *(char *) &op->data = *(char *) addr; break;
|
||||
case 2: *(short *) &op->data = *(short *) addr; break;
|
||||
default: *(int *) &op->data = *(int *) addr; break;
|
||||
}
|
||||
op->where.tag = op_where_register;
|
||||
op->where.addr = (vm_offset_t) &op->data;
|
||||
}
|
||||
|
||||
static inline vm_offset_t reg_addr(int regno, state *state) {
|
||||
return REGBASE(state) + regoffsets[regno];
|
||||
}
|
||||
|
||||
|
||||
static void read_freg(int regno, struct operand *op, state *state) {
|
||||
vm_offset_t addr;
|
||||
if (op->size == sizeof(float)) {
|
||||
static const int offsets[] = {
|
||||
FREGOFFSET(0), FREGOFFSET(1), FREGOFFSET(2), FREGOFFSET(3),
|
||||
FREGOFFSET(4), FREGOFFSET(5), FREGOFFSET(6), FREGOFFSET(7)};
|
||||
addr = FREGBASE(state) + offsets[regno];
|
||||
*(float *) &op->data = *(float *) addr;
|
||||
}
|
||||
else {
|
||||
static const int offsets[] = {
|
||||
LREGOFFSET(0), LREGOFFSET(1), LREGOFFSET(2), LREGOFFSET(3),
|
||||
LREGOFFSET(4), LREGOFFSET(5), LREGOFFSET(6), LREGOFFSET(7)};
|
||||
addr = LREGBASE(state) + offsets[regno];
|
||||
*(double *) &op->data = *(double *) addr;
|
||||
}
|
||||
op->where.tag = op_where_register;
|
||||
op->where.addr = addr;
|
||||
}
|
||||
|
||||
|
||||
static int canonical_to_size(struct operand *op) {
|
||||
int ret = FPC_TT_NONE;
|
||||
union t_conv t = op->data;
|
||||
if(op->type == op_type_float) {
|
||||
if (op->size == sizeof(float)) {
|
||||
unsigned long mantissa;
|
||||
int exp = t.d_bits.exp + EXP_FBIAS - EXP_DBIAS;
|
||||
op->data.f_bits.sign = t.d_bits.sign;
|
||||
op->data.f_bits.exp = (exp < 0)? 0: ((exp > 0xff)? 0xff: exp);
|
||||
if(exp >= 0xff && t.d_bits.exp < 0x7ff) {
|
||||
/* Overflow. need +- infinity.
|
||||
* Allow for trap on overflow.
|
||||
*/
|
||||
ret = FPC_TT_OVFL;
|
||||
mantissa = 0;
|
||||
}
|
||||
else {
|
||||
mantissa = t.d_bits.mantissa << 3;
|
||||
mantissa |= (t.d_bits.mantissa2 >> 29) & 7;
|
||||
if(exp <= 0) {
|
||||
/* Denormalize */
|
||||
mantissa |= 0x800000;
|
||||
mantissa >>= -exp;
|
||||
ret = FPC_TT_UNDFL;
|
||||
}
|
||||
if (mantissa == 0 && ISNAN(t))
|
||||
mantissa = 0x400000; /* Signaling NaN */
|
||||
}
|
||||
op->data.f_bits.mantissa = mantissa;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (op->size) {
|
||||
case sizeof(char):
|
||||
op->data.c = t.i;
|
||||
break;
|
||||
case sizeof(short):
|
||||
op->data.s = t.i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void canonicalise_op(struct operand *op) {
|
||||
union t_conv t = op->data;
|
||||
if(op->type == op_type_float) {
|
||||
if (op->size == sizeof(float)) {
|
||||
op->data.d_bits.sign = t.f_bits.sign;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (op->size) {
|
||||
case sizeof(char):
|
||||
op->data.i = t.c;
|
||||
break;
|
||||
case sizeof(short):
|
||||
op->data.i = t.s;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define MAX_LEN 21 /* The longest an instruction can be */
|
||||
|
||||
static struct {
|
||||
vm_offset_t base;
|
||||
char *max;
|
||||
char buf[MAX_LEN];
|
||||
#if defined(_KERNEL) && defined(__NetBSD__)
|
||||
label_t copyfail;
|
||||
#else
|
||||
jmp_buf copyfail;
|
||||
#endif
|
||||
} copyin_buffer;
|
||||
|
||||
static void store_result(struct operand *op)
|
||||
{
|
||||
if (op->where.tag == op_where_memory) {
|
||||
/* copyout */
|
||||
if (copyout((AT) &op->data, (AT)op->where.addr, op->size) != 0) {
|
||||
longjmp (copyin_buffer.copyfail, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
/* Register */
|
||||
memcpy((char *)op->where.addr, (char *) &op->data, op->size);
|
||||
}
|
||||
}
|
||||
|
||||
#define FETCH_DATA(addr) ((addr) < copyin_buffer.max? 1: fetch_data(addr))
|
||||
#define BUF_TO_UADDR(addr) ((addr) - copyin_buffer.buf + copyin_buffer.base)
|
||||
|
||||
#define FETCH_CHUNK 8 /* Size of chunks to copyin */
|
||||
|
||||
#define MAX(x,y) ((x) > (y)? (x): (y))
|
||||
#define MIN(x,y) ((x) < (y)? (x): (y))
|
||||
|
||||
|
||||
/* Fetch data from user space so as to validate buffer up to addr.
|
||||
* We do some read ahead (to minimise the number of copyins) but
|
||||
* we never read ahead past a page boundary incase that would not
|
||||
* be mapped.
|
||||
*/
|
||||
static int fetch_data (char *addr) {
|
||||
vm_offset_t u_addr = copyin_buffer.base + copyin_buffer.max - copyin_buffer.buf;
|
||||
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);
|
||||
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;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int get_displacement (char **buffer)
|
||||
{
|
||||
int disp;
|
||||
char *buf = *buffer;
|
||||
FETCH_DATA(buf);
|
||||
switch (*buf & 0xc0)
|
||||
{
|
||||
case 0x00:
|
||||
case 0x40:
|
||||
disp = *buf++ & 0x7f;
|
||||
disp = (disp & 0x40) ? disp | 0xffffff80: disp;
|
||||
break;
|
||||
case 0x80:
|
||||
FETCH_DATA(buf + 1);
|
||||
disp = *buf++ & 0x3f;
|
||||
disp = (disp & 0x20) ? disp | 0xffffffc0: disp;
|
||||
disp = (disp << 8) | (0xff & *buf++);
|
||||
break;
|
||||
case 0xc0:
|
||||
FETCH_DATA(buf + 3);
|
||||
disp = *buf++ & 0x3f;
|
||||
disp = (disp & 0x20) ? disp | 0xffffffc0: disp;
|
||||
disp = (disp << 8) | (0xff & *buf++);
|
||||
disp = (disp << 8) | (0xff & *buf++);
|
||||
disp = (disp << 8) | (0xff & *buf++);
|
||||
break;
|
||||
}
|
||||
*buffer = buf;
|
||||
DP(1, "disp = %d\n", disp);
|
||||
return disp;
|
||||
}
|
||||
|
||||
static int get_operand(char **buf, unsigned char gen, unsigned char index, struct operand *op, state *state)
|
||||
{
|
||||
int ret = FPC_TT_NONE;
|
||||
vm_offset_t addr;
|
||||
int disp1, disp2;
|
||||
DP(1,"gen = 0x%x\n", gen);
|
||||
|
||||
if (op->type == op_type_float && (gen & ~7) == 0) {
|
||||
read_freg(gen, op, state);
|
||||
return ret;
|
||||
}
|
||||
switch (gen) {
|
||||
case 0: case 1: case 2: case 3:
|
||||
case 4: case 5: case 6: case 7:
|
||||
if (op->class != op_class_addr) {
|
||||
read_reg(gen, op, state);
|
||||
return ret;
|
||||
}
|
||||
else
|
||||
addr = reg_addr(gen, state);
|
||||
break;
|
||||
case 0x8: case 0x9: case 0xa: case 0xb:
|
||||
case 0xc: case 0xd: case 0xe: case 0xf:
|
||||
/* 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));
|
||||
break;
|
||||
case 0x10:
|
||||
case 0x11:
|
||||
case 0x12:
|
||||
/* Memory relative disp2(disp1(FP, SP, SB)) */
|
||||
disp1 = get_displacement (buf);
|
||||
disp2 = get_displacement (buf);
|
||||
addr = (disp1
|
||||
+ (vm_offset_t) (gen == 0x10? state->FP: (gen == 0x11? state->SP:
|
||||
state->SB)));
|
||||
addr = disp2 + get_dword(addr);
|
||||
break;
|
||||
case 0x14:
|
||||
/* Immediate */
|
||||
if (op->class == op_class_read) {
|
||||
char *p;
|
||||
int i;
|
||||
FETCH_DATA(*buf + op->size - 1);
|
||||
for(p = (char *)&op->data, i = op->size; i--; p++) {
|
||||
*p = *(*buf + i);
|
||||
}
|
||||
op->where.tag = op_where_immediate;
|
||||
op->where.addr = 0;
|
||||
*buf += op->size;
|
||||
return ret;
|
||||
}
|
||||
else {
|
||||
return FPC_TT_ILL;
|
||||
}
|
||||
case 0x15:
|
||||
/* Absolute @disp */
|
||||
disp1 = get_displacement (buf);
|
||||
addr = disp1;
|
||||
break;
|
||||
case 0x16:
|
||||
/* External EXT(disp1) + disp2 (Mod table stuff) */
|
||||
disp1 = get_displacement (buf);
|
||||
disp2 = get_displacement (buf);
|
||||
return FPC_TT_ILL; /* Unsupported */
|
||||
case 0x17:
|
||||
/* Top of stack tos */
|
||||
addr = state->SP;
|
||||
switch (op->class) {
|
||||
case op_class_read:
|
||||
state->SP += op->size;
|
||||
break;
|
||||
case op_class_write:
|
||||
state->SP -= op->size;
|
||||
addr = state->SP;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 0x18:
|
||||
/* Memory space disp(FP) */
|
||||
disp1 = get_displacement (buf);
|
||||
addr = (disp1 + (unsigned int) state->FP);
|
||||
break;
|
||||
case 0x19:
|
||||
/* Memory space disp(SP) */
|
||||
disp1 = get_displacement (buf);
|
||||
addr = (disp1 + (unsigned int) state->SP);
|
||||
break;
|
||||
case 0x1a:
|
||||
/* Memory space disp(SB) */
|
||||
disp1 = get_displacement (buf);
|
||||
addr = (disp1 + (unsigned int) 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;
|
||||
}
|
||||
break;
|
||||
case 0x1c:
|
||||
case 0x1d:
|
||||
case 0x1e:
|
||||
case 0x1f:
|
||||
/* Scaled index basemode[R0 -- R7:B,W,D,Q] */
|
||||
{
|
||||
enum op_class save = op->class;
|
||||
op->class = op_class_addr;
|
||||
if ((ret = get_operand(buf, index >> 3, 0, op, state)) != FPC_TT_NONE)
|
||||
return ret;
|
||||
addr = op->where.addr + (* (int *) reg_addr(index & 7, state)) * (1 << (gen & 3));
|
||||
op->class = save;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (op->class == op_class_read || op->class == op_class_rmw) {
|
||||
COPYIN(addr, (vm_offset_t)&op->data, op->size);
|
||||
}
|
||||
op->where.tag = op_where_memory;
|
||||
op->where.addr = addr;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int default_trap_handle(struct operand *op1, struct operand *op2, struct operand *f0_op, int xopcode, state *state)
|
||||
{
|
||||
int user_trap = FPC_TT_NONE;
|
||||
unsigned int fsr = state->FSR;
|
||||
int trap_type = fsr & FPC_TT;
|
||||
|
||||
DP(2, "trap type %d\n", trap_type);
|
||||
{
|
||||
int s = GET_SET_FSR(fsr & FPC_RM); /* Same rounding mode as at exception */
|
||||
|
||||
switch (trap_type)
|
||||
{
|
||||
case FPC_TT_UNDFL: /* Underflow */
|
||||
user_trap = ieee_undfl(op1, op2, f0_op, xopcode, state);
|
||||
break;
|
||||
case FPC_TT_OVFL: /* Overflow */
|
||||
user_trap = ieee_ovfl(op1, op2, f0_op, xopcode, state);
|
||||
break;
|
||||
case FPC_TT_DIV0: /* Divide by zero */
|
||||
user_trap = ieee_dze(op1, op2, f0_op, xopcode, state);
|
||||
break;
|
||||
case FPC_TT_ILL: /* Illegal instruction */
|
||||
/* Illegal instruction. Cause a SIGILL ? */
|
||||
user_trap = FPC_TT_ILL;
|
||||
break;
|
||||
case FPC_TT_INVOP: /* Invalid operation */
|
||||
user_trap = ieee_invop(op1, op2, f0_op, xopcode, state);
|
||||
break;
|
||||
case FPC_TT_INEXACT: /* Inexact result */
|
||||
/* Nothing to be done */
|
||||
/* Flags in hardware. We can't get here unless FPC_IEF is set */
|
||||
user_trap = FPC_TT_INEXACT;
|
||||
break;
|
||||
case FPC_TT_NONE:
|
||||
default:
|
||||
DP(0,"ieee_handler: fpu trap type none\n");
|
||||
}
|
||||
SET_FSR(s);
|
||||
}
|
||||
return user_trap;
|
||||
}
|
||||
|
||||
int ieee_handle_exception(state *state)
|
||||
{
|
||||
int fmt, xopcode, ret;
|
||||
int fsr, user_trap = FPC_TT_NONE;
|
||||
volatile int ofsr; /* Volatile for setjmp */
|
||||
unsigned char int_type, float_type, opcode, gen1, gen2, index1, index2;
|
||||
struct operand op1, op2, f0_op, *res;
|
||||
char *buf = copyin_buffer.buf;
|
||||
copyin_buffer.base = state->PC;
|
||||
/* Save fsr and set fsr to 0 so that floating point operations within
|
||||
* the emulation proceed in a known way. */
|
||||
ofsr = GET_SET_FSR(0);
|
||||
if (setjmp(copyin_buffer.copyfail) != 0) {
|
||||
SET_FSR(ofsr);
|
||||
return FPC_TT_ILL;
|
||||
}
|
||||
copyin_buffer.max = buf;
|
||||
/* All fp instructions are 24 bits
|
||||
* and extensions start after 3 bytes
|
||||
*/
|
||||
FETCH_DATA(buf + 2);
|
||||
|
||||
fsr = state->FSR;
|
||||
|
||||
switch(fmt = bit_extract(buf, 0, 8))
|
||||
{
|
||||
case 0x3e: /* Format 9 */
|
||||
int_type = bit_extract(buf, 8, 2);
|
||||
float_type = bit_extract(buf, 10, 1);
|
||||
opcode = bit_extract(buf, 11, 3);
|
||||
fmt = fmt9;
|
||||
break;
|
||||
case 0xbe: /* Format 11 */
|
||||
case 0xfe: /* Format 12 */
|
||||
fmt = (fmt == 0xbe)? fmt11: fmt12;
|
||||
float_type = bit_extract(buf, 8, 1);
|
||||
opcode = bit_extract(buf, 10, 4);
|
||||
break;
|
||||
default:
|
||||
user_trap = FPC_TT_ILL;
|
||||
DP(0, "ieee_handler: format not of a floating point instruction\n");
|
||||
}
|
||||
xopcode = XOPCODE(fmt, opcode);
|
||||
DP(2, "xopcode: 0x%x\n", xopcode);
|
||||
|
||||
gen2 = bit_extract(buf, 14, 5);
|
||||
gen1 = bit_extract(buf, 19, 5);
|
||||
buf += 3;
|
||||
if (Adrmod_is_index(gen1)) {
|
||||
FETCH_DATA(buf);
|
||||
index1 = *buf++;
|
||||
}
|
||||
if (Adrmod_is_index(gen2)) {
|
||||
FETCH_DATA(buf);
|
||||
index2 = *buf++;
|
||||
}
|
||||
|
||||
op1.class = op_class_read;
|
||||
op2.class = op_class_rmw;
|
||||
op1.type = op2.type = op_type_float;
|
||||
op1.size = op2.size = float_type? 4: 8;
|
||||
res = &op2;
|
||||
switch(xopcode) {
|
||||
case MOVLF:
|
||||
op1.type = op_type_float; op1.size = 8;
|
||||
op2.size = 4; op2.class = op_class_write;
|
||||
break;
|
||||
case MOVFL:
|
||||
op1.type = op_type_float; op1.size = 4;
|
||||
op2.size = 8; op2.class = op_class_write;
|
||||
break;
|
||||
case MOVIF:
|
||||
op1.type = op_type_int; op1.size = 1 << int_type;
|
||||
op2.class = op_class_write;
|
||||
break;
|
||||
case NEGF:
|
||||
op2.class = op_class_write;
|
||||
break;
|
||||
case ROUNDFI:
|
||||
case TRUNCFI:
|
||||
case FLOORFI:
|
||||
op2.type = op_type_int; op2.size = 1 << int_type;
|
||||
break;
|
||||
case CMPF:
|
||||
op2.class = op_class_read;
|
||||
res = 0;
|
||||
break;
|
||||
case POLYF:
|
||||
case DOTF:
|
||||
op1.type = op2.type = f0_op.type = op_type_float;
|
||||
op1.size = op2.size = f0_op.size = float_type? 4: 8;
|
||||
op2.class = op_class_read;
|
||||
f0_op.class = op_class_rmw;
|
||||
read_freg(0, &f0_op, state);
|
||||
canonicalise_op(&f0_op);
|
||||
res = &f0_op;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((ret = get_operand(&buf, gen1, index1, &op1, state)) != FPC_TT_NONE) {
|
||||
user_trap = ret;
|
||||
DP(0, "get_operand failed\n");
|
||||
}
|
||||
|
||||
if ((ret = get_operand(&buf, gen2, index2, &op2, state)) != FPC_TT_NONE) {
|
||||
user_trap = ret;
|
||||
DP(0, "get_operand failed\n");
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
if (ieee_handler_debug > 1) {
|
||||
printf( "op1 = "); print_op(&op1); printf("\n");
|
||||
printf( "op2 = "); print_op(&op2); printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
canonicalise_op(&op1);
|
||||
canonicalise_op(&op2);
|
||||
|
||||
if(user_trap == FPC_TT_NONE) {
|
||||
user_trap = default_trap_handle(&op1, &op2, &f0_op, xopcode, state);
|
||||
|
||||
/* user_trap now has traps generated during emulation. Correct ieee
|
||||
* results already calculated, but must see whether we need to
|
||||
* pass trap on to user.
|
||||
*
|
||||
* User trap can be set for many reasons. eg dividing a denorm by 0
|
||||
* might initially result in an invalid operand trap, but during
|
||||
* emulation we set the divide by zero trap.
|
||||
*/
|
||||
|
||||
if (res) {
|
||||
int ret;
|
||||
if((ret = canonical_to_size(res)) != FPC_TT_NONE)
|
||||
user_trap = ret;
|
||||
}
|
||||
|
||||
switch (user_trap) {
|
||||
case FPC_TT_UNDFL:
|
||||
fsr |= FPC_UF;
|
||||
if ((fsr & FPC_UNDE) == 0)
|
||||
user_trap = FPC_TT_NONE;
|
||||
break;
|
||||
case FPC_TT_OVFL:
|
||||
fsr |= FPC_OVF;
|
||||
if ((fsr & FPC_OVE) == 0)
|
||||
user_trap = FPC_TT_NONE;
|
||||
break;
|
||||
case FPC_TT_DIV0:
|
||||
fsr |= FPC_DZF;
|
||||
if ((fsr & FPC_DZE) == 0)
|
||||
user_trap = FPC_TT_NONE;
|
||||
break;
|
||||
case FPC_TT_ILL:
|
||||
break;
|
||||
case FPC_TT_INVOP:
|
||||
fsr |= FPC_IVF;
|
||||
if ((fsr & FPC_IVE) == 0)
|
||||
user_trap = FPC_TT_NONE;
|
||||
break;
|
||||
case FPC_TT_INEXACT:
|
||||
fsr |= FPC_IF;
|
||||
if ((fsr & FPC_IEN) == 0)
|
||||
user_trap = FPC_TT_NONE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
printf( "res = "); print_op(res); printf("\n");
|
||||
}
|
||||
#endif
|
||||
store_result(res);
|
||||
}
|
||||
state->PC = BUF_TO_UADDR(buf);
|
||||
}
|
||||
SET_FSR(ofsr);
|
||||
state->FSR = fsr;
|
||||
return user_trap;
|
||||
}
|
129
sys/arch/pc532/fpu/ieee_handler.h
Normal file
129
sys/arch/pc532/fpu/ieee_handler.h
Normal file
@ -0,0 +1,129 @@
|
||||
/* $NetBSD: ieee_handler.h,v 1.1 1996/04/04 06:36:20 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: ieee_handler.h
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* Prototypes for entry points. Customization for in kernel version
|
||||
* or unix signal handler version.
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
#ifndef _IEEE_HANDLER_H_
|
||||
#define _IEEE_HANDLER_H_
|
||||
|
||||
#if defined(KERNEL) || defined(_KERNEL)
|
||||
#ifdef MACH
|
||||
|
||||
#include <ns532/thread.h>
|
||||
#include <mach/vm_param.h>
|
||||
#include "mach_kdb.h"
|
||||
#if MACH_KDB
|
||||
#define DEBUG
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
struct ns532_saved_state *regs;
|
||||
struct ns532_fp_state *fps;
|
||||
} state;
|
||||
|
||||
#define LREGBASE(s) ((vm_offset_t) (s)->fps)
|
||||
#define LREGOFFSET(n) offsetof(struct ns532_fp_state, regs.l.l ## n)
|
||||
#define FREGBASE(s) ((vm_offset_t) (s)->fps)
|
||||
#define FREGOFFSET(n) offsetof(struct ns532_fp_state, regs.f.f ## n)
|
||||
#define REGBASE(s) ((vm_offset_t) (s)->regs)
|
||||
#define REGOFFSET(n) offsetof(struct ns532_saved_state, r ## n)
|
||||
|
||||
#define FSR fps->fsr
|
||||
#define FP regs->fp
|
||||
#define SP regs->usp
|
||||
#define SB regs->sb
|
||||
#define PC regs->pc
|
||||
#define PSR regs->psr
|
||||
|
||||
#elif defined(__NetBSD__) /* MACH */
|
||||
#include <sys/param.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/user.h>
|
||||
|
||||
typedef struct proc state;
|
||||
|
||||
#define LREGBASE(s) ((vm_offset_t) (s)->p_addr->u_pcb.pcb_freg)
|
||||
#define LREGOFFSET(n) (n * sizeof(double))
|
||||
#define FREGBASE(s) ((vm_offset_t) (s)->p_addr->u_pcb.pcb_freg)
|
||||
#define FREGOFFSET(n) ((n & ~1) * sizeof(double) + (n & 1) * sizeof(float))
|
||||
#define REGBASE(s) ((vm_offset_t) (s)->p_md.md_regs)
|
||||
#define REGOFFSET(n) offsetof(struct reg, r_r ## n)
|
||||
|
||||
#define FSR p_addr->u_pcb.pcb_fsr
|
||||
#define FP p_md.md_regs->r_fp
|
||||
#define SP p_md.md_regs->r_sp
|
||||
#define SB p_md.md_regs->r_sb
|
||||
#define PC p_md.md_regs->r_pc
|
||||
#define PSR p_md.md_regs->r_psr
|
||||
|
||||
#define PSR_N PSL_N
|
||||
#define PSR_Z PSL_Z
|
||||
#define PSR_L PSL_L
|
||||
|
||||
#else /* __NetBSD__ */
|
||||
#error OS unsupported
|
||||
#endif /* __NetBSD__ */
|
||||
#else /* KERNEL || _KERNEL */
|
||||
#include <signal.h>
|
||||
|
||||
struct fstate {
|
||||
unsigned int fsr;
|
||||
union {
|
||||
struct { double l0, l2, l4, l6, l1, l3, l5, l7;} l;
|
||||
struct { float f0, f1, f2, f3, f4, f5, f6, f7;} f;
|
||||
} regs;
|
||||
};
|
||||
|
||||
struct ns532_combined_state {
|
||||
struct sigcontext *scp;
|
||||
struct fstate fs;
|
||||
};
|
||||
|
||||
typedef struct ns532_combined_state state;
|
||||
|
||||
#define LREG(REG) fs.regs.l.l ## REG
|
||||
#define LREGBASE(s) ((vm_offset_t) &(s)->fs)
|
||||
#define LREGOFFSET(n) offsetof(struct fstate, regs.l.l ## n)
|
||||
#define FREGBASE(s) ((vm_offset_t) &(s)->fs)
|
||||
#define FREGOFFSET(n) offsetof(struct fstate, regs.f.f ## n)
|
||||
#define REGBASE(s) ((vm_offset_t) (s)->scp)
|
||||
#define REGOFFSET(n) offsetof(struct sigcontext, sc_reg[n])
|
||||
#define FSR fs.fsr
|
||||
#define FP scp->sc_fp
|
||||
#define SP scp->sc_sp
|
||||
#define SB scp->sc_sb
|
||||
#define PC scp->sc_pc
|
||||
#define PSR scp->sc_ps
|
||||
|
||||
int ieee_sig(int sig, int code, struct sigcontext *scp);
|
||||
#endif /* KERNEL */
|
||||
|
||||
int ieee_handle_exception(state *state);
|
||||
|
||||
#endif /* _IEEE_HANDLER_H_ */
|
158
sys/arch/pc532/fpu/ieee_internal.h
Normal file
158
sys/arch/pc532/fpu/ieee_internal.h
Normal file
@ -0,0 +1,158 @@
|
||||
/* $NetBSD: ieee_internal.h,v 1.1 1996/04/04 06:36:22 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: ieee_internal.h
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* Prototypes and structure definitions internal to the ieee exception
|
||||
* handling package.
|
||||
*
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
#ifndef _IEEE_INTERNAL_H_
|
||||
#define _IEEE_INTERNAL_H_
|
||||
#include "ieee_handler.h"
|
||||
#include "fpu_status.h"
|
||||
|
||||
#ifdef DEBUG
|
||||
extern int ieee_handler_debug;
|
||||
#define DP(n, format, args...) if (ieee_handler_debug >= n) printf(format, ## args)
|
||||
#else
|
||||
#define DP(n, format, args...)
|
||||
#endif
|
||||
|
||||
enum format { fmt9, fmt11, fmt12};
|
||||
#define XOPCODE(fmt, opcode) ((opcode) << 2 | (fmt))
|
||||
#define MOVF XOPCODE(fmt11, 1)
|
||||
#define MOVLF XOPCODE(fmt9, 2)
|
||||
#define MOVFL XOPCODE(fmt9, 3)
|
||||
#define MOVIF XOPCODE(fmt9, 0)
|
||||
#define ROUNDFI XOPCODE(fmt9, 4)
|
||||
#define TRUNCFI XOPCODE(fmt9, 5)
|
||||
#define FLOORFI XOPCODE(fmt9, 7)
|
||||
#define ADDF XOPCODE(fmt11, 0)
|
||||
#define SUBF XOPCODE(fmt11, 4)
|
||||
#define MULF XOPCODE(fmt11, 12)
|
||||
#define DIVF XOPCODE(fmt11, 8)
|
||||
#define NEGF XOPCODE(fmt11, 5)
|
||||
#define ABSF XOPCODE(fmt11, 13)
|
||||
#define SCALBF XOPCODE(fmt12, 4)
|
||||
#define LOGBF XOPCODE(fmt12, 5)
|
||||
#define DOTF XOPCODE(fmt12, 3)
|
||||
#define POLYF XOPCODE(fmt12, 2)
|
||||
#define CMPF XOPCODE(fmt11, 2)
|
||||
#define LFSR XOPCODE(fmt9, 1)
|
||||
#define SFSR XOPCODE(fmt9, 6)
|
||||
|
||||
union t_conv {
|
||||
double d;
|
||||
float f;
|
||||
struct {
|
||||
unsigned int mantissa2:32;
|
||||
unsigned int mantissa:20;
|
||||
unsigned int exp:11;
|
||||
unsigned int sign :1;
|
||||
} d_bits;
|
||||
struct {
|
||||
unsigned int mantissa:23;
|
||||
unsigned int exp:8;
|
||||
unsigned int sign :1;
|
||||
} f_bits;
|
||||
signed char c;
|
||||
short s;
|
||||
int i;
|
||||
};
|
||||
|
||||
/* These assume "double" interpretation of the union is valid */
|
||||
#define ISNAN(data) ((data).d_bits.exp == 0x7ff && \
|
||||
((data).d_bits.mantissa != 0 || (data).d_bits.mantissa2 != 0))
|
||||
|
||||
#define ISQNAN(data) ((data).d_bits.exp == 0x7ff && \
|
||||
((data).d_bits.mantissa & 0x80000) != 0)
|
||||
|
||||
#define ISSNAN(data) ((data).d_bits.exp == 0x7ff && \
|
||||
((data).d_bits.mantissa & 0x80000) == 0 && \
|
||||
((data).d_bits.mantissa != 0 || (data).d_bits.mantissa2 != 0))
|
||||
|
||||
#define ISINFTY(data) ((data).d_bits.exp == 0x7ff && (data).d_bits.mantissa == 0 && \
|
||||
(data).d_bits.mantissa2 == 0)
|
||||
|
||||
#define ISDENORM(data) ((data).d_bits.exp == 0 && ((data).d_bits.mantissa != 0 || (data).d_bits.mantissa2 != 0))
|
||||
|
||||
#define ISZERO(data) ((data).d_bits.exp == 0 && (data).d_bits.mantissa == 0 && (data).d_bits.mantissa2 == 0)
|
||||
|
||||
#define EXP_DBIAS 1023
|
||||
|
||||
#define EXP_FBIAS 127
|
||||
|
||||
enum op_type {op_type_float, op_type_int};
|
||||
|
||||
enum op_class {op_class_read, op_class_write, op_class_rmw, op_class_addr};
|
||||
|
||||
enum op_where_tag { op_where_register, op_where_memory, op_where_immediate };
|
||||
|
||||
static const union t_conv infty = {d_bits: { sign: 0, exp: 0x7ff, mantissa: 0, mantissa2: 0}};
|
||||
|
||||
static const union t_conv snan = {d_bits: { sign: 0, exp: 0x7ff, mantissa: 0x40000, mantissa2: 0}};
|
||||
|
||||
static const union t_conv qnan = {d_bits: { sign: 0, exp: 0x7ff, mantissa: 0x80000, mantissa2: 0}};
|
||||
|
||||
struct operand {
|
||||
enum op_type type;
|
||||
enum op_class class;
|
||||
struct {
|
||||
enum op_where_tag tag;
|
||||
vm_offset_t addr;
|
||||
} where;
|
||||
char size;
|
||||
union t_conv data;
|
||||
};
|
||||
|
||||
|
||||
int ieee_undfl(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state);
|
||||
|
||||
int ieee_ovfl(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state);
|
||||
|
||||
int ieee_dze(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state);
|
||||
|
||||
int ieee_invop(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state);
|
||||
|
||||
int ieee_add(double data1, double *data2);
|
||||
|
||||
int ieee_mul(double data1, double *data2);
|
||||
|
||||
int ieee_div(double data1, double *data2);
|
||||
|
||||
int ieee_dot(double data1, double data2, double *data3);
|
||||
|
||||
void ieee_cmp(double data1, double data2, state *status);
|
||||
|
||||
int ieee_normalize(union t_conv *data);
|
||||
|
||||
int ieee_scalb(double data1, double *data2);
|
||||
|
||||
#endif /* _IEEE_INTERNAL_H_ */
|
294
sys/arch/pc532/fpu/ieee_invop.c
Normal file
294
sys/arch/pc532/fpu/ieee_invop.c
Normal file
@ -0,0 +1,294 @@
|
||||
/* $NetBSD: ieee_invop.c,v 1.1 1996/04/04 06:36:25 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: ieee_invop.c
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* Handle operations which generated reserved operand traps.
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
#include "ieee_internal.h"
|
||||
#include <machine/psl.h>
|
||||
#include <limits.h>
|
||||
|
||||
static int nan_2(union t_conv data1, union t_conv *data2)
|
||||
{
|
||||
int nans = (ISNAN(data1)? 1: 0) + (ISNAN(*data2)? 2: 0);
|
||||
switch (nans) {
|
||||
case 0:
|
||||
return 0;
|
||||
case 1:
|
||||
*data2 = data1;
|
||||
break;
|
||||
case 2:
|
||||
break;
|
||||
case 3:
|
||||
if((data1.d_bits.mantissa > data2->d_bits.mantissa)
|
||||
|| (data1.d_bits.mantissa == data1.d_bits.mantissa
|
||||
&& data1.d_bits.mantissa2 > data2->d_bits.mantissa2)) {
|
||||
*data2 = data1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int add_iv (struct operand *op1, struct operand *op2)
|
||||
{
|
||||
int inftys;
|
||||
int ret = FPC_TT_NONE;
|
||||
if(nan_2(op1->data, &op2->data)) {
|
||||
return ret;
|
||||
}
|
||||
inftys = (ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0);
|
||||
switch (inftys) {
|
||||
case 0:
|
||||
break;
|
||||
case 1:
|
||||
op2->data = op1->data;
|
||||
return ret;
|
||||
case 2:
|
||||
return ret;
|
||||
case 3:
|
||||
if(op1->data.d_bits.sign != op2->data.d_bits.sign)
|
||||
op2->data = qnan;
|
||||
return ret;
|
||||
}
|
||||
/* Must be subnormals */
|
||||
return ieee_add(op1->data.d, &op2->data.d);
|
||||
}
|
||||
|
||||
static int div_iv (struct operand *op1, struct operand *op2)
|
||||
{
|
||||
int inftys, sign1, sign2;
|
||||
int ret = FPC_TT_NONE;
|
||||
if(nan_2(op1->data, &op2->data)) {
|
||||
return ret;
|
||||
}
|
||||
inftys = (ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0);
|
||||
sign1 = op1->data.d_bits.sign;
|
||||
sign2 = op2->data.d_bits.sign;
|
||||
switch (inftys) {
|
||||
case 0:
|
||||
break;
|
||||
case 1: /* n/oo */
|
||||
{
|
||||
op2->data.d = 0.0;
|
||||
op2->data.d_bits.sign = sign1 ^ sign2;
|
||||
return ret;
|
||||
}
|
||||
case 2: /* oo/n */
|
||||
op2->data.d_bits.sign = sign1 ^ sign2;
|
||||
return ret;
|
||||
case 3:
|
||||
op2->data = qnan;
|
||||
return ret;
|
||||
}
|
||||
/* Must be subnormals */
|
||||
return ieee_div(op1->data.d, &op2->data.d);
|
||||
}
|
||||
|
||||
static int mul_iv (struct operand *op1, struct operand *op2)
|
||||
{
|
||||
int inftys, sign1, sign2;
|
||||
int ret = FPC_TT_NONE;
|
||||
if(nan_2(op1->data, &op2->data)) {
|
||||
return ret;
|
||||
}
|
||||
inftys = (ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0);
|
||||
sign1 = op1->data.d_bits.sign;
|
||||
sign2 = op2->data.d_bits.sign;
|
||||
switch (inftys) {
|
||||
case 0:
|
||||
break;
|
||||
case 1: /* oo * n */
|
||||
{
|
||||
op2->data = ISZERO(op1->data)? qnan: op1->data;
|
||||
op2->data.d_bits.sign = sign1 ^ sign2;
|
||||
return ret;
|
||||
}
|
||||
case 2: /* n * oo */
|
||||
case 3: /* oo * oo */
|
||||
op2->data.d_bits.sign = sign1 ^ sign2;
|
||||
return ret;
|
||||
}
|
||||
/* Must be subnormals */
|
||||
return ieee_mul(op1->data.d, &op2->data.d);
|
||||
}
|
||||
|
||||
static int dot_iv (struct operand *op1, struct operand *op2, struct operand *op3)
|
||||
{
|
||||
int inftys;
|
||||
int ret = FPC_TT_NONE;
|
||||
union t_conv t = op2->data;
|
||||
if(nan_2(op1->data, &t)) {
|
||||
if(nan_2(t, &op3->data))
|
||||
return ret;
|
||||
}
|
||||
inftys = ((ISINFTY(op1->data)? 1: 0) + (ISINFTY(op2->data)? 2:0)
|
||||
+ (ISINFTY(op3->data)? 4: 0));
|
||||
switch (inftys) {
|
||||
case 0:
|
||||
break;
|
||||
case 1: case 2: case 3: /* oo * n + m or n * oo + m or oo * oo + m */
|
||||
op3->data = op2->data;
|
||||
return mul_iv(op1, op3);
|
||||
case 4: /* n * m + oo */
|
||||
return ret;
|
||||
case 5: case 6: case 7:
|
||||
{
|
||||
struct operand t = *op2;
|
||||
mul_iv(op1, &t);
|
||||
add_iv(&t, op3);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
/* Must be subnormals */
|
||||
return ieee_dot(op1->data.d, op2->data.d, &op3->data.d);
|
||||
}
|
||||
|
||||
static int poly_iv (struct operand *op1, struct operand *op2, struct operand *op3)
|
||||
{
|
||||
int ret;
|
||||
struct operand t = *op2;
|
||||
ret = dot_iv(op3, op1, &t);
|
||||
*op3 = t;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int round_iv (struct operand *op1, struct operand *op2, int xopcode)
|
||||
{
|
||||
int ret = FPC_TT_NONE;
|
||||
if(ISNAN(op1->data)) {
|
||||
/* XXX */
|
||||
op2->data.i = 0;
|
||||
return FPC_TT_INVOP; /* Need a special code */
|
||||
}
|
||||
else if (ISINFTY(op1->data)) {
|
||||
op2->data.i = op1->data.d_bits.sign? INT_MIN: INT_MAX;
|
||||
} else {
|
||||
/* Must be a denorm */
|
||||
op2->data.i = 0;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int scalb_iv (struct operand *op1, struct operand *op2)
|
||||
{
|
||||
int ret = FPC_TT_NONE;
|
||||
if(nan_2(op1->data, &op2->data)) {
|
||||
return ret;
|
||||
}
|
||||
return ieee_scalb(op1->data.d, &op2->data.d);
|
||||
}
|
||||
|
||||
static int logb_iv (struct operand *op1, struct operand *op2)
|
||||
{
|
||||
int ret = FPC_TT_NONE;
|
||||
if (ISNAN(op1->data))
|
||||
op2->data = op1->data;
|
||||
else if(ISINFTY(op1->data))
|
||||
op2->data = infty;
|
||||
else {
|
||||
/* Is a denormal */
|
||||
union t_conv t = op1->data;
|
||||
int norm = ieee_normalize(&t);
|
||||
op2->data.d = t.d_bits.exp + norm;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void cmp_iv(struct operand *op1, struct operand *op2, state *state)
|
||||
{
|
||||
state->PSR &= ~(PSR_N | PSR_Z | PSR_L);
|
||||
|
||||
if (ISNAN(op1->data) || ISNAN(op2->data)) {
|
||||
return;
|
||||
}
|
||||
ieee_cmp(op1->data.d, op2->data.d, state);
|
||||
return;
|
||||
}
|
||||
|
||||
int ieee_invop(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state)
|
||||
{
|
||||
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:
|
||||
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:
|
||||
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;
|
||||
}
|
||||
}
|
||||
state->FSR = fsr;
|
||||
return user_trap;
|
||||
}
|
104
sys/arch/pc532/fpu/ieee_ovfl.c
Normal file
104
sys/arch/pc532/fpu/ieee_ovfl.c
Normal file
@ -0,0 +1,104 @@
|
||||
/* $NetBSD: ieee_ovfl.c,v 1.1 1996/04/04 06:36:27 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: ieee_ovfl.c
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* Handle operations which generated overflow traps.
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
#include "ieee_internal.h"
|
||||
#include <limits.h>
|
||||
|
||||
int ieee_ovfl(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state)
|
||||
{
|
||||
int user_trap = FPC_TT_NONE;
|
||||
unsigned int fsr = state->FSR;
|
||||
|
||||
fsr |= FPC_OVF;
|
||||
if (fsr & FPC_OVE) {
|
||||
/* Users trap handler will fix it */
|
||||
user_trap = FPC_TT_OVFL;
|
||||
}
|
||||
else {
|
||||
/* If destination is float or double, set to +- Infty, else
|
||||
* if byte, word or long, set to max/min int.
|
||||
*/
|
||||
int sign1 = op1->data.d_bits.sign;
|
||||
int sign2 = op2->data.d_bits.sign;
|
||||
switch(xopcode) {
|
||||
case NEGF:
|
||||
sign1 ^= 1;
|
||||
/* Fall through */
|
||||
case MOVF:
|
||||
case MOVLF:
|
||||
case MOVFL:
|
||||
op2->data = infty;
|
||||
op2->data.d_bits.sign = sign1;
|
||||
break;
|
||||
case CMPF:
|
||||
/* Can't happen */
|
||||
break;
|
||||
case SUBF:
|
||||
sign1 ^= 1;
|
||||
/* Fall through */
|
||||
case ADDF:
|
||||
/* Overflow can only happen if both operands are same sign */
|
||||
op2->data = infty;
|
||||
op2->data.d_bits.sign = sign2;
|
||||
break;
|
||||
case MULF:
|
||||
case DIVF:
|
||||
op2->data = infty;
|
||||
op2->data.d_bits.sign = sign1 ^ sign2;
|
||||
break;
|
||||
case ROUNDFI:
|
||||
case TRUNCFI:
|
||||
case FLOORFI:
|
||||
op2->data.i = sign1? INT_MIN: INT_MAX;
|
||||
break;
|
||||
case SCALBF:
|
||||
op2->data = infty;
|
||||
op2->data.d_bits.sign = sign1;
|
||||
break;
|
||||
case LOGBF:
|
||||
op2->data = infty;
|
||||
op2->data.d_bits.sign = ISZERO(op1->data)? 1: 0;
|
||||
break;
|
||||
case DOTF:
|
||||
(void) ieee_dot(op1->data.d, op2->data.d, &f0_op->data.d);
|
||||
break;
|
||||
case POLYF:
|
||||
{
|
||||
union t_conv t;
|
||||
t = op2->data;
|
||||
(void) ieee_dot(f0_op->data.d, op1->data.d, &t.d);
|
||||
f0_op->data = t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state->FSR = fsr;
|
||||
return user_trap;
|
||||
}
|
429
sys/arch/pc532/fpu/ieee_subnormal.c
Normal file
429
sys/arch/pc532/fpu/ieee_subnormal.c
Normal file
@ -0,0 +1,429 @@
|
||||
/* $NetBSD: ieee_subnormal.c,v 1.1 1996/04/04 06:36:30 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: ieee_subnormal.c
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* Handle operations which generated underflow traps. Subnormal
|
||||
* (denormalized numbers) are generated as required.
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
#include "ieee_internal.h"
|
||||
#include <machine/psl.h>
|
||||
|
||||
/* Return bit pos numbered from lsb 0 to 31. Returns 31 if no bit is set */
|
||||
static int find_msb(unsigned int t) {
|
||||
static const int b_mask[] = {
|
||||
0xffff0000,
|
||||
0xff00ff00,
|
||||
0xf0f0f0f0,
|
||||
0xcccccccc,
|
||||
0xaaaaaaaa };
|
||||
int i;
|
||||
int pos = 31;
|
||||
int bit_incr = 16; /* Half no of bits in int */
|
||||
for (i = 0; i < 5; i++, bit_incr /= 2) {
|
||||
if(t & b_mask[i]) {
|
||||
t &= b_mask[i];
|
||||
}
|
||||
else {
|
||||
pos -= bit_incr;
|
||||
t &= ~b_mask[i];
|
||||
}
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
static int leading_zeros(union t_conv *data)
|
||||
{
|
||||
unsigned int t;
|
||||
if ((t = data->d_bits.mantissa)) {
|
||||
return 19 - find_msb(t);
|
||||
}
|
||||
else if ((t = data->d_bits.mantissa2)) {
|
||||
return 51 - find_msb(t);
|
||||
}
|
||||
else
|
||||
return 52;
|
||||
}
|
||||
|
||||
static void lshift_mantissa(union t_conv *data, int n)
|
||||
{
|
||||
unsigned long t[2];
|
||||
t[1] = data->d_bits.mantissa;
|
||||
t[0] = data->d_bits.mantissa2;
|
||||
*(unsigned long long *) t <<= n;
|
||||
data->d_bits.mantissa = t[1];
|
||||
data->d_bits.mantissa2 = t[0];
|
||||
}
|
||||
|
||||
|
||||
static void rshift_mantissa(union t_conv *data, int n)
|
||||
{
|
||||
unsigned long t[2];
|
||||
t[1] = data->d_bits.mantissa | 0x100000;
|
||||
t[0] = data->d_bits.mantissa2;
|
||||
*(unsigned long long *) t >>= n;
|
||||
data->d_bits.mantissa = t[1];
|
||||
data->d_bits.mantissa2 = t[0];
|
||||
}
|
||||
|
||||
/* After this, the data is a normal double and the returned value is
|
||||
* such that:
|
||||
* union t_conv t;
|
||||
* t = *data;
|
||||
* norm = normalize(&t);
|
||||
* 2**norm * t.d == data->d;
|
||||
*
|
||||
* Assume data is not already normalized.
|
||||
*/
|
||||
int ieee_normalize(union t_conv *data)
|
||||
{
|
||||
int norm;
|
||||
if(data->d_bits.exp != 0)
|
||||
return 0;
|
||||
norm = leading_zeros(data) + 1; /* plus one for the implied bit */
|
||||
data->d_bits.exp = 1;
|
||||
lshift_mantissa(data, norm);
|
||||
return -norm;
|
||||
}
|
||||
|
||||
/* Divide by 2**n producing a denormalized no if necessary */
|
||||
static void denormalize(union t_conv *data, int n)
|
||||
{
|
||||
int exp = data->d_bits.exp;
|
||||
if(exp > n)
|
||||
exp -= n;
|
||||
else if (exp <= n) {
|
||||
rshift_mantissa(data, n - exp + 1); /* plus 1 for the implied bit */
|
||||
exp = 0;
|
||||
}
|
||||
data->d_bits.exp = exp;
|
||||
}
|
||||
|
||||
static int scale_and_check(union t_conv *d, int scale)
|
||||
{
|
||||
int exp;
|
||||
exp = d->d_bits.exp - scale;
|
||||
if(exp >= 0x7ff) {
|
||||
/* Overflow */
|
||||
d->d_bits.exp = 0x7ff;
|
||||
d->d_bits.mantissa = 0;
|
||||
d->d_bits.mantissa2 = 0; /* XXX sig */
|
||||
return FPC_TT_OVFL;
|
||||
}
|
||||
if(exp <= 0) {
|
||||
/* Underflow */
|
||||
denormalize(d, scale); /* XXX sig */
|
||||
return FPC_TT_UNDFL;
|
||||
}
|
||||
d->d_bits.exp = exp;
|
||||
return FPC_TT_NONE;
|
||||
}
|
||||
|
||||
|
||||
/* Add two doubles, not caring if one or both is a de-norm.
|
||||
* Strategy: First scale and normalize operands so the addition
|
||||
* can't overflow or underflow, then do a normal floating point
|
||||
* addition, then scale back and possibly denormalize.
|
||||
*/
|
||||
int ieee_add(double data1, double *data2)
|
||||
{
|
||||
union t_conv d1 = (union t_conv) data1;
|
||||
union t_conv *d2 = (union t_conv *) data2;
|
||||
int scale;
|
||||
int norm1 = ieee_normalize(&d1);
|
||||
int norm2 = ieee_normalize(d2);
|
||||
int exp1 = d1.d_bits.exp + norm1;
|
||||
int exp2 = d2->d_bits.exp + norm2;
|
||||
if(exp1 > exp2) {
|
||||
scale = EXP_DBIAS - exp1;
|
||||
exp1 = EXP_DBIAS;
|
||||
exp2 += scale;
|
||||
}
|
||||
else {
|
||||
scale = EXP_DBIAS - exp2;
|
||||
exp2 = EXP_DBIAS;
|
||||
exp1 += scale;
|
||||
}
|
||||
if(exp1 > 0) {
|
||||
d1.d_bits.exp = exp1;
|
||||
if (exp2 > 0) {
|
||||
d2->d_bits.exp = exp2;
|
||||
d2->d += d1.d;
|
||||
}
|
||||
else {
|
||||
d2->d = d1.d;
|
||||
}
|
||||
}
|
||||
else {
|
||||
d2->d_bits.exp = exp2;
|
||||
}
|
||||
return scale_and_check(d2, scale);
|
||||
}
|
||||
|
||||
/* Multiply two doubles, not caring if one or both is a de-norm.
|
||||
* Strategy: First scale and normalize operands so the multiplication
|
||||
* can't overflow or underflow, then do a normal floating point
|
||||
* addition, then scale back and possibly denormalize.
|
||||
*/
|
||||
int ieee_mul(double data1, double *data2)
|
||||
{
|
||||
union t_conv d1 = (union t_conv) data1;
|
||||
union t_conv *d2 = (union t_conv *) data2;
|
||||
int scale;
|
||||
int norm1 = ieee_normalize(&d1);
|
||||
int norm2 = ieee_normalize(d2);
|
||||
int exp1 = d1.d_bits.exp + norm1;
|
||||
int exp2 = d2->d_bits.exp + norm2;
|
||||
d1.d_bits.exp = EXP_DBIAS; /* Add EXP_DBIAS - exp1 */
|
||||
d2->d_bits.exp = EXP_DBIAS;
|
||||
d2->d *= d1.d;
|
||||
scale = EXP_DBIAS - exp1 + EXP_DBIAS - exp2;
|
||||
return scale_and_check(d2, scale);
|
||||
}
|
||||
|
||||
/* Divide d2 by d1, not caring if one or both is a de-norm.
|
||||
* Strategy: First scale and normalize operands so the division
|
||||
* can't overflow or underflow, then do a normal floating point
|
||||
* division, then scale back and possibly denormalize.
|
||||
*/
|
||||
int ieee_div(double data1, double *data2)
|
||||
{
|
||||
union t_conv d1 = (union t_conv) data1;
|
||||
union t_conv *d2 = (union t_conv *) data2;
|
||||
int scale;
|
||||
int norm1 = ieee_normalize(&d1);
|
||||
int norm2 = ieee_normalize(d2);
|
||||
int exp1 = d1.d_bits.exp + norm1;
|
||||
int exp2 = d2->d_bits.exp + norm2;
|
||||
d1.d_bits.exp = EXP_DBIAS; /* Add EXP_DBIAS - exp1 */
|
||||
d2->d_bits.exp = EXP_DBIAS;
|
||||
d2->d /= d1.d;
|
||||
scale = exp1 - exp2;
|
||||
return scale_and_check(d2, scale);
|
||||
}
|
||||
|
||||
/* Add mul-add three doubles d1 * d2 + d3 -> d3, not caring if any a de-norm.
|
||||
* Strategy: First scale and normalize operands so the operations
|
||||
* can't overflow or underflow, then do a normal floating point operation
|
||||
* addition, then scale back and possibly denormalize.
|
||||
*/
|
||||
int ieee_dot(double data1, double data2, double *data3)
|
||||
{
|
||||
union t_conv d1 = (union t_conv) data1;
|
||||
union t_conv d2 = (union t_conv) data2;
|
||||
union t_conv *d3 = (union t_conv *) data3;
|
||||
int scale;
|
||||
int norm1 = ieee_normalize(&d1);
|
||||
int norm2 = ieee_normalize(&d2);
|
||||
int norm3 = ieee_normalize(d3);
|
||||
int exp1 = d1.d_bits.exp + norm1;
|
||||
int exp2 = d2.d_bits.exp + norm2;
|
||||
int exp3 = d3->d_bits.exp + norm3;
|
||||
int exp_prod = exp1 + exp2;
|
||||
if(exp_prod > exp3) {
|
||||
scale = EXP_DBIAS + EXP_DBIAS - exp_prod;
|
||||
exp1 = EXP_DBIAS; /* Add EXP_DBIAS - exp1 */
|
||||
exp2 = EXP_DBIAS;
|
||||
exp3 += scale;
|
||||
}
|
||||
else {
|
||||
scale = EXP_DBIAS - exp3;
|
||||
exp3 = EXP_DBIAS;
|
||||
exp1 = (exp_prod + scale)/2;
|
||||
exp2 = exp_prod + scale - exp1;
|
||||
}
|
||||
|
||||
if(exp1 > 0 && exp2 > 0) {
|
||||
d1.d_bits.exp = exp1;
|
||||
d2.d_bits.exp = exp2;
|
||||
if(exp3 > 0) {
|
||||
d3->d_bits.exp = exp3;
|
||||
d3->d += d1.d * d2.d;
|
||||
}
|
||||
else {
|
||||
d3->d = d1.d * d2.d;
|
||||
}
|
||||
}
|
||||
else {
|
||||
d3->d_bits.exp = exp3;
|
||||
}
|
||||
return scale_and_check(d3, scale);
|
||||
}
|
||||
|
||||
/* Compare the magnitude of two ops.
|
||||
* return: 1 |op1| > |op2|
|
||||
* -1 |op1| < |op2|
|
||||
* 0 |op1| == |op2|
|
||||
*/
|
||||
static int u_cmp(double data1, double data2)
|
||||
{
|
||||
union t_conv d1 = (union t_conv) data1;
|
||||
union t_conv d2 = (union t_conv) data2;
|
||||
int exp1 = d1.d_bits.exp;
|
||||
int exp2 = d2.d_bits.exp;
|
||||
if (exp1 > exp2)
|
||||
return 1;
|
||||
else if (exp1 < exp2)
|
||||
return -1;
|
||||
else if (d1.d_bits.mantissa > d2.d_bits.mantissa)
|
||||
return 1;
|
||||
else if (d1.d_bits.mantissa < d2.d_bits.mantissa)
|
||||
return -1;
|
||||
else if (d1.d_bits.mantissa2 > d2.d_bits.mantissa2)
|
||||
return 1;
|
||||
else if (d1.d_bits.mantissa2 < d2.d_bits.mantissa2)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ieee_cmp(double data1, double data2, state *state)
|
||||
{
|
||||
union t_conv d1 = (union t_conv) data1;
|
||||
union t_conv d2 = (union t_conv) data2;
|
||||
int sign1 = d1.d_bits.sign;
|
||||
int sign2 = d2.d_bits.sign;
|
||||
state->PSR &= ~(PSR_N | PSR_Z | PSR_L);
|
||||
switch(sign2 * 2 + sign1) {
|
||||
case 2: /* op2 is negative op1 is positive */
|
||||
state->PSR |= PSR_N;
|
||||
break;
|
||||
case 1: /* op2 is positive op1 is negative */
|
||||
break;
|
||||
case 0: /* Both ops same sign */
|
||||
case 3:
|
||||
{
|
||||
int cmp = u_cmp(d1.d, d2.d);
|
||||
if(sign1)
|
||||
cmp *= -1;
|
||||
if(cmp > 0)
|
||||
state->PSR |= PSR_N;
|
||||
else if (cmp == 0)
|
||||
state->PSR |= PSR_Z;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
int ieee_scalb(double data1, double *data2)
|
||||
{
|
||||
union t_conv d1 = (union t_conv) data1;
|
||||
union t_conv *d2 = (union t_conv *) data2;
|
||||
int exp2 = d2->d_bits.exp - EXP_DBIAS;
|
||||
int n;
|
||||
if (exp2 > 16) {
|
||||
*d2 = infty;
|
||||
d2->d_bits.sign = d1.d_bits.sign;
|
||||
return FPC_TT_OVFL;
|
||||
}
|
||||
else if (exp2 < -16) {
|
||||
d2->d = 0.0;
|
||||
d2->d_bits.sign = d1.d_bits.sign;
|
||||
return FPC_TT_OVFL;
|
||||
}
|
||||
n = d2->d;
|
||||
*d2 = d1;
|
||||
return scale_and_check(d2, n);
|
||||
}
|
||||
|
||||
/* With no trap, hardware produces zero, which is fast but not
|
||||
* strictly correct. We should always have the hardware trap bit set
|
||||
* and generate denormalized numbers by simulation unless the user
|
||||
* indicates via the FPC_UNDE flag they want to handle it. */
|
||||
|
||||
int ieee_undfl(struct operand *op1, struct operand *op2,
|
||||
struct operand *f0_op, int xopcode, state *state)
|
||||
{
|
||||
unsigned int fsr = state->FSR;
|
||||
int user_trap = FPC_TT_NONE;
|
||||
DP(1, "Underflow trap: xopcode = 0x%x\n", xopcode);
|
||||
if (fsr & FPC_UNDE) {
|
||||
user_trap = FPC_TT_UNDFL;
|
||||
}
|
||||
else {
|
||||
user_trap = FPC_TT_NONE;
|
||||
/* Calculate correct denormal output. The easiest way is to
|
||||
* prescale the operands so they won't underflow, then use the
|
||||
* hardware operation, then post scale.
|
||||
*/
|
||||
|
||||
/* The exact sematics are a bit tricky. Apparently, we should only
|
||||
* set flag if we underflowed *and* there was loss of precision
|
||||
* For now, just set the flag always XXX
|
||||
*/
|
||||
fsr |= FPC_UF;
|
||||
|
||||
switch(xopcode) {
|
||||
case NEGF:
|
||||
op1->data.d_bits.sign ^= 1;
|
||||
/* Fall through */
|
||||
case MOVF:
|
||||
case MOVLF:
|
||||
case MOVFL:
|
||||
op2->data = op1->data;
|
||||
break;
|
||||
case CMPF:
|
||||
ieee_cmp(op1->data.d, op2->data.d, state);
|
||||
break;
|
||||
case SUBF:
|
||||
op1->data.d_bits.sign ^= 1;
|
||||
/* Fall through */
|
||||
case ADDF:
|
||||
user_trap = ieee_add(op1->data.d, &op2->data.d);
|
||||
break;
|
||||
case MULF:
|
||||
user_trap = ieee_mul(op1->data.d, &op2->data.d);
|
||||
break;
|
||||
case DIVF:
|
||||
user_trap = ieee_div(op1->data.d, &op2->data.d);
|
||||
break;
|
||||
case ROUNDFI:
|
||||
case TRUNCFI:
|
||||
case FLOORFI:
|
||||
op2->data.i = 0;
|
||||
break;
|
||||
case SCALBF:
|
||||
user_trap = ieee_scalb(op1->data.d, &op2->data.d);
|
||||
break;
|
||||
case LOGBF:
|
||||
op2->data.d = 0.0;
|
||||
break;
|
||||
case DOTF:
|
||||
user_trap = ieee_dot(op1->data.d, op2->data.d, &f0_op->data.d);
|
||||
break;
|
||||
case POLYF:
|
||||
{
|
||||
union t_conv t = op2->data;
|
||||
user_trap = ieee_dot(f0_op->data.d, op1->data.d, &t.d);
|
||||
f0_op->data = t;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
state->FSR = fsr;
|
||||
return user_trap;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: cpu.h,v 1.15 1996/03/11 20:56:48 phil Exp $ */
|
||||
/* $NetBSD: cpu.h,v 1.16 1996/04/04 06:36:36 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
@ -75,9 +75,9 @@
|
||||
|
||||
#define clockframe intrframe
|
||||
|
||||
#define CLKF_USERMODE(framep) USERMODE((framep)->if_psr)
|
||||
#define CLKF_USERMODE(framep) USERMODE((framep)->if_regs.r_psr)
|
||||
#define CLKF_BASEPRI(framep) ((framep)->if_pl == imask[IPL_ZERO])
|
||||
#define CLKF_PC(framep) ((framep)->if_pc)
|
||||
#define CLKF_PC(framep) ((framep)->if_regs.r_pc)
|
||||
#define CLKF_INTR(frame) (0) /* XXX should have an interrupt stack */
|
||||
|
||||
/*
|
||||
|
65
sys/arch/pc532/include/fpu.h
Normal file
65
sys/arch/pc532/include/fpu.h
Normal file
@ -0,0 +1,65 @@
|
||||
/* $NetBSD: fpu.h,v 1.1 1996/04/04 06:36:41 phil Exp $ */
|
||||
|
||||
/*
|
||||
* IEEE floating point support for NS32081 and NS32381 fpus.
|
||||
* Copyright (c) 1995 Ian Dall
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission to use, copy, modify and distribute this software and its
|
||||
* documentation is hereby granted, provided that both the copyright
|
||||
* notice and this permission notice appear in all copies of the
|
||||
* software, derivative works or modified versions, and any portions
|
||||
* thereof, and that both notices appear in supporting documentation.
|
||||
*
|
||||
* IAN DALL ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" CONDITION.
|
||||
* IAN DALL DISCLAIMS ANY LIABILITY OF ANY KIND FOR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
|
||||
*/
|
||||
/*
|
||||
* File: fpu_status.h
|
||||
* Author: Ian Dall
|
||||
* Date: November 1995
|
||||
*
|
||||
* FPU status register definitions
|
||||
*
|
||||
* HISTORY
|
||||
* 14-Dec-95 Ian Dall (Ian.Dall@dsto.defence.gov.au)
|
||||
* First release.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _NS532_FPU_H_
|
||||
#define _NS532_FPU_H_
|
||||
/*
|
||||
* Control register
|
||||
*/
|
||||
#define FPC_RMB 0x00010000 /* register modify bit */
|
||||
#define FPC_SWF 0x0000fe00 /* reserved for software */
|
||||
#define FPC_RM 0x00000180 /* rounding mode */
|
||||
#define FPC_RM_NEAREST 0x00000000 /* round to nearest */
|
||||
#define FPC_RM_TOZERO 0x00000080 /* round towards zero */
|
||||
#define FPC_RM_TOPOS 0x00000100 /* round towards +infinity */
|
||||
#define FPC_RM_TONEG 0x00000180 /* round towards -infinity */
|
||||
#define FPC_IF 0x00000040 /* inexact result flag */
|
||||
#define FPC_IEN 0x00000020 /* inexact result trap enable */
|
||||
#define FPC_UF 0x00000010 /* underflow flag (else 0) */
|
||||
#define FPC_UEN 0x00000008 /* underflow trap enable */
|
||||
#define FPC_TT 0x00000007 /* trap type */
|
||||
#define FPC_TT_NONE 0x00000000 /* no exceptional condition */
|
||||
#define FPC_TT_UNDFL 0x00000001 /* underflow */
|
||||
#define FPC_TT_OVFL 0x00000002 /* overflow */
|
||||
#define FPC_TT_DIV0 0x00000003 /* divide by zero */
|
||||
#define FPC_TT_ILL 0x00000004 /* illegal instruction */
|
||||
#define FPC_TT_INVOP 0x00000005 /* invalid operation */
|
||||
#define FPC_TT_INEXACT 0x00000006 /* inexact result */
|
||||
|
||||
/* Bits in the SWF field used for software emulation */
|
||||
#define FPC_OVE 0x200 /* Overflow enable */
|
||||
#define FPC_OVF 0x400 /* Overflow flag */
|
||||
#define FPC_IVE 0x800 /* Invalid enable */
|
||||
#define FPC_IVF 0x1000 /* Invalid flag */
|
||||
#define FPC_DZE 0x2000 /* Divide by zero enable */
|
||||
#define FPC_DZF 0x4000 /* Divide by zero flag */
|
||||
#define FPC_UNDE 0x8000 /* Soft Underflow enable, requires FPC_UEN */
|
||||
|
||||
#endif /* _NS532_FPU_H_ */
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: frame.h,v 1.5 1996/02/01 00:03:27 phil Exp $ */
|
||||
/* $NetBSD: frame.h,v 1.6 1996/04/04 06:36:43 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
@ -38,8 +38,8 @@
|
||||
* @(#)frame.h 5.2 (Berkeley) 1/18/91
|
||||
*/
|
||||
|
||||
#ifndef _MACHINE_FRAME_H_
|
||||
#define _MACHINE_FRAME_H_
|
||||
#ifndef _NS532_FRAME_H_
|
||||
#define _NS532_FRAME_H_
|
||||
|
||||
#include <sys/signal.h>
|
||||
#include <machine/reg.h>
|
||||
@ -56,14 +56,7 @@ struct trapframe {
|
||||
long tf_msr; /* For abt. 0 for others. */
|
||||
long tf_tear; /* For abt. 0 for others. */
|
||||
long tf_trapno;
|
||||
long tf_reg[8]; /* R7 - R0 from enter */
|
||||
long tf_usp;
|
||||
long tf_sb;
|
||||
long tf_fp; /* From enter */
|
||||
/* below portion defined in 532 hardware */
|
||||
long tf_pc;
|
||||
u_short tf_mod; /* Not used in direct excption mode. */
|
||||
u_short tf_psr;
|
||||
struct reg tf_regs;
|
||||
};
|
||||
|
||||
/* Interrupt stack frame */
|
||||
@ -71,14 +64,7 @@ struct trapframe {
|
||||
struct intrframe {
|
||||
long if_vec;
|
||||
long if_pl; /* the "processor level" for clock. */
|
||||
long if_reg[8]; /* R7 - R0 from enter */
|
||||
long if_usp;
|
||||
long if_sb;
|
||||
long if_fp; /* From enter */
|
||||
/* below portion defined in 532 hardware */
|
||||
long if_pc;
|
||||
u_short if_mod; /* Not used in direct excption mode. */
|
||||
u_short if_psr;
|
||||
struct reg if_regs;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -86,14 +72,7 @@ struct intrframe {
|
||||
*/
|
||||
|
||||
struct syscframe {
|
||||
long sf_reg[8]; /* R7 - R0 from enter */
|
||||
long sf_usp;
|
||||
long sf_sb;
|
||||
long sf_fp; /* From enter */
|
||||
/* below portion defined in 532 hardware */
|
||||
long sf_pc;
|
||||
u_short sf_mod; /* Not used in direct excption mode. */
|
||||
u_short sf_psr;
|
||||
struct reg sf_regs;
|
||||
};
|
||||
|
||||
/*
|
||||
@ -101,7 +80,11 @@ struct syscframe {
|
||||
*/
|
||||
struct switchframe {
|
||||
long sf_pl;
|
||||
long sf_reg[5];
|
||||
long sf_r7;
|
||||
long sf_r6;
|
||||
long sf_r5;
|
||||
long sf_r4;
|
||||
long sf_r3;
|
||||
long sf_fp;
|
||||
int sf_pc;
|
||||
};
|
||||
@ -117,4 +100,4 @@ struct sigframe {
|
||||
struct sigcontext sf_sc;
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif /* _NS532_FRAME_H_ */
|
||||
|
@ -1,3 +1,5 @@
|
||||
/* $NetBSD: ieeefp.h,v 1.2 1996/04/04 06:36:45 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Written by J.T. Conklin, Apr 28, 1995
|
||||
* Public domain.
|
||||
@ -6,8 +8,12 @@
|
||||
#ifndef _PC532_IEEEFP_H_
|
||||
#define _PC532_IEEEFP_H_
|
||||
|
||||
/* defined just to keep prototypes in machine independant header happy. */
|
||||
typedef int fp_except;
|
||||
#define FP_X_IMP 0x0020 /* imprecise (loss of precision) */
|
||||
#define FP_X_OFL 0x0200 /* overflow exception */
|
||||
#define FP_X_INV 0x0800 /* invalid operation exception */
|
||||
#define FP_X_DZ 0x2000 /* divide-by-zero exception */
|
||||
#define FP_X_UFL 0x8000 /* underflow exception */
|
||||
|
||||
typedef enum {
|
||||
FP_RN=0, /* round to nearest representable number */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: pcb.h,v 1.7 1996/02/01 00:03:32 phil Exp $ */
|
||||
/* $NetBSD: pcb.h,v 1.8 1996/04/04 06:36:47 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
@ -48,21 +48,9 @@
|
||||
*
|
||||
*/
|
||||
|
||||
/* The registers as pushed from a trap/interrupt with the
|
||||
exception of USP and SB, and they are placed by software. */
|
||||
struct on_stack {
|
||||
long pcb_reg[8]; /* R7 - R0 from enter */
|
||||
long pcb_usp; /* User stack pointer, by software. */
|
||||
long pcb_sb; /* Static Base pointer, by software. */
|
||||
long pcb_fp; /* From enter */
|
||||
long pcb_pc; /* From the trap/interrupt */
|
||||
u_short pcb_mod; /* in direct exception mode. */
|
||||
u_short pcb_psr;
|
||||
};
|
||||
|
||||
struct pcb {
|
||||
/* Put in a pointer to the trap/interrupt frame. */
|
||||
struct on_stack *pcb_onstack;
|
||||
struct reg *pcb_onstack;
|
||||
|
||||
/* Floating point stuff */
|
||||
long pcb_fsr; /* fpu status reg */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: proc.h,v 1.4 1994/10/26 08:24:37 cgd Exp $ */
|
||||
/* $NetBSD: proc.h,v 1.5 1996/04/04 06:36:50 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1991 Regents of the University of California.
|
||||
@ -35,14 +35,14 @@
|
||||
* @(#)proc.h 7.1 (Berkeley) 5/15/91
|
||||
*/
|
||||
|
||||
#ifndef _MACHINE_PROC_H_
|
||||
#define _MACHINE_PROC_H_
|
||||
#ifndef _NS532_PROC_H_
|
||||
#define _NS532_PROC_H_
|
||||
|
||||
/*
|
||||
* Machine-dependent part of the proc structure for the pc532.
|
||||
*/
|
||||
struct mdproc {
|
||||
int *md_regs; /* pointer to regs on the stack */
|
||||
struct reg *md_regs; /* pointer to regs on the stack */
|
||||
};
|
||||
|
||||
#endif
|
||||
#endif /* _NS532_PROC_H_ */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: reg.h,v 1.10 1995/08/29 22:40:59 phil Exp $ */
|
||||
/* $NetBSD: reg.h,v 1.11 1996/04/04 06:36:52 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
@ -64,7 +64,7 @@
|
||||
#define REG_R7 (0)
|
||||
|
||||
#define REG_SP (8)
|
||||
#define REG_SB (9)
|
||||
#define REG_SB (9)
|
||||
#define REG_FP (10)
|
||||
#define REG_PC (11)
|
||||
#define REG_PSR (12)
|
||||
@ -85,7 +85,7 @@ struct reg {
|
||||
int r_sb;
|
||||
int r_fp;
|
||||
int r_pc;
|
||||
short r_mod;
|
||||
short r_mod; /* This is not set in direct exception mode */
|
||||
short r_psr;
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: types.h,v 1.14 1996/03/28 04:53:17 phil Exp $ */
|
||||
/* $NetBSD: types.h,v 1.15 1996/04/04 06:36:55 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
@ -46,7 +46,7 @@ typedef struct _physadr {
|
||||
} *physadr;
|
||||
|
||||
typedef struct label_t {
|
||||
int val[6];
|
||||
int val[8];
|
||||
} label_t;
|
||||
#endif
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: genassym.c,v 1.10 1996/02/02 19:43:03 mycroft Exp $ */
|
||||
/* $NetBSD: genassym.c,v 1.11 1996/04/04 06:36:59 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1982, 1990 The Regents of the University of California.
|
||||
@ -58,7 +58,7 @@ main()
|
||||
struct vmmeter *vm = 0;
|
||||
struct pcb *pcb = 0;
|
||||
struct sigframe *sigf = 0;
|
||||
struct on_stack *regs = 0;
|
||||
struct reg *regs = 0;
|
||||
struct iv *iv = 0;
|
||||
register unsigned i;
|
||||
|
||||
@ -100,11 +100,11 @@ main()
|
||||
def("PCB_PTB", &pcb->pcb_ptb);
|
||||
def("PCB_ONFAULT", &pcb->pcb_onfault);
|
||||
|
||||
def("ON_STK_SIZE", sizeof(struct on_stack));
|
||||
def("REGS_USP", ®s->pcb_usp);
|
||||
def("REGS_FP", ®s->pcb_fp);
|
||||
def("REGS_SB", ®s->pcb_sb);
|
||||
def("REGS_PSR", ®s->pcb_psr);
|
||||
def("ON_STK_SIZE", sizeof(struct reg));
|
||||
def("REGS_USP", ®s->r_sp);
|
||||
def("REGS_FP", ®s->r_fp);
|
||||
def("REGS_SB", ®s->r_sb);
|
||||
def("REGS_PSR", ®s->r_psr);
|
||||
|
||||
def("SIGF_HANDLER", &sigf->sf_handler);
|
||||
def("SIGF_SC", &sigf->sf_sc);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: intr.c,v 1.6 1996/01/31 21:33:53 phil Exp $ */
|
||||
/* $NetBSD: intr.c,v 1.7 1996/04/04 06:37:00 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 Matthias Pfaller.
|
||||
@ -204,7 +204,7 @@ badhard(struct intrframe *frame)
|
||||
bad_count++;
|
||||
if (bad_count < 5)
|
||||
printf("Unknown hardware interrupt: vec=%d pc=0x%08x psr=0x%04x cpl=0x%08x\n",
|
||||
frame->if_vec, frame->if_pc, frame->if_psr, frame->if_pl);
|
||||
frame->if_vec, frame->if_regs.r_pc, frame->if_regs.r_psr, frame->if_pl);
|
||||
|
||||
if (bad_count == 5)
|
||||
printf("Too many unknown hardware interrupts, quitting reporting them.\n");
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: locore.s,v 1.35 1996/03/28 05:00:06 phil Exp $ */
|
||||
/* $NetBSD: locore.s,v 1.36 1996/04/04 06:37:02 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993 Philip A. Nelson.
|
||||
@ -31,8 +31,6 @@
|
||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* locore.s
|
||||
*
|
||||
* locore.s,v 1.2 1993/09/13 07:26:47 phil Exp
|
||||
*/
|
||||
|
||||
/*
|
||||
@ -57,6 +55,7 @@
|
||||
#include <machine/pte.h>
|
||||
#include <machine/trap.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/jmpbuf.h>
|
||||
|
||||
/*
|
||||
* PTmap is recursive pagemap at top of virtual address space.
|
||||
@ -138,7 +137,7 @@ ENTRY(proc_trampoline)
|
||||
cmpqd 0,tos
|
||||
br rei
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* Burn N microseconds in a delay loop.
|
||||
@ -160,7 +159,7 @@ ENTRY(delay) /* bsr 2 cycles; 80 ns */
|
||||
acbd -1,r0,1b /* 5 cycles; 200 ns */
|
||||
2: ret 0 /* 4 cycles; 160 ns */
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* Signal trampoline; copied to top of user stack.
|
||||
@ -177,7 +176,7 @@ ENTRY(sigcode)
|
||||
.globl _esigcode
|
||||
_esigcode:
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* The following primitives are used to fill and copy regions of memory.
|
||||
@ -283,7 +282,7 @@ ENTRY(bzero)
|
||||
acbd -1,r0,7b
|
||||
br 3b
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* The following primitives are used to copy data in and out of the user's
|
||||
@ -610,7 +609,49 @@ ENTRY(fusubail)
|
||||
movqd -1,r0
|
||||
ret 0
|
||||
|
||||
/*****************************************************************************/
|
||||
/***************************************************************************/
|
||||
|
||||
/*
|
||||
* setjmp(label_t *);
|
||||
* longjmp(label_t *);
|
||||
*
|
||||
* The kernel versions of setjmp and longjmp.
|
||||
* r0-r2 and sb are not saved.
|
||||
*/
|
||||
|
||||
ENTRY(setjmp)
|
||||
movd S_ARG0,r0
|
||||
|
||||
sprd sp,0(r0) /* save stackpointer */
|
||||
sprd fp,4(r0) /* save framepointer */
|
||||
movd 0(sp),8(r0) /* save return address */
|
||||
|
||||
movd r3,12(r0) /* save registers r3-r7 */
|
||||
movd r4,16(r0)
|
||||
movd r5,20(r0)
|
||||
movd r6,24(r0)
|
||||
movd r7,28(r0)
|
||||
|
||||
movqd 0,r0 /* return(0) */
|
||||
ret 0
|
||||
|
||||
ENTRY(longjmp)
|
||||
movd S_ARG0,r0
|
||||
|
||||
lprd sp,0(r0) /* restore stackpointer */
|
||||
lprd fp,4(r0) /* restore framepointer */
|
||||
movd 8(r0),0(sp) /* modify return address */
|
||||
|
||||
movd 12(r0),r3 /* restore registers r3-r7 */
|
||||
movd 16(r0),r4
|
||||
movd 20(r0),r5
|
||||
movd 24(r0),r6
|
||||
movd 28(r0),r7
|
||||
|
||||
movqd 1,r0 /* return(1) */
|
||||
ret 0
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* The following primitives manipulate the run queues.
|
||||
@ -840,7 +881,7 @@ switch_return:
|
||||
exit [r3,r4,r5,r6,r7]
|
||||
ret 0
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* FPU handling.
|
||||
@ -898,7 +939,7 @@ ENTRY(restore_fpu_context)
|
||||
movl PCB_F7(r0),f7
|
||||
9: ret 0
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* Trap and fault vector routines
|
||||
@ -1094,7 +1135,7 @@ _inttab:
|
||||
.long trap_dbg
|
||||
.long trap_reserved
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* void *ram_size(void *start);
|
||||
@ -1239,7 +1280,7 @@ highagain:
|
||||
/* Include all other .s files. */
|
||||
#include "bcopy.s"
|
||||
|
||||
/*****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
/*
|
||||
* vmstat -i uses the following labels and trap_int even increments the
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: machdep.c,v 1.45 1996/02/15 08:39:27 phil Exp $ */
|
||||
/* $NetBSD: machdep.c,v 1.46 1996/04/04 06:37:05 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996 Matthias Pfaller.
|
||||
@ -84,6 +84,7 @@ static char rcsid[] = "/b/source/CVS/src/sys/arch/pc532/pc532/machdep.c,v 1.2 19
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/pmap.h>
|
||||
|
||||
/*
|
||||
@ -360,7 +361,7 @@ sendsig(catcher, sig, mask, code)
|
||||
u_long code;
|
||||
{
|
||||
register struct proc *p = curproc;
|
||||
register int *regs;
|
||||
register struct reg *regs;
|
||||
register struct sigframe *fp;
|
||||
struct sigacts *ps = p->p_sigacts;
|
||||
int oonstack;
|
||||
@ -378,7 +379,7 @@ sendsig(catcher, sig, mask, code)
|
||||
ps->ps_sigstk.ss_size - sizeof(struct sigframe));
|
||||
ps->ps_sigstk.ss_flags |= SS_ONSTACK;
|
||||
} else {
|
||||
fp = (struct sigframe *)regs[REG_SP] - 1;
|
||||
fp = (struct sigframe *)regs->r_sp - 1;
|
||||
}
|
||||
|
||||
if ((unsigned)fp <= (unsigned)p->p_vmspace->vm_maxsaddr + MAXSSIZ - ctob(p->p_vmspace->vm_ssize))
|
||||
@ -406,18 +407,25 @@ sendsig(catcher, sig, mask, code)
|
||||
*/
|
||||
fp->sf_sc.sc_onstack = oonstack;
|
||||
fp->sf_sc.sc_mask = mask;
|
||||
fp->sf_sc.sc_fp = regs[REG_FP];
|
||||
fp->sf_sc.sc_sp = regs[REG_SP];
|
||||
fp->sf_sc.sc_pc = regs[REG_PC];
|
||||
fp->sf_sc.sc_ps = regs[REG_PSR];
|
||||
fp->sf_sc.sc_sb = regs[REG_SB];
|
||||
bcopy (regs, fp->sf_sc.sc_reg, 8*sizeof(int));
|
||||
fp->sf_sc.sc_fp = regs->r_fp;
|
||||
fp->sf_sc.sc_sp = regs->r_sp;
|
||||
fp->sf_sc.sc_pc = regs->r_pc;
|
||||
fp->sf_sc.sc_ps = regs->r_psr;
|
||||
fp->sf_sc.sc_sb = regs->r_sb;
|
||||
fp->sf_sc.sc_reg[REG_R7] = regs->r_r7;
|
||||
fp->sf_sc.sc_reg[REG_R6] = regs->r_r6;
|
||||
fp->sf_sc.sc_reg[REG_R5] = regs->r_r5;
|
||||
fp->sf_sc.sc_reg[REG_R4] = regs->r_r4;
|
||||
fp->sf_sc.sc_reg[REG_R3] = regs->r_r3;
|
||||
fp->sf_sc.sc_reg[REG_R2] = regs->r_r2;
|
||||
fp->sf_sc.sc_reg[REG_R1] = regs->r_r1;
|
||||
fp->sf_sc.sc_reg[REG_R0] = regs->r_r0;
|
||||
|
||||
/*
|
||||
* Build context to run handler in.
|
||||
*/
|
||||
regs[REG_SP] = (int)fp;
|
||||
regs[REG_PC] = (int)(((char *)PS_STRINGS) - (esigcode - sigcode));
|
||||
regs->r_sp = (int)fp;
|
||||
regs->r_pc = (int)(((char *)PS_STRINGS) - (esigcode - sigcode));
|
||||
}
|
||||
|
||||
/*
|
||||
@ -440,7 +448,7 @@ sys_sigreturn(p, v, retval)
|
||||
syscallarg(struct sigcontext *) sigcntxp;
|
||||
} */ *uap = v;
|
||||
register struct sigcontext *scp;
|
||||
register int *regs = p->p_md.md_regs;
|
||||
register struct reg *regs = p->p_md.md_regs;
|
||||
|
||||
/*
|
||||
* The trampoline code hands us the context.
|
||||
@ -454,7 +462,7 @@ sys_sigreturn(p, v, retval)
|
||||
/*
|
||||
* Check for security violations.
|
||||
*/
|
||||
if (((scp->sc_ps ^ regs[REG_PSR]) & PSL_USERSTATIC) != 0)
|
||||
if (((scp->sc_ps ^ regs->r_psr) & PSL_USERSTATIC) != 0)
|
||||
return (EINVAL);
|
||||
|
||||
if (scp->sc_onstack & 01)
|
||||
@ -466,19 +474,26 @@ sys_sigreturn(p, v, retval)
|
||||
/*
|
||||
* Restore signal context.
|
||||
*/
|
||||
regs[REG_FP] = scp->sc_fp;
|
||||
regs[REG_SP] = scp->sc_sp;
|
||||
regs[REG_PC] = scp->sc_pc;
|
||||
regs[REG_PSR] = scp->sc_ps;
|
||||
regs[REG_SB] = scp->sc_sb;
|
||||
bcopy (scp->sc_reg, regs, 8*sizeof(int));
|
||||
regs->r_fp = scp->sc_fp;
|
||||
regs->r_sp = scp->sc_sp;
|
||||
regs->r_pc = scp->sc_pc;
|
||||
regs->r_psr = scp->sc_ps;
|
||||
regs->r_sb = scp->sc_sb;
|
||||
regs->r_r7 = scp->sc_reg[REG_R7];
|
||||
regs->r_r6 = scp->sc_reg[REG_R6];
|
||||
regs->r_r5 = scp->sc_reg[REG_R5];
|
||||
regs->r_r4 = scp->sc_reg[REG_R4];
|
||||
regs->r_r3 = scp->sc_reg[REG_R3];
|
||||
regs->r_r2 = scp->sc_reg[REG_R2];
|
||||
regs->r_r1 = scp->sc_reg[REG_R1];
|
||||
regs->r_r0 = scp->sc_reg[REG_R0];
|
||||
|
||||
return(EJUSTRETURN);
|
||||
}
|
||||
|
||||
int waittime = -1;
|
||||
struct pcb dumppcb;
|
||||
struct on_stack dumppcb_onstack;
|
||||
struct reg dumppcb_regs;
|
||||
|
||||
void
|
||||
boot(howto)
|
||||
@ -532,15 +547,15 @@ boot(howto)
|
||||
sprd(sp, dumppcb.pcb_ksp);
|
||||
sprd(fp, dumppcb.pcb_kfp);
|
||||
smr(ptb0, dumppcb.pcb_ptb);
|
||||
dumppcb.pcb_onstack = &dumppcb_onstack;
|
||||
sprw(psr, dumppcb_onstack.pcb_psr);
|
||||
sprw(mod, dumppcb_onstack.pcb_mod);
|
||||
lprd(sp, &dumppcb_onstack.pcb_mod);
|
||||
dumppcb.pcb_onstack = &dumppcb_regs;
|
||||
sprw(psr, dumppcb_regs.r_psr);
|
||||
sprw(mod, dumppcb_regs.r_mod);
|
||||
lprd(sp, &dumppcb_regs.r_mod);
|
||||
__asm __volatile("bsr 1f; 1: enter [r0,r1,r2,r3,r4,r5,r6,r7],8");
|
||||
lprd(sp, dumppcb.pcb_ksp);
|
||||
lprd(fp, dumppcb.pcb_kfp);
|
||||
sprd(sb, dumppcb_onstack.pcb_sb);
|
||||
sprd(usp, dumppcb_onstack.pcb_usp);
|
||||
sprd(sb, dumppcb_regs.r_sb);
|
||||
sprd(usp, dumppcb_regs.r_sp);
|
||||
ei();
|
||||
dumpsys();
|
||||
}
|
||||
@ -751,21 +766,20 @@ setregs(p, pack, stack, retval)
|
||||
u_long stack;
|
||||
register_t *retval;
|
||||
{
|
||||
struct on_stack *r = (struct on_stack *)p->p_md.md_regs;
|
||||
struct reg *r = p->p_md.md_regs;
|
||||
struct pcb *pcbp = &p->p_addr->u_pcb;
|
||||
extern struct proc *fpu_proc;
|
||||
|
||||
if (p == fpu_proc)
|
||||
fpu_proc = 0;
|
||||
|
||||
r->pcb_usp = stack;
|
||||
r->pcb_fp = 0;
|
||||
r->pcb_pc = pack->ep_entry;
|
||||
r->pcb_psr = PSL_USERSET;
|
||||
bzero(r->pcb_reg, sizeof(r->pcb_reg));
|
||||
r->pcb_reg[0] = (int)PS_STRINGS;
|
||||
bzero(r, sizeof(*r));
|
||||
r->r_sp = stack;
|
||||
r->r_pc = pack->ep_entry;
|
||||
r->r_psr = PSL_USERSET;
|
||||
r->r_r7 = (int)PS_STRINGS;
|
||||
|
||||
pcbp->pcb_fsr = 0;
|
||||
pcbp->pcb_fsr = FPC_UEN;
|
||||
bzero(pcbp->pcb_freg, sizeof(pcbp->pcb_freg));
|
||||
|
||||
retval[1] = 0;
|
||||
@ -985,7 +999,7 @@ init532()
|
||||
|
||||
/* Construct an empty syscframe for proc0. */
|
||||
curpcb = &proc0.p_addr->u_pcb;
|
||||
curpcb->pcb_onstack = (struct on_stack *)
|
||||
curpcb->pcb_onstack = (struct reg *)
|
||||
((u_int)proc0.p_addr + USPACE) - 1;
|
||||
|
||||
/* Switch to proc0's stack. */
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: process_machdep.c,v 1.9 1996/01/31 21:34:02 phil Exp $ */
|
||||
/* $NetBSD: process_machdep.c,v 1.10 1996/04/04 06:37:08 phil Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1993 The Regents of the University of California.
|
||||
@ -75,13 +75,6 @@
|
||||
|
||||
extern struct proc *fpu_proc;
|
||||
|
||||
static inline struct reg *
|
||||
process_regs(p)
|
||||
struct proc *p;
|
||||
{
|
||||
return ((struct reg *) p->p_md.md_regs);
|
||||
}
|
||||
|
||||
int
|
||||
process_read_regs(p, regs)
|
||||
struct proc *p;
|
||||
@ -89,7 +82,7 @@ process_read_regs(p, regs)
|
||||
{
|
||||
struct reg *pregs;
|
||||
|
||||
pregs = process_regs(p);
|
||||
pregs = p->p_md.md_regs;
|
||||
if (pregs == NULL)
|
||||
return (EIO);
|
||||
|
||||
@ -104,7 +97,7 @@ process_write_regs(p, regs)
|
||||
{
|
||||
struct reg *pregs;
|
||||
|
||||
pregs = process_regs(p);
|
||||
pregs = p->p_md.md_regs;
|
||||
if (pregs == NULL)
|
||||
return (EIO);
|
||||
|
||||
@ -154,7 +147,7 @@ process_sstep(p, sstep)
|
||||
{
|
||||
struct reg *pregs;
|
||||
|
||||
pregs = process_regs(p);
|
||||
pregs = p->p_md.md_regs;
|
||||
if (pregs == NULL)
|
||||
return (EIO);
|
||||
|
||||
@ -173,7 +166,7 @@ process_set_pc(p, addr)
|
||||
{
|
||||
struct reg *pregs;
|
||||
|
||||
pregs = process_regs(p);
|
||||
pregs = p->p_md.md_regs;
|
||||
if (pregs == NULL)
|
||||
return (EIO);
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: trap.c,v 1.15 1996/03/28 05:00:16 phil Exp $ */
|
||||
/* $NetBSD: trap.c,v 1.16 1996/04/04 06:37:12 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996 Matthias Pfaller. All rights reserved.
|
||||
@ -63,6 +63,7 @@
|
||||
#include <machine/cpu.h>
|
||||
#include <machine/cpufunc.h>
|
||||
#include <machine/psl.h>
|
||||
#include <machine/fpu.h>
|
||||
#include <machine/reg.h>
|
||||
#include <machine/trap.h>
|
||||
|
||||
@ -173,10 +174,10 @@ trap(frame)
|
||||
}
|
||||
#endif
|
||||
|
||||
if (USERMODE(frame.tf_psr)) {
|
||||
if (USERMODE(frame.tf_regs.r_psr)) {
|
||||
type |= T_USER;
|
||||
sticks = p->p_sticks;
|
||||
p->p_md.md_regs = (int *)&(frame.tf_reg);
|
||||
p->p_md.md_regs = &frame.tf_regs;
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
@ -193,7 +194,7 @@ trap(frame)
|
||||
printf("unknown trap %d", frame.tf_trapno);
|
||||
printf(" in %s mode\n", (type & T_USER) ? "user" : "supervisor");
|
||||
printf("trap type=%d, pc=0x%x, tear=0x%x, msr=0x%x\n",
|
||||
type, frame.tf_pc, frame.tf_tear, frame.tf_msr);
|
||||
type, frame.tf_regs.r_pc, frame.tf_tear, frame.tf_msr);
|
||||
|
||||
panic("trap");
|
||||
/*NOTREACHED*/
|
||||
@ -245,17 +246,26 @@ trap(frame)
|
||||
goto out;
|
||||
|
||||
case T_SLAVE | T_USER: {
|
||||
int fsr;
|
||||
#ifdef MATH_IEEE
|
||||
int rv;
|
||||
if ((rv = math_ieee(&frame)) == 0) {
|
||||
if (frame.tf_psr & PSL_T)
|
||||
int fsr, sig = SIGFPE;
|
||||
pcb = &p->p_addr->u_pcb;
|
||||
save_fpu_context(pcb);
|
||||
switch(ieee_handle_exception(p)) {
|
||||
case FPC_TT_NONE:
|
||||
restore_fpu_context(pcb);
|
||||
if (frame.tf_regs.r_psr & PSL_T) {
|
||||
type = T_TRC | T_USER;
|
||||
goto trace;
|
||||
}
|
||||
return;
|
||||
case FPC_TT_ILL:
|
||||
sig = SIGILL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
restore_fpu_context(pcb);
|
||||
sfsr(fsr);
|
||||
trapsignal(p, SIGFPE, 0x80000000 | fsr);
|
||||
trapsignal(p, sig, 0x80000000 | fsr);
|
||||
goto out;
|
||||
}
|
||||
|
||||
@ -360,7 +370,7 @@ trap(frame)
|
||||
if (type == T_ABT) {
|
||||
if (pcb->pcb_onfault != 0) {
|
||||
copyfault:
|
||||
frame.tf_pc = (int)curpcb->pcb_onfault;
|
||||
frame.tf_regs.r_pc = (int)curpcb->pcb_onfault;
|
||||
return;
|
||||
}
|
||||
printf("vm_fault(%x, %x, %x, 0) -> %x\n",
|
||||
@ -376,7 +386,7 @@ trap(frame)
|
||||
case T_BPT | T_USER: /* breakpoint instruction */
|
||||
case T_DBG | T_USER: /* debug trap */
|
||||
trace:
|
||||
frame.tf_psr &= ~PSL_P;
|
||||
frame.tf_regs.r_psr &= ~PSL_P;
|
||||
trapsignal(p, SIGTRAP, type &~ T_USER);
|
||||
break;
|
||||
|
||||
@ -394,7 +404,7 @@ trap(frame)
|
||||
if ((type & T_USER) == 0)
|
||||
return;
|
||||
out:
|
||||
userret(p, frame.tf_pc, sticks);
|
||||
userret(p, frame.tf_regs.r_pc, sticks);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -416,18 +426,18 @@ syscall(frame)
|
||||
u_quad_t sticks;
|
||||
|
||||
cnt.v_syscall++;
|
||||
if (!USERMODE(frame.sf_psr))
|
||||
if (!USERMODE(frame.sf_regs.r_psr))
|
||||
panic("syscall");
|
||||
p = curproc;
|
||||
sticks = p->p_sticks;
|
||||
p->p_md.md_regs = (int *) &frame.sf_reg;
|
||||
opc = frame.sf_pc++;
|
||||
code = frame.sf_reg[REG_R0];
|
||||
p->p_md.md_regs = &frame.sf_regs;
|
||||
opc = frame.sf_regs.r_pc++;
|
||||
code = frame.sf_regs.r_r0;
|
||||
|
||||
nsys = p->p_emul->e_nsysent;
|
||||
callp = p->p_emul->e_sysent;
|
||||
|
||||
params = (caddr_t)frame.sf_usp + sizeof(int);
|
||||
params = (caddr_t)frame.sf_regs.r_sp + sizeof(int);
|
||||
|
||||
switch (code) {
|
||||
case SYS_syscall:
|
||||
@ -469,7 +479,7 @@ syscall(frame)
|
||||
if (error)
|
||||
goto bad;
|
||||
rval[0] = 0;
|
||||
rval[1] = frame.sf_reg[REG_R1];
|
||||
rval[1] = frame.sf_regs.r_r1;
|
||||
error = (*callp->sy_call)(p, args, rval);
|
||||
switch (error) {
|
||||
case 0:
|
||||
@ -478,15 +488,15 @@ syscall(frame)
|
||||
* if this is a child returning from fork syscall.
|
||||
*/
|
||||
p = curproc;
|
||||
frame.sf_reg[REG_R0] = rval[0];
|
||||
frame.sf_reg[REG_R1] = rval[1];
|
||||
frame.sf_psr &= ~PSL_C; /* carry bit */
|
||||
frame.sf_regs.r_r0 = rval[0];
|
||||
frame.sf_regs.r_r1 = rval[1];
|
||||
frame.sf_regs.r_psr &= ~PSL_C; /* carry bit */
|
||||
break;
|
||||
case ERESTART:
|
||||
/*
|
||||
* Just reset the pc to the SVC instruction.
|
||||
*/
|
||||
frame.sf_pc = opc;
|
||||
frame.sf_regs.r_pc = opc;
|
||||
break;
|
||||
case EJUSTRETURN:
|
||||
/* nothing to do */
|
||||
@ -495,15 +505,15 @@ syscall(frame)
|
||||
bad:
|
||||
if (p->p_emul->e_errno)
|
||||
error = p->p_emul->e_errno[error];
|
||||
frame.sf_reg[REG_R0] = error;
|
||||
frame.sf_psr |= PSL_C; /* carry bit */
|
||||
frame.sf_regs.r_r0 = error;
|
||||
frame.sf_regs.r_psr |= PSL_C; /* carry bit */
|
||||
break;
|
||||
}
|
||||
|
||||
#ifdef SYSCALL_DEBUG
|
||||
scdebug_ret(p, code, error, rval);
|
||||
#endif
|
||||
userret(p, frame.sf_pc, sticks);
|
||||
userret(p, frame.sf_regs.r_pc, sticks);
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(p, KTR_SYSRET))
|
||||
ktrsysret(p->p_tracep, code, error, rval[0]);
|
||||
@ -515,10 +525,10 @@ child_return(p, frame)
|
||||
struct proc *p;
|
||||
struct syscframe frame;
|
||||
{
|
||||
frame.sf_reg[REG_R0] = 0;
|
||||
frame.sf_psr &= ~PSL_C;
|
||||
frame.sf_regs.r_r0 = 0;
|
||||
frame.sf_regs.r_psr &= ~PSL_C;
|
||||
|
||||
userret(p, frame.sf_pc, 0);
|
||||
userret(p, frame.sf_regs.r_pc, 0);
|
||||
#ifdef KTRACE
|
||||
if (KTRPOINT(p, KTR_SYSRET))
|
||||
ktrsysret(p->p_tracep, SYS_fork, 0, 0);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: vm_machdep.c,v 1.14 1996/02/05 20:33:37 christos Exp $ */
|
||||
/* $NetBSD: vm_machdep.c,v 1.15 1996/04/04 06:37:15 phil Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1996 Matthias Pfaller.
|
||||
@ -78,7 +78,7 @@ cpu_fork(p1, p2)
|
||||
|
||||
/* Copy curpcb (which is presumably p1's PCB) to p2. */
|
||||
*pcb = p1->p_addr->u_pcb;
|
||||
pcb->pcb_onstack = (struct on_stack *)((u_int)p2->p_addr + USPACE) - 1;
|
||||
pcb->pcb_onstack = (struct reg *)((u_int)p2->p_addr + USPACE) - 1;
|
||||
*pcb->pcb_onstack = *p1->p_addr->u_pcb.pcb_onstack;
|
||||
/* If p1 is holding the FPU, update the FPU context of p2. */
|
||||
if (fpu_proc == p1)
|
||||
@ -90,12 +90,12 @@ cpu_fork(p1, p2)
|
||||
* through rei().
|
||||
*/
|
||||
tf = (struct syscframe *)((u_int)p2->p_addr + USPACE) - 1;
|
||||
p2->p_md.md_regs = (int *)&(tf->sf_reg);
|
||||
p2->p_md.md_regs = &tf->sf_regs;
|
||||
sf = (struct switchframe *)tf - 1;
|
||||
sf->sf_pc = (long) proc_trampoline;
|
||||
sf->sf_fp = (long) &tf->sf_fp;
|
||||
sf->sf_reg[REG_R3] = (long) child_return;
|
||||
sf->sf_reg[REG_R4] = (long) p2;
|
||||
sf->sf_fp = (long) &tf->sf_regs.r_fp;
|
||||
sf->sf_r3 = (long) child_return;
|
||||
sf->sf_r4 = (long) p2;
|
||||
sf->sf_pl = imask[IPL_ZERO];
|
||||
pcb->pcb_ksp = (long) sf;
|
||||
pcb->pcb_kfp = (long) &sf->sf_fp;
|
||||
@ -123,8 +123,8 @@ cpu_set_kpc(p, pc)
|
||||
pcbp = &p->p_addr->u_pcb;
|
||||
sf = (struct switchframe *) pcbp->pcb_ksp;
|
||||
sf->sf_pc = (long) proc_trampoline;
|
||||
sf->sf_reg[REG_R3] = pc;
|
||||
sf->sf_reg[REG_R4] = (long) p;
|
||||
sf->sf_r3 = pc;
|
||||
sf->sf_r4 = (long) p;
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user