446 lines
7.1 KiB
C
446 lines
7.1 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <mach.h>
|
|
#define Extern extern
|
|
#include "sparc.h"
|
|
|
|
void
|
|
ldf(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, rs1, rs2;
|
|
|
|
getrop23(ir);
|
|
if(ir&IMMBIT) {
|
|
ximm(ea, ir);
|
|
if(trace)
|
|
itrace("ldf\tf%d,0x%lux(r%d) ea=%lux",rd, ea, rs1, ea+reg.r[rs1]);
|
|
ea += reg.r[rs1];
|
|
}
|
|
else {
|
|
ea = reg.r[rs1] + reg.r[rs2];
|
|
if(trace)
|
|
itrace("ldf\tf%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
|
|
}
|
|
|
|
reg.di[rd] = getmem_w(ea);
|
|
}
|
|
|
|
void
|
|
lddf(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, rs1, rs2;
|
|
|
|
getrop23(ir);
|
|
if(ir&IMMBIT) {
|
|
ximm(ea, ir);
|
|
if(trace)
|
|
itrace("lddf\tf%d,0x%lux(r%d) ea=%lux",
|
|
rd, ea, rs1, ea+reg.r[rs1]);
|
|
ea += reg.r[rs1];
|
|
}
|
|
else {
|
|
ea = reg.r[rs1] + reg.r[rs2];
|
|
if(trace)
|
|
itrace("lddf\tf%d,[r%d+r%d] ea=%lux", rd, rs1, rs2, ea);
|
|
}
|
|
|
|
if(ea&7) {
|
|
Bprint(bioout, "mem_address_not_aligned [load addr %.8lux]\n", ea);
|
|
longjmp(errjmp, 0);
|
|
}
|
|
if(rd&1)
|
|
undef(ir);
|
|
|
|
reg.di[rd] = getmem_w(ea);
|
|
reg.di[rd+1] = getmem_w(ea+4);
|
|
}
|
|
|
|
void
|
|
stf(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, rs1, rs2;
|
|
|
|
getrop23(ir);
|
|
if(ir&IMMBIT) {
|
|
ximm(ea, ir);
|
|
if(trace)
|
|
itrace("stf\tf%d,0x%lux(r%d) %lux=%g",
|
|
rd, ea, rs1, ea+reg.r[rs1], reg.fl[rd]);
|
|
ea += reg.r[rs1];
|
|
}
|
|
else {
|
|
ea = reg.r[rs1] + reg.r[rs2];
|
|
if(trace)
|
|
itrace("stf\tf%d,[r%d+r%d] %lux=%lux",
|
|
rd, rs1, rs2, ea, reg.r[rd]);
|
|
}
|
|
|
|
putmem_w(ea, reg.di[rd]);
|
|
}
|
|
|
|
void
|
|
stdf(ulong ir)
|
|
{
|
|
ulong ea;
|
|
int rd, rs1, rs2;
|
|
|
|
getrop23(ir);
|
|
if(ir&IMMBIT) {
|
|
ximm(ea, ir);
|
|
if(trace)
|
|
itrace("stdf\tf%d,0x%lux(r%d) %lux=%g",
|
|
rd, ea, rs1, ea+reg.r[rs1], reg.fl[rd]);
|
|
ea += reg.r[rs1];
|
|
}
|
|
else {
|
|
ea = reg.r[rs1] + reg.r[rs2];
|
|
if(trace)
|
|
itrace("stdf\tf%d,[r%d+r%d] %lux=%lux",
|
|
rd, rs1, rs2, ea, reg.r[rd]);
|
|
}
|
|
|
|
if(ea&7) {
|
|
Bprint(bioout, "mem_address_not_aligned [store addr %.8lux]\n", ea);
|
|
longjmp(errjmp, 0);
|
|
}
|
|
if(rd&1)
|
|
undef(ir);
|
|
|
|
putmem_w(ea, reg.di[rd]);
|
|
putmem_w(ea+4, reg.di[rd+1]);
|
|
}
|
|
|
|
void
|
|
fcmp(ulong ir)
|
|
{
|
|
int fc, rd, rs1, rs2;
|
|
|
|
getrop23(ir);
|
|
USED(rd);
|
|
SET(fc);
|
|
switch((ir>>5)&0x1FF) {
|
|
default:
|
|
undef(ir);
|
|
case 0x51: /* fcmps */
|
|
if(trace)
|
|
itrace("fcmps\tf%d,f%d", rs1, rs2);
|
|
if(isNaN(reg.fl[rs1]) || isNaN(reg.fl[rs2])) {
|
|
fc = 3;
|
|
break;
|
|
}
|
|
if(reg.fl[rs1] == reg.fl[rs2]) {
|
|
fc = 0;
|
|
break;
|
|
}
|
|
if(reg.fl[rs1] < reg.fl[rs2]) {
|
|
fc = 1;
|
|
break;
|
|
}
|
|
if(reg.fl[rs1] > reg.fl[rs2]) {
|
|
fc = 2;
|
|
break;
|
|
}
|
|
print("ki: fcmp error\n");
|
|
break;
|
|
case 0x52:
|
|
if(trace)
|
|
itrace("fcmpd\tf%d,f%d", rs1, rs2);
|
|
rs1 >>= 1;
|
|
rs2 >>= 1;
|
|
if(isNaN(reg.fd[rs1]) || isNaN(reg.fd[rs2])) {
|
|
fc = 3;
|
|
break;
|
|
}
|
|
if(reg.fd[rs1] == reg.fd[rs2]) {
|
|
fc = 0;
|
|
break;
|
|
}
|
|
if(reg.fd[rs1] < reg.fd[rs2]) {
|
|
fc = 1;
|
|
break;
|
|
}
|
|
if(reg.fd[rs1] > reg.fd[rs2]) {
|
|
fc = 2;
|
|
break;
|
|
}
|
|
print("ki: fcmp error\n");
|
|
break;
|
|
case 0x55: /* fcmpes */
|
|
if(trace)
|
|
itrace("fcmpes\tf%d,f%d", rs1, rs2);
|
|
rs1 >>= 1;
|
|
rs2 >>= 2;
|
|
if(isNaN(reg.fl[rs1]) || isNaN(reg.fl[rs2])) {
|
|
Bprint(bioout, "invalid_fp_register\n");
|
|
longjmp(errjmp, 0);
|
|
}
|
|
if(reg.fl[rs1] == reg.fl[rs2]) {
|
|
fc = 0;
|
|
break;
|
|
}
|
|
if(reg.fl[rs1] < reg.fl[rs2]) {
|
|
fc = 1;
|
|
break;
|
|
}
|
|
if(reg.fl[rs1] > reg.fl[rs2]) {
|
|
fc = 2;
|
|
break;
|
|
}
|
|
print("ki: fcmp error\n");
|
|
break;
|
|
case 0x56:
|
|
if(trace)
|
|
itrace("fcmped\tf%d,f%d", rs1, rs2);
|
|
if(isNaN(reg.fd[rs1]) || isNaN(reg.fd[rs2])) {
|
|
Bprint(bioout, "invalid_fp_register\n");
|
|
longjmp(errjmp, 0);
|
|
}
|
|
if(reg.fd[rs1] == reg.fd[rs2]) {
|
|
fc = 0;
|
|
break;
|
|
}
|
|
if(reg.fd[rs1] < reg.fd[rs2]) {
|
|
fc = 1;
|
|
break;
|
|
}
|
|
if(reg.fd[rs1] > reg.fd[rs2]) {
|
|
fc = 2;
|
|
break;
|
|
}
|
|
print("ki: fcmp error\n");
|
|
break;
|
|
|
|
}
|
|
reg.fpsr = (reg.fpsr&~(0x3<<10)) | (fc<<10);
|
|
}
|
|
|
|
void
|
|
fbcc(ulong ir)
|
|
{
|
|
char *op;
|
|
ulong npc;
|
|
int takeit, fc, ba, anul;
|
|
|
|
fc = (reg.fpsr>>10)&3;
|
|
ba = 0;
|
|
SET(op, takeit);
|
|
switch((ir>>25)&0x0F) {
|
|
case 0:
|
|
op = "fbn";
|
|
takeit = 0;
|
|
break;
|
|
case 1:
|
|
op = "fbne";
|
|
takeit = fc == FP_L || fc == FP_G || fc == FP_U;
|
|
break;
|
|
case 2:
|
|
op = "fblg";
|
|
takeit = fc == FP_L || fc == FP_G;
|
|
break;
|
|
case 3:
|
|
op = "fbul";
|
|
takeit = fc == FP_L || fc == FP_U;
|
|
break;
|
|
case 4:
|
|
op = "fbl";
|
|
takeit = fc == FP_L;
|
|
break;
|
|
case 5:
|
|
op = "fbug";
|
|
takeit = fc == FP_U || fc == FP_G;
|
|
break;
|
|
case 6:
|
|
op = "fbg";
|
|
takeit = fc == FP_G;
|
|
break;
|
|
case 7:
|
|
op = "fbu";
|
|
takeit = fc == FP_U;
|
|
break;
|
|
case 8:
|
|
op = "fba";
|
|
ba = 1;
|
|
takeit = 1;
|
|
break;
|
|
case 9:
|
|
op = "fbe";
|
|
takeit = fc == FP_E;
|
|
break;
|
|
case 10:
|
|
op = "fbue";
|
|
takeit = fc == FP_E || fc == FP_U;
|
|
break;
|
|
case 11:
|
|
op = "fbge";
|
|
takeit = fc == FP_E || fc == FP_G;
|
|
break;
|
|
case 12:
|
|
op = "fbuge";
|
|
takeit = fc == FP_E || fc == FP_G || fc == FP_U;
|
|
break;
|
|
case 13:
|
|
op = "fble";
|
|
takeit = fc == FP_E || fc == FP_L;
|
|
break;
|
|
case 14:
|
|
op = "fbule";
|
|
takeit = fc == FP_E || fc == FP_L || fc == FP_U;
|
|
break;
|
|
case 15:
|
|
op = "fbo";
|
|
takeit = fc == FP_E || fc == FP_L || fc == FP_G;
|
|
break;
|
|
}
|
|
|
|
npc = ir & 0x3FFFFF;
|
|
if(npc & (1<<21))
|
|
npc |= ~((1<<22)-1);
|
|
npc = (npc<<2) + reg.pc;
|
|
|
|
anul = ir&ANUL;
|
|
if(trace) {
|
|
if(anul)
|
|
itrace("%s,a\t%lux", op, npc);
|
|
else
|
|
itrace("%s\t%lux", op, npc);
|
|
}
|
|
|
|
if(takeit == 0) {
|
|
reg.pc += 4;
|
|
if(anul == 0) {
|
|
reg.ir = ifetch(reg.pc);
|
|
delay(reg.pc+4);
|
|
}
|
|
else
|
|
anulled++;
|
|
return;
|
|
}
|
|
|
|
ci->taken++;
|
|
if(ba && anul) {
|
|
reg.pc = npc-4;
|
|
anulled++;
|
|
return;
|
|
}
|
|
reg.ir = ifetch(reg.pc+4);
|
|
delay(npc);
|
|
reg.pc = npc-4;
|
|
}
|
|
|
|
void
|
|
farith(ulong ir)
|
|
{
|
|
char *op;
|
|
long v;
|
|
int rd, rs1, rs2, fmt;
|
|
|
|
fmt = 0;
|
|
getrop23(ir);
|
|
switch((ir>>5)&0x1FF) {
|
|
default:
|
|
undef(ir);
|
|
case 0x41:
|
|
reg.fl[rd] = reg.fl[rs1] + reg.fl[rs2];
|
|
op = "fadds";
|
|
break;
|
|
case 0x42:
|
|
reg.fd[rd>>1] = reg.fd[rs1>>1] + reg.fd[rs2>>1];
|
|
op = "faddd";
|
|
break;
|
|
case 0x45:
|
|
reg.fl[rd] = reg.fl[rs1] - reg.fl[rs2];
|
|
op = "fsubs";
|
|
break;
|
|
case 0x46:
|
|
reg.fd[rd>>1] = reg.fd[rs1>>1] - reg.fd[rs2>>1];
|
|
op = "fsubd";
|
|
break;
|
|
case 0x4d:
|
|
if(reg.fl[rs2] == 0.0) {
|
|
Bprint(bioout, "fp_exception DZ\n");
|
|
longjmp(errjmp, 0);
|
|
}
|
|
reg.fl[rd] = reg.fl[rs1] / reg.fl[rs2];
|
|
op = "fdivs";
|
|
break;
|
|
case 0x4e:
|
|
if(reg.fd[rs2>>1] == 0.0) {
|
|
Bprint(bioout, "fp_exception DZ\n");
|
|
longjmp(errjmp, 0);
|
|
}
|
|
reg.fd[rd>>1] = reg.fd[rs1>>1] / reg.fd[rs2>>1];
|
|
op = "fdivd";
|
|
break;
|
|
case 0x49:
|
|
reg.fl[rd] = reg.fl[rs1] * reg.fl[rs2];
|
|
op = "fmuls";
|
|
break;
|
|
case 0x4a:
|
|
reg.fd[rd>>1] = reg.fd[rs1>>1] * reg.fd[rs2>>1];
|
|
op = "fmuld";
|
|
break;
|
|
case 0xc4:
|
|
reg.fl[rd] = (long)reg.di[rs2];
|
|
fmt = 1;
|
|
op = "fitos";
|
|
break;
|
|
case 0xc8:
|
|
reg.fd[rd>>1] = (long)reg.di[rs2];
|
|
fmt = 1;
|
|
op = "fitod";
|
|
break;
|
|
case 0xd1:
|
|
v = reg.fl[rs2];
|
|
reg.di[rd] = v;
|
|
fmt = 1;
|
|
op = "fstoi";
|
|
break;
|
|
case 0xd2:
|
|
v = reg.fd[rs2>>1];
|
|
reg.di[rd] = v;
|
|
fmt = 1;
|
|
op = "fdtoi";
|
|
break;
|
|
case 0x01:
|
|
reg.di[rd] = reg.di[rs2];
|
|
fmt = 1;
|
|
op = "fmovs";
|
|
break;
|
|
case 0x05:
|
|
reg.fl[rd] = -reg.fl[rs2];
|
|
fmt = 1;
|
|
op = "fnegs";
|
|
break;
|
|
case 0x09:
|
|
reg.fl[rd] = fabs(reg.fl[rs2]);
|
|
fmt = 1;
|
|
op = "fabss";
|
|
break;
|
|
case 0xc9:
|
|
reg.fd[rd>>1] = reg.fl[rs2];
|
|
fmt = 1;
|
|
op = "fstod";
|
|
break;
|
|
case 0xc6:
|
|
reg.fl[rd] = reg.fd[rs2>>1];
|
|
fmt = 1;
|
|
op = "fdtos";
|
|
break;
|
|
}
|
|
|
|
if(trace) {
|
|
switch(fmt) {
|
|
case 0:
|
|
itrace("%s\tf%d,f%d,f%d", op, rs1, rs2, rd);
|
|
break;
|
|
case 1:
|
|
itrace("%s\tf%d,f%d", op, rs2, rd);
|
|
break;
|
|
}
|
|
}
|
|
}
|