5e: added FPA support
This commit is contained in:
parent
0b22dfd1f6
commit
a4436018f1
6 changed files with 166 additions and 2 deletions
|
@ -19,7 +19,7 @@ enum {
|
||||||
fH = 1<<5,
|
fH = 1<<5,
|
||||||
};
|
};
|
||||||
|
|
||||||
static void
|
void
|
||||||
invalid(u32int instr)
|
invalid(u32int instr)
|
||||||
{
|
{
|
||||||
suicide("undefined instruction %8ux @ %8ux", instr, P->R[15] - 4);
|
suicide("undefined instruction %8ux @ %8ux", instr, P->R[15] - 4);
|
||||||
|
@ -467,6 +467,12 @@ step(void)
|
||||||
syscall();
|
syscall();
|
||||||
else if((instr & (7<<25)) == (4 << 25))
|
else if((instr & (7<<25)) == (4 << 25))
|
||||||
block(instr);
|
block(instr);
|
||||||
|
else if((instr & 0x0E000F00) == 0x0C000100)
|
||||||
|
fpatransfer(instr);
|
||||||
|
else if((instr & 0x0E000F10) == 0x0E000100)
|
||||||
|
fpaoperation(instr);
|
||||||
|
else if((instr & 0x0E000F10) == 0x0E000110)
|
||||||
|
fparegtransfer(instr);
|
||||||
else
|
else
|
||||||
invalid(instr);
|
invalid(instr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,9 @@ struct Process {
|
||||||
Segment *S[SEGNUM]; /* memory */
|
Segment *S[SEGNUM]; /* memory */
|
||||||
u32int R[16]; /* general purpose registers / PC (R15) */
|
u32int R[16]; /* general purpose registers / PC (R15) */
|
||||||
u32int CPSR; /* status register */
|
u32int CPSR; /* status register */
|
||||||
|
|
||||||
|
u32int FPSR;
|
||||||
|
long double F[8];
|
||||||
|
|
||||||
char errbuf[ERRMAX];
|
char errbuf[ERRMAX];
|
||||||
Fd *fd; /* bitmap of OCEXEC files */
|
Fd *fd; /* bitmap of OCEXEC files */
|
||||||
|
|
|
@ -30,3 +30,8 @@ Process *findproc(int);
|
||||||
void donote(char *, ulong);
|
void donote(char *, ulong);
|
||||||
void addnote(char *);
|
void addnote(char *);
|
||||||
void dump(void);
|
void dump(void);
|
||||||
|
void resetfpa(void);
|
||||||
|
void invalid(u32int);
|
||||||
|
void fpatransfer(u32int);
|
||||||
|
void fpaoperation(u32int);
|
||||||
|
void fparegtransfer(u32int);
|
||||||
|
|
148
sys/src/cmd/5e/fpa.c
Normal file
148
sys/src/cmd/5e/fpa.c
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <thread.h>
|
||||||
|
#include <bio.h>
|
||||||
|
#include <mach.h>
|
||||||
|
#include "dat.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
void
|
||||||
|
resetfpa(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
P->FPSR = 0x81000000;
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
P->F[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fpatransfer(u32int instr)
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
fP = 1<<24,
|
||||||
|
fU = 1<<23,
|
||||||
|
fT1 = 1<<22,
|
||||||
|
fW = 1<<21,
|
||||||
|
fL = 1<<20,
|
||||||
|
fT0 = 1<<15,
|
||||||
|
};
|
||||||
|
|
||||||
|
long double *Fd;
|
||||||
|
u32int *Rn, addr;
|
||||||
|
int off;
|
||||||
|
void *targ;
|
||||||
|
Segment *seg;
|
||||||
|
|
||||||
|
Rn = P->R + ((instr >> 16) & 15);
|
||||||
|
Fd = P->F + ((instr >> 12) & 7);
|
||||||
|
if(Rn == P->R + 15)
|
||||||
|
invalid(instr);
|
||||||
|
off = (instr & 255) * 4;
|
||||||
|
if(!(instr & fU))
|
||||||
|
off = -off;
|
||||||
|
addr = *Rn;
|
||||||
|
if(instr & fP)
|
||||||
|
addr += off;
|
||||||
|
targ = vaddr(addr, 8, &seg);
|
||||||
|
switch(instr & (fT0 | fT1 | fL)) {
|
||||||
|
case 0: *(float *) targ = *Fd; break;
|
||||||
|
case fL: *Fd = *(float *) targ; break;
|
||||||
|
case fT0: *(double *) targ = *Fd; break;
|
||||||
|
case fT0 | fL: *Fd = *(double *) targ; break;
|
||||||
|
default: invalid(instr);
|
||||||
|
}
|
||||||
|
segunlock(seg);
|
||||||
|
if(!(instr & fP))
|
||||||
|
addr += off;
|
||||||
|
if(instr & fW)
|
||||||
|
*Rn = addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
static long double
|
||||||
|
fpasecop(u32int instr)
|
||||||
|
{
|
||||||
|
switch(instr & 15) {
|
||||||
|
case 8: return 0.0; break;
|
||||||
|
case 9: return 1.0; break;
|
||||||
|
case 10: return 2.0; break;
|
||||||
|
case 11: return 3.0; break;
|
||||||
|
case 12: return 4.0; break;
|
||||||
|
case 13: return 5.0; break;
|
||||||
|
case 14: return 0.5; break;
|
||||||
|
case 15: return 10.0; break;
|
||||||
|
}
|
||||||
|
return P->F[instr & 7];
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fpaoperation(u32int instr)
|
||||||
|
{
|
||||||
|
long double *Fn, *Fd, op, op2, res;
|
||||||
|
int prec, opc;
|
||||||
|
|
||||||
|
Fn = P->F + ((instr >> 16) & 7);
|
||||||
|
Fd = P->F + ((instr >> 12) & 7);
|
||||||
|
op2 = fpasecop(instr);
|
||||||
|
op = *Fn;
|
||||||
|
prec = ((instr >> 7) & 1) | ((instr >> 18) & 2);
|
||||||
|
opc = ((instr >> 20) & 15) | ((instr >> 11) & 16);
|
||||||
|
switch(opc) {
|
||||||
|
case 0: res = op + op2; break;
|
||||||
|
case 1: res = op * op2; break;
|
||||||
|
case 2: res = op - op2; break;
|
||||||
|
case 3: res = op2 - op; break;
|
||||||
|
case 4: res = op / op2; break;
|
||||||
|
case 5: res = op2 / op; break;
|
||||||
|
case 16: res = op2; break;
|
||||||
|
case 17: res = - op2; break;
|
||||||
|
case 18: res = fabs(op2); break;
|
||||||
|
case 19: res = (vlong) op2; break;
|
||||||
|
case 20: res = sqrt(op2); break;
|
||||||
|
default: sysfatal("unimplemented FPA operation %#x @ %8ux", opc, P->R[15] - 4);
|
||||||
|
}
|
||||||
|
switch(prec) {
|
||||||
|
case 0: *Fd = (float) res; break;
|
||||||
|
case 1: *Fd = (double) res; break;
|
||||||
|
case 2: *Fd = res; break;
|
||||||
|
default: invalid(instr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
fparegtransfer(u32int instr)
|
||||||
|
{
|
||||||
|
u32int *Rd;
|
||||||
|
long tmp;
|
||||||
|
long double *Fn, op, op2;
|
||||||
|
|
||||||
|
Rd = P->R + ((instr >> 12) & 15);
|
||||||
|
Fn = P->F + ((instr >> 16) & 7);
|
||||||
|
op = fpasecop(instr);
|
||||||
|
if(Rd == P->R + 15) {
|
||||||
|
op2 = *Fn;
|
||||||
|
switch((instr >> 21) & 7) {
|
||||||
|
case 4: break;
|
||||||
|
case 5: op = - op; break;
|
||||||
|
default: invalid(instr);
|
||||||
|
}
|
||||||
|
if(op2 < op)
|
||||||
|
P->CPSR = (P->CPSR & ~FLAGS) | flN;
|
||||||
|
else if(op2 >= op) {
|
||||||
|
P->CPSR = (P->CPSR & ~FLAGS) | flC;
|
||||||
|
if(op2 == op)
|
||||||
|
P->CPSR |= flZ;
|
||||||
|
} else
|
||||||
|
P->CPSR = (P->CPSR & ~FLAGS) | flV;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(instr & (1<<3))
|
||||||
|
invalid(instr);
|
||||||
|
switch((instr >> 20) & 15) {
|
||||||
|
case 0: *Fn = *(long *) Rd; break;
|
||||||
|
case 1: tmp = op; *Rd = tmp; break;
|
||||||
|
case 2: P->FPSR = *Rd; break;
|
||||||
|
case 3: *Rd = P->FPSR; break;
|
||||||
|
default: invalid(instr);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
</$objtype/mkfile
|
</$objtype/mkfile
|
||||||
|
|
||||||
TARG=5e
|
TARG=5e
|
||||||
OFILES=5e.$O seg.$O proc.$O util.$O arm.$O sys.$O fs.$O
|
OFILES=5e.$O seg.$O proc.$O util.$O arm.$O sys.$O fs.$O fpa.$O
|
||||||
HFILES=dat.h fns.h
|
HFILES=dat.h fns.h
|
||||||
BIN=/$objtype/bin
|
BIN=/$objtype/bin
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ initproc(void)
|
||||||
plist.next = P;
|
plist.next = P;
|
||||||
P->prev = &plist;
|
P->prev = &plist;
|
||||||
P->next = &plist;
|
P->next = &plist;
|
||||||
|
resetfpa();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -202,6 +203,7 @@ loadtext(char *file, int argc, char **argv)
|
||||||
close(fd);
|
close(fd);
|
||||||
fdclear(P->fd);
|
fdclear(P->fd);
|
||||||
initstack(argc, argv);
|
initstack(argc, argv);
|
||||||
|
resetfpa();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue