Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#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;
                }
        }
}