177cbace73
this provides basic console support using the ARC bios routines theu uartarcs driver. and has native seeq ethernet driver which was written by reading the 2ed devseq driver as i have no documentation on the hardware. mmu and trap code is based on the routerboard kernel.
269 lines
4.4 KiB
C
269 lines
4.4 KiB
C
#include "u.h"
|
|
#include "../port/lib.h"
|
|
#include "mem.h"
|
|
#include "dat.h"
|
|
#include "fns.h"
|
|
#include "ureg.h"
|
|
#include "io.h"
|
|
#include "../port/error.h"
|
|
|
|
enum /* op */
|
|
{
|
|
ABS = 5,
|
|
ADD = 0,
|
|
CVTD = 33,
|
|
CVTS = 32,
|
|
CVTW = 36,
|
|
DIV = 3,
|
|
MOV = 6,
|
|
MUL = 2,
|
|
NEG = 7,
|
|
SUB = 1,
|
|
};
|
|
|
|
static int fpunimp(ulong);
|
|
static ulong branch(Ureg*, ulong);
|
|
|
|
void
|
|
fptrap(Ureg *ur)
|
|
{
|
|
ulong iw, npc;
|
|
|
|
if((up->fpsave.fpstatus&(1<<17)) == 0)
|
|
return;
|
|
|
|
if(ur->cause & (1<<31))
|
|
iw = *(ulong*)(ur->pc+4);
|
|
else
|
|
iw = *(ulong*)ur->pc;
|
|
|
|
if(fpunimp(iw) == 0)
|
|
return;
|
|
|
|
if(ur->cause & (1<<31)){
|
|
npc = branch(ur, up->fpsave.fpstatus);
|
|
if(npc == 0)
|
|
return;
|
|
ur->pc = npc;
|
|
}
|
|
else
|
|
ur->pc += 4;
|
|
|
|
up->fpsave.fpstatus &= ~(1<<17);
|
|
}
|
|
|
|
static void
|
|
unpack(FPsave *f, int fmt, int reg, int *sign, int *exp)
|
|
{
|
|
*sign = 1;
|
|
if(f->reg[reg] & 0x80000000)
|
|
*sign = -1;
|
|
|
|
switch(fmt){
|
|
case 0:
|
|
*exp = ((f->reg[reg]>>23)&0xFF) - ((1<<7)-2);
|
|
break;
|
|
case 1:
|
|
if(reg & 1) /* shouldn't happen */
|
|
reg &= ~1;
|
|
*exp = ((f->reg[reg]>>20)&0x7FF) - ((1<<10)-2);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
zeroreg(FPsave *f, int fmt, int reg, int sign)
|
|
{
|
|
int size;
|
|
|
|
size = 0;
|
|
switch(fmt){
|
|
case 0:
|
|
size = 4;
|
|
break;
|
|
case 1:
|
|
if(reg & 1)
|
|
reg &= ~1;
|
|
size = 8;
|
|
break;
|
|
}
|
|
memset(&f->reg[reg], 0, size);
|
|
if(sign < 0)
|
|
f->reg[reg] |= 0x80000000;
|
|
}
|
|
|
|
static int
|
|
fpunimp(ulong iw)
|
|
{
|
|
int ss, st, sd;
|
|
int es, et, ed;
|
|
int maxe, maxm;
|
|
ulong op, fmt, ft, fs, fd;
|
|
|
|
if((iw>>25) != 0x23)
|
|
return 0;
|
|
op = iw & ((1<<6)-1);
|
|
fmt = (iw>>21) & ((1<<4)-1);
|
|
ft = (iw>>16) & ((1<<5)-1);
|
|
fs = (iw>>11) & ((1<<5)-1);
|
|
fd = (iw>>6) & ((1<<5)-1);
|
|
unpack(&up->fpsave, fmt, fs, &ss, &es);
|
|
unpack(&up->fpsave, fmt, ft, &st, &et);
|
|
ed = 0;
|
|
maxe = 0;
|
|
maxm = 0;
|
|
switch(fmt){
|
|
case 0:
|
|
maxe = 1<<7;
|
|
maxm = 24;
|
|
break;
|
|
case 1:
|
|
maxe = 1<<10;
|
|
maxm = 53;
|
|
break;
|
|
}
|
|
switch(op){
|
|
case ABS:
|
|
up->fpsave.reg[fd] &= ~0x80000000;
|
|
return 1;
|
|
|
|
case NEG:
|
|
up->fpsave.reg[fd] ^= 0x80000000;
|
|
return 1;
|
|
|
|
case SUB:
|
|
st = -st;
|
|
case ADD:
|
|
if(es<-(maxe-maxm) && et<-(maxe-maxm))
|
|
ed = -maxe;
|
|
if(es > et)
|
|
sd = es;
|
|
else
|
|
sd = et;
|
|
break;
|
|
|
|
case DIV:
|
|
et = -et;
|
|
case MUL:
|
|
sd = 1;
|
|
if(ss != st)
|
|
sd = -1;
|
|
ed = es + et;
|
|
break;
|
|
|
|
case CVTS:
|
|
if(fmt != 1)
|
|
return 0;
|
|
fmt = 0; /* convert FROM double TO single */
|
|
maxe = 1<<7;
|
|
ed = es;
|
|
sd = ss;
|
|
break;
|
|
|
|
default: /* probably a compare */
|
|
return 0;
|
|
}
|
|
if(ed <= -(maxe-5)){ /* guess: underflow */
|
|
zeroreg(&up->fpsave, fmt, fd, sd);
|
|
/* Set underflow exception and sticky */
|
|
up->fpsave.fpstatus |= (1<<3)|(1<<13);
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static ulong
|
|
branch(Ureg *ur, ulong fcr31)
|
|
{
|
|
ulong iw, npc, rs, rt, rd, offset;
|
|
|
|
iw = *(ulong*)ur->pc;
|
|
rs = (iw>>21) & 0x1F;
|
|
if(rs)
|
|
rs = *reg(ur, rs);
|
|
rt = (iw>>16) & 0x1F;
|
|
if(rt)
|
|
rt = *reg(ur, rt);
|
|
offset = iw & ((1<<16)-1);
|
|
if(offset & (1<<15)) /* sign extend */
|
|
offset |= ~((1<<16)-1);
|
|
offset <<= 2;
|
|
/*
|
|
* Integer unit jumps first
|
|
*/
|
|
switch(iw>>26){
|
|
case 0: /* SPECIAL: JR or JALR */
|
|
switch(iw&0x3F){
|
|
case 0x09: /* JALR */
|
|
rd = (iw>>11) & 0x1F;
|
|
if(rd)
|
|
*reg(ur, rd) = ur->pc+8;
|
|
/* fall through */
|
|
case 0x08: /* JR */
|
|
return rs;
|
|
default:
|
|
return 0;
|
|
}
|
|
case 1: /* BCOND */
|
|
switch((iw>>16) & 0x1F){
|
|
case 0x10: /* BLTZAL */
|
|
ur->r31 = ur->pc + 8;
|
|
/* fall through */
|
|
case 0x00: /* BLTZ */
|
|
if((long)rs < 0)
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
case 0x11: /* BGEZAL */
|
|
ur->r31 = ur->pc + 8;
|
|
/* fall through */
|
|
case 0x01: /* BGEZ */
|
|
if((long)rs >= 0)
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
default:
|
|
return 0;
|
|
}
|
|
case 3: /* JAL */
|
|
ur->r31 = ur->pc+8;
|
|
/* fall through */
|
|
case 2: /* JMP */
|
|
npc = iw & ((1<<26)-1);
|
|
npc <<= 2;
|
|
return npc | (ur->pc&0xF0000000);
|
|
case 4: /* BEQ */
|
|
if(rs == rt)
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
case 5: /* BNE */
|
|
if(rs != rt)
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
case 6: /* BLEZ */
|
|
if((long)rs <= 0)
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
case 7: /* BGTZ */
|
|
if((long)rs > 0)
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
}
|
|
/*
|
|
* Floating point unit jumps
|
|
*/
|
|
if((iw>>26) == 0x11) /* COP1 */
|
|
switch((iw>>16) & 0x3C1){
|
|
case 0x101: /* BCT */
|
|
case 0x181: /* BCT */
|
|
if(fcr31 & (1<<23))
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
case 0x100: /* BCF */
|
|
case 0x180: /* BCF */
|
|
if(!(fcr31 & (1<<23)))
|
|
return ur->pc+4 + offset;
|
|
return ur->pc + 8;
|
|
}
|
|
/* shouldn't get here */
|
|
return 0;
|
|
}
|