mupen64plus-oldsvn/r4300/pure_interp.c
Jesse Dean 895a9d3d48 Rewrite of debugger memory breakpoint trap. Memory breakpoints are now
trapped by functions injected into the memory function tables.  
New setup should be MUCH faster, and more flexible
2008-12-22 04:54:03 +00:00

3140 lines
70 KiB
C
Raw Permalink Blame History

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Mupen64plus - pure_interp.c *
* Mupen64Plus homepage: http://code.google.com/p/mupen64plus/ *
* Copyright (C) 2002 Hacktarux *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "r4300.h"
#include "exception.h"
#include "macros.h"
#include "interupt.h"
#include "../memory/memory.h"
#ifdef DBG
#include "../debugger/debugger.h"
#endif
unsigned int interp_addr;
unsigned int op;
static int skip;
void prefetch();
static void (*interp_ops[64])(void);
extern unsigned int next_vi;
static void NI()
{
printf("NI:%x\n", (unsigned int)op);
stop=1;
}
static void SLL()
{
rrd32 = (unsigned int)(rrt32) << rsa;
sign_extended(rrd);
interp_addr+=4;
}
static void SRL()
{
rrd32 = (unsigned int)rrt32 >> rsa;
sign_extended(rrd);
interp_addr+=4;
}
static void SRA()
{
rrd32 = (signed int)rrt32 >> rsa;
sign_extended(rrd);
interp_addr+=4;
}
static void SLLV()
{
rrd32 = (unsigned int)(rrt32) << (rrs32&0x1F);
sign_extended(rrd);
interp_addr+=4;
}
static void SRLV()
{
rrd32 = (unsigned int)rrt32 >> (rrs32 & 0x1F);
sign_extended(rrd);
interp_addr+=4;
}
static void SRAV()
{
rrd32 = (signed int)rrt32 >> (rrs32 & 0x1F);
sign_extended(rrd);
interp_addr+=4;
}
static void JR()
{
local_rs32 = irs32;
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr = local_rs32;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void JALR()
{
unsigned long long *dest = (unsigned long long *) PC->f.r.rd;
local_rs32 = rrs32;
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (!skip_jump)
{
*dest = interp_addr;
sign_extended(*dest);
interp_addr = local_rs32;
}
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void SYSCALL()
{
Cause = 8 << 2;
exception_general();
}
static void SYNC()
{
interp_addr+=4;
}
static void MFHI()
{
rrd = hi;
interp_addr+=4;
}
static void MTHI()
{
hi = rrs;
interp_addr+=4;
}
static void MFLO()
{
rrd = lo;
interp_addr+=4;
}
static void MTLO()
{
lo = rrs;
interp_addr+=4;
}
static void DSLLV()
{
rrd = rrt << (rrs32&0x3F);
interp_addr+=4;
}
static void DSRLV()
{
rrd = (unsigned long long)rrt >> (rrs32 & 0x3F);
interp_addr+=4;
}
static void DSRAV()
{
rrd = (long long)rrt >> (rrs32 & 0x3F);
interp_addr+=4;
}
static void MULT()
{
long long int temp;
temp = rrs * rrt;
hi = temp >> 32;
lo = temp;
sign_extended(lo);
interp_addr+=4;
}
static void MULTU()
{
unsigned long long int temp;
temp = (unsigned int)rrs * (unsigned long long)((unsigned int)rrt);
hi = (long long)temp >> 32;
lo = temp;
sign_extended(lo);
interp_addr+=4;
}
static void DIV()
{
if (rrt32)
{
lo = rrs32 / rrt32;
hi = rrs32 % rrt32;
sign_extended(lo);
sign_extended(hi);
}
else printf("div\n");
interp_addr+=4;
}
static void DIVU()
{
if (rrt32)
{
lo = (unsigned int)rrs32 / (unsigned int)rrt32;
hi = (unsigned int)rrs32 % (unsigned int)rrt32;
sign_extended(lo);
sign_extended(hi);
}
else printf("divu\n");
interp_addr+=4;
}
static void DMULT()
{
unsigned long long int op1, op2, op3, op4;
unsigned long long int result1, result2, result3, result4;
unsigned long long int temp1, temp2, temp3, temp4;
int sign = 0;
if (rrs < 0)
{
op2 = -rrs;
sign = 1 - sign;
}
else op2 = rrs;
if (rrt < 0)
{
op4 = -rrt;
sign = 1 - sign;
}
else op4 = rrt;
op1 = op2 & 0xFFFFFFFF;
op2 = (op2 >> 32) & 0xFFFFFFFF;
op3 = op4 & 0xFFFFFFFF;
op4 = (op4 >> 32) & 0xFFFFFFFF;
temp1 = op1 * op3;
temp2 = (temp1 >> 32) + op1 * op4;
temp3 = op2 * op3;
temp4 = (temp3 >> 32) + op2 * op4;
result1 = temp1 & 0xFFFFFFFF;
result2 = temp2 + (temp3 & 0xFFFFFFFF);
result3 = (result2 >> 32) + temp4;
result4 = (result3 >> 32);
lo = result1 | (result2 << 32);
hi = (result3 & 0xFFFFFFFF) | (result4 << 32);
if (sign)
{
hi = ~hi;
if (!lo) hi++;
else lo = ~lo + 1;
}
interp_addr+=4;
}
static void DMULTU()
{
unsigned long long int op1, op2, op3, op4;
unsigned long long int result1, result2, result3, result4;
unsigned long long int temp1, temp2, temp3, temp4;
op1 = rrs & 0xFFFFFFFF;
op2 = (rrs >> 32) & 0xFFFFFFFF;
op3 = rrt & 0xFFFFFFFF;
op4 = (rrt >> 32) & 0xFFFFFFFF;
temp1 = op1 * op3;
temp2 = (temp1 >> 32) + op1 * op4;
temp3 = op2 * op3;
temp4 = (temp3 >> 32) + op2 * op4;
result1 = temp1 & 0xFFFFFFFF;
result2 = temp2 + (temp3 & 0xFFFFFFFF);
result3 = (result2 >> 32) + temp4;
result4 = (result3 >> 32);
lo = result1 | (result2 << 32);
hi = (result3 & 0xFFFFFFFF) | (result4 << 32);
interp_addr+=4;
}
static void DDIV()
{
if (rrt)
{
lo = (long long int)rrs / (long long int)rrt;
hi = (long long int)rrs % (long long int)rrt;
}
else printf("ddiv\n");
interp_addr+=4;
}
static void DDIVU()
{
if (rrt)
{
lo = (unsigned long long int)rrs / (unsigned long long int)rrt;
hi = (unsigned long long int)rrs % (unsigned long long int)rrt;
}
else printf("ddivu\n");
interp_addr+=4;
}
static void ADD()
{
rrd32 = rrs32 + rrt32;
sign_extended(rrd);
interp_addr+=4;
}
static void ADDU()
{
rrd32 = rrs32 + rrt32;
sign_extended(rrd);
interp_addr+=4;
}
static void SUB()
{
rrd32 = rrs32 - rrt32;
sign_extended(rrd);
interp_addr+=4;
}
static void SUBU()
{
rrd32 = rrs32 - rrt32;
sign_extended(rrd);
interp_addr+=4;
}
static void AND()
{
rrd = rrs & rrt;
interp_addr+=4;
}
static void OR()
{
rrd = rrs | rrt;
interp_addr+=4;
}
static void XOR()
{
rrd = rrs ^ rrt;
interp_addr+=4;
}
static void NOR()
{
rrd = ~(rrs | rrt);
interp_addr+=4;
}
static void SLT()
{
if (rrs < rrt) rrd = 1;
else rrd = 0;
interp_addr+=4;
}
static void SLTU()
{
if ((unsigned long long)rrs < (unsigned long long)rrt)
rrd = 1;
else rrd = 0;
interp_addr+=4;
}
static void DADD()
{
rrd = rrs + rrt;
interp_addr+=4;
}
static void DADDU()
{
rrd = rrs + rrt;
interp_addr+=4;
}
static void DSUB()
{
rrd = rrs - rrt;
interp_addr+=4;
}
static void DSUBU()
{
rrd = rrs - rrt;
interp_addr+=4;
}
static void TEQ()
{
if (rrs == rrt)
{
printf("trap exception in teq\n");
stop=1;
}
interp_addr+=4;
}
static void DSLL()
{
rrd = rrt << rsa;
interp_addr+=4;
}
static void DSRL()
{
rrd = (unsigned long long)rrt >> rsa;
interp_addr+=4;
}
static void DSRA()
{
rrd = rrt >> rsa;
interp_addr+=4;
}
static void DSLL32()
{
rrd = rrt << (32+rsa);
interp_addr+=4;
}
static void DSRL32()
{
rrd = (unsigned long long int)rrt >> (32+rsa);
interp_addr+=4;
}
static void DSRA32()
{
rrd = (signed long long int)rrt >> (32+rsa);
interp_addr+=4;
}
static void (*interp_special[64])(void) =
{
SLL , NI , SRL , SRA , SLLV , NI , SRLV , SRAV ,
JR , JALR , NI , NI , SYSCALL, NI , NI , SYNC ,
MFHI, MTHI , MFLO, MTLO, DSLLV , NI , DSRLV , DSRAV ,
MULT, MULTU, DIV , DIVU, DMULT , DMULTU, DDIV , DDIVU ,
ADD , ADDU , SUB , SUBU, AND , OR , XOR , NOR ,
NI , NI , SLT , SLTU, DADD , DADDU , DSUB , DSUBU ,
NI , NI , NI , NI , TEQ , NI , NI , NI ,
DSLL, NI , DSRL, DSRA, DSLL32 , NI , DSRL32, DSRA32
};
static void BLTZ()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs < 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (local_rs < 0)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BGEZ()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs >= 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (local_rs >= 0)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BLTZL()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (irs < 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (irs < 0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else interp_addr+=8;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BGEZL()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (irs >= 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (irs >= 0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else interp_addr+=8;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BLTZAL()
{
short local_immediate = iimmediate;
local_rs = irs;
reg[31]=interp_addr+8;
if((&irs)!=(reg+31))
{
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs < 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if(local_rs < 0)
interp_addr += (local_immediate-1)*4;
}
else printf("erreur dans bltzal\n");
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BGEZAL()
{
short local_immediate = iimmediate;
local_rs = irs;
reg[31]=interp_addr+8;
if((&irs)!=(reg+31))
{
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs >= 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if(local_rs >= 0)
interp_addr += (local_immediate-1)*4;
}
else printf("erreur dans bgezal\n");
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BLTZALL()
{
short local_immediate = iimmediate;
local_rs = irs;
reg[31]=interp_addr+8;
if((&irs)!=(reg+31))
{
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs < 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (local_rs < 0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else interp_addr+=8;
}
else printf("erreur dans bltzall\n");
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BGEZALL()
{
short local_immediate = iimmediate;
local_rs = irs;
reg[31]=interp_addr+8;
if((&irs)!=(reg+31))
{
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs >= 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (local_rs >= 0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else interp_addr+=8;
}
else printf("erreur dans bgezall\n");
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void (*interp_regimm[32])(void) =
{
BLTZ , BGEZ , BLTZL , BGEZL , NI, NI, NI, NI,
NI , NI , NI , NI , NI, NI, NI, NI,
BLTZAL, BGEZAL, BLTZALL, BGEZALL, NI, NI, NI, NI,
NI , NI , NI , NI , NI, NI, NI, NI
};
static void TLBR()
{
int index;
index = Index & 0x1F;
PageMask = tlb_e[index].mask << 13;
EntryHi = ((tlb_e[index].vpn2 << 13) | tlb_e[index].asid);
EntryLo0 = (tlb_e[index].pfn_even << 6) | (tlb_e[index].c_even << 3)
| (tlb_e[index].d_even << 2) | (tlb_e[index].v_even << 1)
| tlb_e[index].g;
EntryLo1 = (tlb_e[index].pfn_odd << 6) | (tlb_e[index].c_odd << 3)
| (tlb_e[index].d_odd << 2) | (tlb_e[index].v_odd << 1)
| tlb_e[index].g;
interp_addr+=4;
}
static void TLBWI()
{
unsigned int i;
if (tlb_e[Index&0x3F].v_even)
{
for (i=tlb_e[Index&0x3F].start_even; i<tlb_e[Index&0x3F].end_even; i++)
tlb_LUT_r[i>>12] = 0;
if (tlb_e[Index&0x3F].d_even)
for (i=tlb_e[Index&0x3F].start_even; i<tlb_e[Index&0x3F].end_even; i++)
tlb_LUT_w[i>>12] = 0;
}
if (tlb_e[Index&0x3F].v_odd)
{
for (i=tlb_e[Index&0x3F].start_odd; i<tlb_e[Index&0x3F].end_odd; i++)
tlb_LUT_r[i>>12] = 0;
if (tlb_e[Index&0x3F].d_odd)
for (i=tlb_e[Index&0x3F].start_odd; i<tlb_e[Index&0x3F].end_odd; i++)
tlb_LUT_w[i>>12] = 0;
}
tlb_e[Index&0x3F].g = (EntryLo0 & EntryLo1 & 1);
tlb_e[Index&0x3F].pfn_even = (EntryLo0 & 0x3FFFFFC0) >> 6;
tlb_e[Index&0x3F].pfn_odd = (EntryLo1 & 0x3FFFFFC0) >> 6;
tlb_e[Index&0x3F].c_even = (EntryLo0 & 0x38) >> 3;
tlb_e[Index&0x3F].c_odd = (EntryLo1 & 0x38) >> 3;
tlb_e[Index&0x3F].d_even = (EntryLo0 & 0x4) >> 2;
tlb_e[Index&0x3F].d_odd = (EntryLo1 & 0x4) >> 2;
tlb_e[Index&0x3F].v_even = (EntryLo0 & 0x2) >> 1;
tlb_e[Index&0x3F].v_odd = (EntryLo1 & 0x2) >> 1;
tlb_e[Index&0x3F].asid = (EntryHi & 0xFF);
tlb_e[Index&0x3F].vpn2 = (EntryHi & 0xFFFFE000) >> 13;
//tlb_e[Index&0x3F].r = (EntryHi & 0xC000000000000000LL) >> 62;
tlb_e[Index&0x3F].mask = (PageMask & 0x1FFE000) >> 13;
tlb_e[Index&0x3F].start_even = tlb_e[Index&0x3F].vpn2 << 13;
tlb_e[Index&0x3F].end_even = tlb_e[Index&0x3F].start_even+
(tlb_e[Index&0x3F].mask << 12) + 0xFFF;
tlb_e[Index&0x3F].phys_even = tlb_e[Index&0x3F].pfn_even << 12;
if (tlb_e[Index&0x3F].v_even)
{
if (tlb_e[Index&0x3F].start_even < tlb_e[Index&0x3F].end_even &&
!(tlb_e[Index&0x3F].start_even >= 0x80000000 &&
tlb_e[Index&0x3F].end_even < 0xC0000000) &&
tlb_e[Index&0x3F].phys_even < 0x20000000)
{
for (i=tlb_e[Index&0x3F].start_even;i<tlb_e[Index&0x3F].end_even;i++)
tlb_LUT_r[i>>12] = 0x80000000 |
(tlb_e[Index&0x3F].phys_even + (i - tlb_e[Index&0x3F].start_even));
if (tlb_e[Index&0x3F].d_even)
for (i=tlb_e[Index&0x3F].start_even;i<tlb_e[Index&0x3F].end_even;i++)
tlb_LUT_w[i>>12] = 0x80000000 |
(tlb_e[Index&0x3F].phys_even + (i - tlb_e[Index&0x3F].start_even));
}
}
tlb_e[Index&0x3F].start_odd = tlb_e[Index&0x3F].end_even+1;
tlb_e[Index&0x3F].end_odd = tlb_e[Index&0x3F].start_odd+
(tlb_e[Index&0x3F].mask << 12) + 0xFFF;
tlb_e[Index&0x3F].phys_odd = tlb_e[Index&0x3F].pfn_odd << 12;
if (tlb_e[Index&0x3F].v_odd)
{
if (tlb_e[Index&0x3F].start_odd < tlb_e[Index&0x3F].end_odd &&
!(tlb_e[Index&0x3F].start_odd >= 0x80000000 &&
tlb_e[Index&0x3F].end_odd < 0xC0000000) &&
tlb_e[Index&0x3F].phys_odd < 0x20000000)
{
for (i=tlb_e[Index&0x3F].start_odd;i<tlb_e[Index&0x3F].end_odd;i++)
tlb_LUT_r[i>>12] = 0x80000000 |
(tlb_e[Index&0x3F].phys_odd + (i - tlb_e[Index&0x3F].start_odd));
if (tlb_e[Index&0x3F].d_odd)
for (i=tlb_e[Index&0x3F].start_odd;i<tlb_e[Index&0x3F].end_odd;i++)
tlb_LUT_w[i>>12] = 0x80000000 |
(tlb_e[Index&0x3F].phys_odd + (i - tlb_e[Index&0x3F].start_odd));
}
}
interp_addr+=4;
}
static void TLBWR()
{
unsigned int i;
update_count();
Random = (Count/2 % (32 - Wired)) + Wired;
if (tlb_e[Random].v_even)
{
for (i=tlb_e[Random].start_even; i<tlb_e[Random].end_even; i++)
tlb_LUT_r[i>>12] = 0;
if (tlb_e[Random].d_even)
for (i=tlb_e[Random].start_even; i<tlb_e[Random].end_even; i++)
tlb_LUT_w[i>>12] = 0;
}
if (tlb_e[Random].v_odd)
{
for (i=tlb_e[Random].start_odd; i<tlb_e[Random].end_odd; i++)
tlb_LUT_r[i>>12] = 0;
if (tlb_e[Random].d_odd)
for (i=tlb_e[Random].start_odd; i<tlb_e[Random].end_odd; i++)
tlb_LUT_w[i>>12] = 0;
}
tlb_e[Random].g = (EntryLo0 & EntryLo1 & 1);
tlb_e[Random].pfn_even = (EntryLo0 & 0x3FFFFFC0) >> 6;
tlb_e[Random].pfn_odd = (EntryLo1 & 0x3FFFFFC0) >> 6;
tlb_e[Random].c_even = (EntryLo0 & 0x38) >> 3;
tlb_e[Random].c_odd = (EntryLo1 & 0x38) >> 3;
tlb_e[Random].d_even = (EntryLo0 & 0x4) >> 2;
tlb_e[Random].d_odd = (EntryLo1 & 0x4) >> 2;
tlb_e[Random].v_even = (EntryLo0 & 0x2) >> 1;
tlb_e[Random].v_odd = (EntryLo1 & 0x2) >> 1;
tlb_e[Random].asid = (EntryHi & 0xFF);
tlb_e[Random].vpn2 = (EntryHi & 0xFFFFE000) >> 13;
//tlb_e[Random].r = (EntryHi & 0xC000000000000000LL) >> 62;
tlb_e[Random].mask = (PageMask & 0x1FFE000) >> 13;
tlb_e[Random].start_even = tlb_e[Random].vpn2 << 13;
tlb_e[Random].end_even = tlb_e[Random].start_even+
(tlb_e[Random].mask << 12) + 0xFFF;
tlb_e[Random].phys_even = tlb_e[Random].pfn_even << 12;
if (tlb_e[Random].v_even)
{
if (tlb_e[Random].start_even < tlb_e[Random].end_even &&
!(tlb_e[Random].start_even >= 0x80000000 &&
tlb_e[Random].end_even < 0xC0000000) &&
tlb_e[Random].phys_even < 0x20000000)
{
for (i=tlb_e[Random].start_even;i<tlb_e[Random].end_even;i++)
tlb_LUT_r[i>>12] = 0x80000000 |
(tlb_e[Random].phys_even + (i - tlb_e[Random].start_even));
if (tlb_e[Random].d_even)
for (i=tlb_e[Random].start_even;i<tlb_e[Random].end_even;i++)
tlb_LUT_w[i>>12] = 0x80000000 |
(tlb_e[Random].phys_even + (i - tlb_e[Random].start_even));
}
}
tlb_e[Random].start_odd = tlb_e[Random].end_even+1;
tlb_e[Random].end_odd = tlb_e[Random].start_odd+
(tlb_e[Random].mask << 12) + 0xFFF;
tlb_e[Random].phys_odd = tlb_e[Random].pfn_odd << 12;
if (tlb_e[Random].v_odd)
{
if (tlb_e[Random].start_odd < tlb_e[Random].end_odd &&
!(tlb_e[Random].start_odd >= 0x80000000 &&
tlb_e[Random].end_odd < 0xC0000000) &&
tlb_e[Random].phys_odd < 0x20000000)
{
for (i=tlb_e[Random].start_odd;i<tlb_e[Random].end_odd;i++)
tlb_LUT_r[i>>12] = 0x80000000 |
(tlb_e[Random].phys_odd + (i - tlb_e[Random].start_odd));
if (tlb_e[Random].d_odd)
for (i=tlb_e[Random].start_odd;i<tlb_e[Random].end_odd;i++)
tlb_LUT_w[i>>12] = 0x80000000 |
(tlb_e[Random].phys_odd + (i - tlb_e[Random].start_odd));
}
}
interp_addr+=4;
}
static void TLBP()
{
int i;
Index |= 0x80000000;
for (i=0; i<32; i++)
{
if (((tlb_e[i].vpn2 & (~tlb_e[i].mask)) ==
(((EntryHi & 0xFFFFE000) >> 13) & (~tlb_e[i].mask))) &&
((tlb_e[i].g) ||
(tlb_e[i].asid == (EntryHi & 0xFF))))
{
Index = i;
break;
}
}
interp_addr+=4;
}
static void ERET()
{
update_count();
if (Status & 0x4)
{
printf("erreur dans ERET\n");
stop=1;
}
else
{
Status &= 0xFFFFFFFD;
interp_addr = EPC;
}
llbit = 0;
check_interupt();
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void (*interp_tlb[64])(void) =
{
NI , TLBR, TLBWI, NI, NI, NI, TLBWR, NI,
TLBP, NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
ERET, NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI,
NI , NI , NI , NI, NI, NI, NI , NI
};
static void MFC0()
{
switch(PC->f.r.nrd)
{
case 1:
printf("lecture de Random\n");
stop=1;
default:
rrt32 = reg_cop0[PC->f.r.nrd];
sign_extended(rrt);
}
interp_addr+=4;
}
static void MTC0()
{
switch(PC->f.r.nrd)
{
case 0: // Index
Index = rrt & 0x8000003F;
if ((Index & 0x3F) > 31)
{
printf ("il y a plus de 32 TLB\n");
stop=1;
}
break;
case 1: // Random
break;
case 2: // EntryLo0
EntryLo0 = rrt & 0x3FFFFFFF;
break;
case 3: // EntryLo1
EntryLo1 = rrt & 0x3FFFFFFF;
break;
case 4: // Context
Context = (rrt & 0xFF800000) | (Context & 0x007FFFF0);
break;
case 5: // PageMask
PageMask = rrt & 0x01FFE000;
break;
case 6: // Wired
Wired = rrt;
Random = 31;
break;
case 8: // BadVAddr
break;
case 9: // Count
update_count();
if (next_interupt <= Count) gen_interupt();
debug_count += Count;
translate_event_queue(rrt & 0xFFFFFFFF);
Count = rrt & 0xFFFFFFFF;
debug_count -= Count;
break;
case 10: // EntryHi
EntryHi = rrt & 0xFFFFE0FF;
break;
case 11: // Compare
update_count();
remove_event(COMPARE_INT);
add_interupt_event_count(COMPARE_INT, (unsigned int)rrt);
Compare = rrt;
Cause = Cause & 0xFFFF7FFF; //Timer interupt is clear
break;
case 12: // Status
if((rrt & 0x04000000) != (Status & 0x04000000))
{
if (rrt & 0x04000000)
{
int i;
for (i=0; i<32; i++)
{
//reg_cop1_fgr_64[i]=reg_cop1_fgr_32[i];
reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i];
reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i];
}
}
else
{
int i;
for (i=0; i<32; i++)
{
//reg_cop1_fgr_32[i]=reg_cop1_fgr_64[i]&0xFFFFFFFF;
//if (i<16) reg_cop1_double[i*2]=(double*)&reg_cop1_fgr_32[i*2];
//reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i & 0xFFFE];
if(!(i&1))
reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i>>1];
//reg_cop1_double[i]=(double*)&reg_cop1_fgr_64[i];
//reg_cop1_simple[i]=(float*)&reg_cop1_fgr_32[i];
//reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i & 0xFFFE]+(i&1);
#ifndef _BIG_ENDIAN
reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(i&1);
#else
reg_cop1_simple[i]=(float*)&reg_cop1_fgr_64[i>>1]+(1-(i&1));
#endif
}
}
}
Status = rrt;
interp_addr+=4;
check_interupt();
update_count();
if (next_interupt <= Count) gen_interupt();
interp_addr-=4;
break;
case 13: // Cause
if (rrt!=0)
{
printf("<EFBFBD>criture dans Cause\n");
stop = 1;
}
else Cause = rrt;
break;
case 14: // EPC
EPC = rrt;
break;
case 15: // PRevID
break;
case 16: // Config
Config = rrt;
break;
case 18: // WatchLo
WatchLo = rrt & 0xFFFFFFFF;
break;
case 19: // WatchHi
WatchHi = rrt & 0xFFFFFFFF;
break;
case 27: // CacheErr
break;
case 28: // TagLo
TagLo = rrt & 0x0FFFFFC0;
break;
case 29: // TagHi
TagHi =0;
break;
default:
printf("unknown mtc0 write : %d\n", PC->f.r.nrd);
stop=1;
}
interp_addr+=4;
}
static void TLB()
{
interp_tlb[(op & 0x3F)]();
}
static void (*interp_cop0[32])(void) =
{
MFC0, NI, NI, NI, MTC0, NI, NI, NI,
NI , NI, NI, NI, NI , NI, NI, NI,
TLB , NI, NI, NI, NI , NI, NI, NI,
NI , NI, NI, NI, NI , NI, NI, NI
};
static void BC1F()
{
short local_immediate = iimmediate;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if ((FCR31 & 0x800000)==0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if ((FCR31 & 0x800000)==0)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BC1T()
{
short local_immediate = iimmediate;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if ((FCR31 & 0x800000)!=0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if ((FCR31 & 0x800000)!=0)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BC1FL()
{
short local_immediate = iimmediate;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if ((FCR31 & 0x800000)==0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if ((FCR31 & 0x800000)==0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else
interp_addr+=8;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BC1TL()
{
short local_immediate = iimmediate;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if ((FCR31 & 0x800000)!=0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if ((FCR31 & 0x800000)!=0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else
interp_addr+=8;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void (*interp_cop1_bc[4])(void) =
{
BC1F , BC1T,
BC1FL, BC1TL
};
static void ADD_S()
{
set_rounding();
*reg_cop1_simple[cffd] = *reg_cop1_simple[cffs] +
*reg_cop1_simple[cfft];
interp_addr+=4;
}
static void SUB_S()
{
set_rounding();
*reg_cop1_simple[cffd] = *reg_cop1_simple[cffs] -
*reg_cop1_simple[cfft];
interp_addr+=4;
}
static void MUL_S()
{
set_rounding();
*reg_cop1_simple[cffd] = *reg_cop1_simple[cffs] *
*reg_cop1_simple[cfft];
interp_addr+=4;
}
static void DIV_S()
{
if((FCR31 & 0x400) && *reg_cop1_simple[cfft] == 0)
{
printf("div_s by 0\n");
}
set_rounding();
*reg_cop1_simple[cffd] = *reg_cop1_simple[cffs] /
*reg_cop1_simple[cfft];
interp_addr+=4;
}
static void SQRT_S()
{
set_rounding();
*reg_cop1_simple[cffd] = sqrt(*reg_cop1_simple[cffs]);
interp_addr+=4;
}
static void ABS_S()
{
set_rounding();
*reg_cop1_simple[cffd] = fabs(*reg_cop1_simple[cffs]);
interp_addr+=4;
}
static void MOV_S()
{
set_rounding();
*reg_cop1_simple[cffd] = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void NEG_S()
{
set_rounding();
*reg_cop1_simple[cffd] = -(*reg_cop1_simple[cffs]);
interp_addr+=4;
}
static void ROUND_L_S()
{
set_round();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void TRUNC_L_S()
{
set_trunc();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void CEIL_L_S()
{
set_ceil();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void FLOOR_L_S()
{
set_floor();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void ROUND_W_S()
{
set_round();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void TRUNC_W_S()
{
set_trunc();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void CEIL_W_S()
{
set_ceil();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void FLOOR_W_S()
{
set_floor();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void CVT_D_S()
{
set_rounding();
*reg_cop1_double[cffd] = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void CVT_W_S()
{
set_rounding();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void CVT_L_S()
{
set_rounding();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_simple[cffs];
interp_addr+=4;
}
static void C_F_S()
{
FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_UN_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_EQ_S()
{
if (!isnan(*reg_cop1_simple[cffs]) && !isnan(*reg_cop1_simple[cfft]) &&
*reg_cop1_simple[cffs] == *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_UEQ_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]) ||
*reg_cop1_simple[cffs] == *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_OLT_S()
{
if (!isnan(*reg_cop1_simple[cffs]) && !isnan(*reg_cop1_simple[cfft]) &&
*reg_cop1_simple[cffs] < *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_ULT_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]) ||
*reg_cop1_simple[cffs] < *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_OLE_S()
{
if (!isnan(*reg_cop1_simple[cffs]) && !isnan(*reg_cop1_simple[cfft]) &&
*reg_cop1_simple[cffs] <= *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_ULE_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]) ||
*reg_cop1_simple[cffs] <= *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_SF_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGLE_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_SEQ_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_simple[cffs] == *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGL_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_simple[cffs] == *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_LT_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_simple[cffs] < *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGE_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_simple[cffs] < *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_LE_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_simple[cffs] <= *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGT_S()
{
if (isnan(*reg_cop1_simple[cffs]) || isnan(*reg_cop1_simple[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_simple[cffs] <= *reg_cop1_simple[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void (*interp_cop1_s[64])(void) =
{
ADD_S ,SUB_S ,MUL_S ,DIV_S ,SQRT_S ,ABS_S ,MOV_S ,NEG_S ,
ROUND_L_S,TRUNC_L_S,CEIL_L_S,FLOOR_L_S,ROUND_W_S,TRUNC_W_S,CEIL_W_S,FLOOR_W_S,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
NI ,CVT_D_S ,NI ,NI ,CVT_W_S ,CVT_L_S ,NI ,NI ,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
C_F_S ,C_UN_S ,C_EQ_S ,C_UEQ_S ,C_OLT_S ,C_ULT_S ,C_OLE_S ,C_ULE_S ,
C_SF_S ,C_NGLE_S ,C_SEQ_S ,C_NGL_S ,C_LT_S ,C_NGE_S ,C_LE_S ,C_NGT_S
};
static void ADD_D()
{
set_rounding();
*reg_cop1_double[cffd] = *reg_cop1_double[cffs] +
*reg_cop1_double[cfft];
interp_addr+=4;
}
static void SUB_D()
{
set_rounding();
*reg_cop1_double[cffd] = *reg_cop1_double[cffs] -
*reg_cop1_double[cfft];
interp_addr+=4;
}
static void MUL_D()
{
set_rounding();
*reg_cop1_double[cffd] = *reg_cop1_double[cffs] *
*reg_cop1_double[cfft];
interp_addr+=4;
}
static void DIV_D()
{
if((FCR31 & 0x400) && *reg_cop1_double[cfft] == 0)
{
//FCR31 |= 0x8020;
/*FCR31 |= 0x8000;
Cause = 15 << 2;
exception_general();*/
printf("div_d by 0\n");
//return;
}
set_rounding();
*reg_cop1_double[cffd] = *reg_cop1_double[cffs] /
*reg_cop1_double[cfft];
interp_addr+=4;
}
static void SQRT_D()
{
set_rounding();
*reg_cop1_double[cffd] = sqrt(*reg_cop1_double[cffs]);
interp_addr+=4;
}
static void ABS_D()
{
set_rounding();
*reg_cop1_double[cffd] = fabs(*reg_cop1_double[cffs]);
interp_addr+=4;
}
static void MOV_D()
{
set_rounding();
*reg_cop1_double[cffd] = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void NEG_D()
{
set_rounding();
*reg_cop1_double[cffd] = -(*reg_cop1_double[cffs]);
interp_addr+=4;
}
static void ROUND_L_D()
{
set_round();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void TRUNC_L_D()
{
set_trunc();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void CEIL_L_D()
{
set_ceil();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void FLOOR_L_D()
{
set_floor();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void ROUND_W_D()
{
set_round();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void TRUNC_W_D()
{
set_trunc();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void CEIL_W_D()
{
set_ceil();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void FLOOR_W_D()
{
set_floor();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void CVT_S_D()
{
set_rounding();
*reg_cop1_simple[cffd] = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void CVT_W_D()
{
set_rounding();
*((int*)reg_cop1_simple[cffd]) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void CVT_L_D()
{
set_rounding();
*((long long*)(reg_cop1_double[cffd])) = *reg_cop1_double[cffs];
interp_addr+=4;
}
static void C_F_D()
{
FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_UN_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_EQ_D()
{
if (!isnan(*reg_cop1_double[cffs]) && !isnan(*reg_cop1_double[cfft]) &&
*reg_cop1_double[cffs] == *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_UEQ_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]) ||
*reg_cop1_double[cffs] == *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_OLT_D()
{
if (!isnan(*reg_cop1_double[cffs]) && !isnan(*reg_cop1_double[cfft]) &&
*reg_cop1_double[cffs] < *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_ULT_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]) ||
*reg_cop1_double[cffs] < *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_OLE_D()
{
if (!isnan(*reg_cop1_double[cffs]) && !isnan(*reg_cop1_double[cfft]) &&
*reg_cop1_double[cffs] <= *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_ULE_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]) ||
*reg_cop1_double[cffs] <= *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_SF_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGLE_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_SEQ_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_double[cffs] == *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGL_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_double[cffs] == *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_LT_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_double[cffs] < *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGE_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_double[cffs] < *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_LE_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_double[cffs] <= *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void C_NGT_D()
{
if (isnan(*reg_cop1_double[cffs]) || isnan(*reg_cop1_double[cfft]))
{
printf("Invalid operation exception in C opcode\n");
stop=1;
}
if (*reg_cop1_double[cffs] <= *reg_cop1_double[cfft])
FCR31 |= 0x800000;
else FCR31 &= ~0x800000;
interp_addr+=4;
}
static void (*interp_cop1_d[64])(void) =
{
ADD_D ,SUB_D ,MUL_D ,DIV_D ,SQRT_D ,ABS_D ,MOV_D ,NEG_D ,
ROUND_L_D,TRUNC_L_D,CEIL_L_D,FLOOR_L_D,ROUND_W_D,TRUNC_W_D,CEIL_W_D,FLOOR_W_D,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
CVT_S_D ,NI ,NI ,NI ,CVT_W_D ,CVT_L_D ,NI ,NI ,
NI ,NI ,NI ,NI ,NI ,NI ,NI ,NI ,
C_F_D ,C_UN_D ,C_EQ_D ,C_UEQ_D ,C_OLT_D ,C_ULT_D ,C_OLE_D ,C_ULE_D ,
C_SF_D ,C_NGLE_D ,C_SEQ_D ,C_NGL_D ,C_LT_D ,C_NGE_D ,C_LE_D ,C_NGT_D
};
static void CVT_S_W()
{
set_rounding();
*reg_cop1_simple[cffd] = *((int*)reg_cop1_simple[cffs]);
interp_addr+=4;
}
static void CVT_D_W()
{
set_rounding();
*reg_cop1_double[cffd] = *((int*)reg_cop1_simple[cffs]);
interp_addr+=4;
}
static void (*interp_cop1_w[64])(void) =
{
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
CVT_S_W, CVT_D_W, NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI
};
static void CVT_S_L()
{
set_rounding();
*reg_cop1_simple[cffd] = *((long long*)(reg_cop1_double[cffs]));
interp_addr+=4;
}
static void CVT_D_L()
{
set_rounding();
*reg_cop1_double[cffd] = *((long long*)(reg_cop1_double[cffs]));
interp_addr+=4;
}
static void (*interp_cop1_l[64])(void) =
{
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
CVT_S_L, CVT_D_L, NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI,
NI , NI , NI, NI, NI, NI, NI, NI
};
static void MFC1()
{
rrt32 = *((int*)reg_cop1_simple[rfs]);
sign_extended(rrt);
interp_addr+=4;
}
static void DMFC1()
{
rrt = *((long long*)(reg_cop1_double[rfs]));
interp_addr+=4;
}
static void CFC1()
{
if (rfs==31)
{
rrt32 = FCR31;
sign_extended(rrt);
}
if (rfs==0)
{
rrt32 = FCR0;
sign_extended(rrt);
}
interp_addr+=4;
}
static void MTC1()
{
*((int*)reg_cop1_simple[rfs]) = rrt32;
interp_addr+=4;
}
static void DMTC1()
{
*((long long*)reg_cop1_double[rfs]) = rrt;
interp_addr+=4;
}
static void CTC1()
{
if (rfs==31)
FCR31 = rrt32;
switch((FCR31 & 3))
{
case 0:
rounding_mode = 0x33F;
break;
case 1:
rounding_mode = 0xF3F;
break;
case 2:
rounding_mode = 0xB3F;
break;
case 3:
rounding_mode = 0x73F;
break;
}
//if ((FCR31 >> 7) & 0x1F) printf("FPU Exception enabled : %x\n",
// (int)((FCR31 >> 7) & 0x1F));
interp_addr+=4;
}
static void BC()
{
interp_cop1_bc[(op >> 16) & 3]();
}
static void S()
{
interp_cop1_s[(op & 0x3F)]();
}
static void D()
{
interp_cop1_d[(op & 0x3F)]();
}
static void W()
{
interp_cop1_w[(op & 0x3F)]();
}
static void L()
{
interp_cop1_l[(op & 0x3F)]();
}
static void (*interp_cop1[32])(void) =
{
MFC1, DMFC1, CFC1, NI, MTC1, DMTC1, CTC1, NI,
BC , NI , NI , NI, NI , NI , NI , NI,
S , D , NI , NI, W , L , NI , NI,
NI , NI , NI , NI, NI , NI , NI , NI
};
static void SPECIAL()
{
interp_special[(op & 0x3F)]();
}
static void REGIMM()
{
interp_regimm[((op >> 16) & 0x1F)]();
}
static void J()
{
unsigned int naddr = (PC->f.j.inst_index<<2) | (interp_addr & 0xF0000000);
if (naddr == interp_addr)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr = naddr;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void JAL()
{
unsigned int naddr = (PC->f.j.inst_index<<2) | (interp_addr & 0xF0000000);
if (naddr == interp_addr)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (!skip_jump)
{
reg[31]=interp_addr;
sign_extended(reg[31]);
interp_addr = naddr;
}
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BEQ()
{
short local_immediate = iimmediate;
local_rs = irs;
local_rt = irt;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs == local_rt)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (local_rs == local_rt)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BNE()
{
short local_immediate = iimmediate;
local_rs = irs;
local_rt = irt;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs != local_rt)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (local_rs != local_rt)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BLEZ()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs <= 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (local_rs <= 0)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BGTZ()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (local_rs > 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
if (local_rs > 0)
interp_addr += (local_immediate-1)*4;
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void ADDI()
{
irt32 = irs32 + iimmediate;
sign_extended(irt);
interp_addr+=4;
}
static void ADDIU()
{
irt32 = irs32 + iimmediate;
sign_extended(irt);
interp_addr+=4;
}
static void SLTI()
{
if (irs < iimmediate) irt = 1;
else irt = 0;
interp_addr+=4;
}
static void SLTIU()
{
if ((unsigned long long)irs < (unsigned long long)((long long)iimmediate))
irt = 1;
else irt = 0;
interp_addr+=4;
}
static void ANDI()
{
irt = irs & (unsigned short)iimmediate;
interp_addr+=4;
}
static void ORI()
{
irt = irs | (unsigned short)iimmediate;
interp_addr+=4;
}
static void XORI()
{
irt = irs ^ (unsigned short)iimmediate;
interp_addr+=4;
}
static void LUI()
{
irt32 = iimmediate << 16;
sign_extended(irt);
interp_addr+=4;
}
static void COP0()
{
interp_cop0[((op >> 21) & 0x1F)]();
}
static void COP1()
{
if (check_cop1_unusable()) return;
interp_cop1[((op >> 21) & 0x1F)]();
}
static void BEQL()
{
short local_immediate = iimmediate;
local_rs = irs;
local_rt = irt;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (irs == irt)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (local_rs == local_rt)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else
{
interp_addr+=8;
update_count();
}
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BNEL()
{
short local_immediate = iimmediate;
local_rs = irs;
local_rt = irt;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (irs != irt)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (local_rs != local_rt)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else
{
interp_addr+=8;
update_count();
}
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BLEZL()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (irs <= 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (local_rs <= 0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else
{
interp_addr+=8;
update_count();
}
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void BGTZL()
{
short local_immediate = iimmediate;
local_rs = irs;
if ((interp_addr + (local_immediate+1)*4) == interp_addr)
if (irs > 0)
{
if (probe_nop(interp_addr+4))
{
update_count();
skip = next_interupt - Count;
if (skip > 3)
{
Count += (skip & 0xFFFFFFFC);
return;
}
}
}
if (local_rs > 0)
{
interp_addr+=4;
delay_slot=1;
prefetch();
interp_ops[((op >> 26) & 0x3F)]();
update_count();
delay_slot=0;
interp_addr += (local_immediate-1)*4;
}
else
{
interp_addr+=8;
update_count();
}
last_addr = interp_addr;
if (next_interupt <= Count) gen_interupt();
}
static void DADDI()
{
irt = irs + iimmediate;
interp_addr+=4;
}
static void DADDIU()
{
irt = irs + iimmediate;
interp_addr+=4;
}
static void LDL()
{
unsigned long long int word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 7)
{
case 0:
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
read_dword_in_memory();
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFF) | (word << 8);
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFF) | (word << 16);
break;
case 3:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFF) | (word << 24);
break;
case 4:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFF) | (word << 32);
break;
case 5:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFFFFLL) | (word << 40);
break;
case 6:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFFFFFFLL) | (word << 48);
break;
case 7:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFFFFFFFFLL) | (word << 56);
break;
}
}
static void LDR()
{
unsigned long long int word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 7)
{
case 0:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFFFFFFFF00LL) | (word >> 56);
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFFFFFF0000LL) | (word >> 48);
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFFFF000000LL) | (word >> 40);
break;
case 3:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFFFF00000000LL) | (word >> 32);
break;
case 4:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFFFF0000000000LL) | (word >> 24);
break;
case 5:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFFFF000000000000LL) | (word >> 16);
break;
case 6:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &word;
read_dword_in_memory();
irt = (irt & 0xFF00000000000000LL) | (word >> 8);
break;
case 7:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = (unsigned long long *) &irt;
read_dword_in_memory();
break;
}
}
static void LB()
{
interp_addr+=4;
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
read_byte_in_memory();
sign_extendedb(irt);
}
static void LH()
{
interp_addr+=4;
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
read_hword_in_memory();
sign_extendedh(irt);
}
static void LWL()
{
unsigned long long int word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 3)
{
case 0:
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
read_word_in_memory();
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &word;
read_word_in_memory();
irt = (irt & 0xFF) | (word << 8);
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &word;
read_word_in_memory();
irt = (irt & 0xFFFF) | (word << 16);
break;
case 3:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &word;
read_word_in_memory();
irt = (irt & 0xFFFFFF) | (word << 24);
break;
}
sign_extended(irt);
}
static void LW()
{
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
interp_addr+=4;
read_word_in_memory();
sign_extended(irt);
}
static void LBU()
{
interp_addr+=4;
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
read_byte_in_memory();
}
static void LHU()
{
interp_addr+=4;
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
read_hword_in_memory();
}
static void LWR()
{
unsigned long long int word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 3)
{
case 0:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &word;
read_word_in_memory();
irt = (irt & 0xFFFFFFFFFFFFFF00LL) | ((word >> 24) & 0xFF);
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &word;
read_word_in_memory();
irt = (irt & 0xFFFFFFFFFFFF0000LL) | ((word >> 16) & 0xFFFF);
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &word;
read_word_in_memory();
irt = (irt & 0xFFFFFFFFFF000000LL) | ((word >> 8) & 0xFFFFFF);
break;
case 3:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = (unsigned long long *) &irt;
read_word_in_memory();
sign_extended(irt);
}
}
static void LWU()
{
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
interp_addr+=4;
read_word_in_memory();
}
static void SB()
{
interp_addr+=4;
address = iimmediate + irs32;
byte = (unsigned char)(irt & 0xFF);
write_byte_in_memory();
}
static void SH()
{
interp_addr+=4;
address = iimmediate + irs32;
hword = (unsigned short)(irt & 0xFFFF);
write_hword_in_memory();
}
static void SWL()
{
unsigned long long int old_word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 3)
{
case 0:
address = (iimmediate + irs32) & 0xFFFFFFFC;
word = (unsigned int)irt;
write_word_in_memory();
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &old_word;
read_word_in_memory();
word = ((unsigned int)irt >> 8) | (old_word & 0xFF000000);
write_word_in_memory();
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &old_word;
read_word_in_memory();
word = ((unsigned int)irt >> 16) | (old_word & 0xFFFF0000);
write_word_in_memory();
break;
case 3:
address = iimmediate + irs32;
byte = (unsigned char)(irt >> 24);
write_byte_in_memory();
break;
}
}
static void SW()
{
interp_addr+=4;
address = iimmediate + irs32;
word = (unsigned int)(irt & 0xFFFFFFFF);
write_word_in_memory();
}
static void SDL()
{
unsigned long long int old_word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 7)
{
case 0:
address = (iimmediate + irs32) & 0xFFFFFFF8;
dword = irt;
write_dword_in_memory();
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = ((unsigned long long)irt >> 8)|(old_word & 0xFF00000000000000LL);
write_dword_in_memory();
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = ((unsigned long long)irt >> 16)|(old_word & 0xFFFF000000000000LL);
write_dword_in_memory();
break;
case 3:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = ((unsigned long long)irt >> 24)|(old_word & 0xFFFFFF0000000000LL);
write_dword_in_memory();
break;
case 4:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = ((unsigned long long)irt >> 32)|(old_word & 0xFFFFFFFF00000000LL);
write_dword_in_memory();
break;
case 5:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = ((unsigned long long)irt >> 40)|(old_word & 0xFFFFFFFFFF000000LL);
write_dword_in_memory();
break;
case 6:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = ((unsigned long long)irt >> 48)|(old_word & 0xFFFFFFFFFFFF0000LL);
write_dword_in_memory();
break;
case 7:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = ((unsigned long long)irt >> 56)|(old_word & 0xFFFFFFFFFFFFFF00LL);
write_dword_in_memory();
break;
}
}
static void SDR()
{
unsigned long long int old_word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 7)
{
case 0:
address = iimmediate + irs32;
rdword = &old_word;
read_dword_in_memory();
dword = (irt << 56) | (old_word & 0x00FFFFFFFFFFFFFFLL);
write_dword_in_memory();
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = (irt << 48) | (old_word & 0x0000FFFFFFFFFFFFLL);
write_dword_in_memory();
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = (irt << 40) | (old_word & 0x000000FFFFFFFFFFLL);
write_dword_in_memory();
break;
case 3:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = (irt << 32) | (old_word & 0x00000000FFFFFFFFLL);
write_dword_in_memory();
break;
case 4:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = (irt << 24) | (old_word & 0x0000000000FFFFFFLL);
write_dword_in_memory();
break;
case 5:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = (irt << 16) | (old_word & 0x000000000000FFFFLL);
write_dword_in_memory();
break;
case 6:
address = (iimmediate + irs32) & 0xFFFFFFF8;
rdword = &old_word;
read_dword_in_memory();
dword = (irt << 8) | (old_word & 0x00000000000000FFLL);
write_dword_in_memory();
break;
case 7:
address = (iimmediate + irs32) & 0xFFFFFFF8;
dword = irt;
write_dword_in_memory();
break;
}
}
static void SWR()
{
unsigned long long int old_word = 0;
interp_addr+=4;
switch ((iimmediate + irs32) & 3)
{
case 0:
address = iimmediate + irs32;
rdword = &old_word;
read_word_in_memory();
word = ((unsigned int)irt << 24) | (old_word & 0x00FFFFFF);
write_word_in_memory();
break;
case 1:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &old_word;
read_word_in_memory();
word = ((unsigned int)irt << 16) | (old_word & 0x0000FFFF);
write_word_in_memory();
break;
case 2:
address = (iimmediate + irs32) & 0xFFFFFFFC;
rdword = &old_word;
read_word_in_memory();
word = ((unsigned int)irt << 8) | (old_word & 0x000000FF);
write_word_in_memory();
break;
case 3:
address = (iimmediate + irs32) & 0xFFFFFFFC;
word = (unsigned int)irt;
write_word_in_memory();
break;
}
}
static void CACHE()
{
interp_addr+=4;
}
static void LL()
{
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
interp_addr+=4;
read_word_in_memory();
sign_extended(irt);
llbit = 1;
}
static void LWC1()
{
unsigned long long int temp;
if (check_cop1_unusable()) return;
interp_addr+=4;
address = lfoffset+reg[lfbase];
rdword = &temp;
read_word_in_memory();
*((int*)reg_cop1_simple[lfft]) = *rdword;
}
static void LDC1()
{
if (check_cop1_unusable()) return;
interp_addr+=4;
address = lfoffset+reg[lfbase];
rdword = (unsigned long long*) reg_cop1_double[lfft];
read_dword_in_memory();
}
static void LD()
{
interp_addr+=4;
address = iimmediate + irs32;
rdword = (unsigned long long *) &irt;
read_dword_in_memory();
}
static void SC()
{
interp_addr+=4;
if(llbit)
{
address = iimmediate + irs32;
word = (unsigned int)(irt & 0xFFFFFFFF);
write_word_in_memory();
llbit = 0;
irt = 1;
}
else
{
irt = 0;
}
}
static void SWC1()
{
if (check_cop1_unusable()) return;
interp_addr+=4;
address = lfoffset+reg[lfbase];
word = *((int*)reg_cop1_simple[lfft]);
write_word_in_memory();
}
static void SDC1()
{
if (check_cop1_unusable()) return;
interp_addr+=4;
address = lfoffset+reg[lfbase];
dword = *((unsigned long long*)reg_cop1_double[lfft]);
write_dword_in_memory();
}
static void SD()
{
interp_addr+=4;
address = iimmediate + irs32;
dword = irt;
write_dword_in_memory();
}
static void (*interp_ops[64])(void) =
{
SPECIAL, REGIMM, J , JAL , BEQ , BNE , BLEZ , BGTZ ,
ADDI , ADDIU , SLTI, SLTIU, ANDI, ORI , XORI , LUI ,
COP0 , COP1 , NI , NI , BEQL, BNEL, BLEZL, BGTZL,
DADDI , DADDIU, LDL , LDR , NI , NI , NI , NI ,
LB , LH , LWL , LW , LBU , LHU , LWR , LWU ,
SB , SH , SWL , SW , SDL , SDR , SWR , CACHE,
LL , LWC1 , NI , NI , NI , LDC1, NI , LD ,
SC , SWC1 , NI , NI , NI , SDC1, NI , SD
};
void prefetch()
{
//static FILE *f = NULL;
//static int line=1;
//static int tlb_used = 0;
//unsigned int comp;
//if (!tlb_used)
//{
/*if (f==NULL) f = fopen("/mnt/windows/pcdeb.txt", "rb");
fscanf(f, "%x", &comp);
if (comp != interp_addr)
{
printf("diff@%x, line:%d\n", interp_addr, line);
stop=1;
}*/
//line++;
//if ((debug_count+Count) > 0x50fe000) printf("line:%d\n", line);
/*if ((debug_count+Count) > 0xb70000)
printf("count:%x, add:%x, op:%x, l%d\n", (int)(Count+debug_count),
interp_addr, op, line);*/
//}
//printf("addr:%x\n", interp_addr);
if ((interp_addr >= 0x80000000) && (interp_addr < 0xc0000000))
{
if ((interp_addr >= 0x80000000) && (interp_addr < 0x80800000))
{
op = rdram[(interp_addr&0xFFFFFF)/4];
/*if ((debug_count+Count) > 0xabaa20)
printf("count:%x, add:%x, op:%x, l%d\n", (int)(Count+debug_count),
interp_addr, op, line);*/
prefetch_opcode(op);
}
else if ((interp_addr >= 0xa4000000) && (interp_addr < 0xa4001000))
{
op = SP_DMEM[(interp_addr&0xFFF)/4];
prefetch_opcode(op);
}
else if ((interp_addr > 0xb0000000))
{
op = ((unsigned int*)rom)[(interp_addr & 0xFFFFFFF)/4];
prefetch_opcode(op);
}
else
{
printf("execution <20> l'addresse :%x\n", (int)interp_addr);
stop=1;
}
}
else
{
unsigned int addr = interp_addr, phys;
phys = virtual_to_physical_address(interp_addr, 2);
if (phys != 0x00000000) interp_addr = phys;
else
{
prefetch();
//tlb_used = 0;
return;
}
//tlb_used = 1;
prefetch();
//tlb_used = 0;
interp_addr = addr;
}
}
void pure_interpreter()
{
interp_addr = 0xa4000040;
stop=0;
PC = malloc(sizeof(precomp_instr));
PC->addr = last_addr = interp_addr;
/*#ifdef DBG
if (debugger_mode)
update_debugger(PC->addr);
#endif*/
while (!stop)
{
//if (interp_addr == 0x10022d08) stop = 1;
prefetch();
#ifdef COMPARE_CORE
compare_core();
#endif
//if (Count > 0x2000000) printf("inter:%x,%x\n", interp_addr,op);
//if ((Count+debug_count) > 0xabaa2c) stop=1;
#ifdef DBG
PC->addr = interp_addr;
if (debugger_mode) update_debugger(PC->addr);
#endif
interp_ops[((op >> 26) & 0x3F)]();
//Count = (unsigned int)Count + 2;
//if (interp_addr == 0x80000180) last_addr = interp_addr;
}
PC->addr = interp_addr;
}
void interprete_section(unsigned int addr)
{
interp_addr = addr;
PC = malloc(sizeof(precomp_instr));
last_addr = interp_addr;
while (!stop && (addr >> 12) == (interp_addr >> 12))
{
prefetch();
#ifdef COMPARE_CORE
compare_core();
#endif
PC->addr = interp_addr;
interp_ops[((op >> 26) & 0x3F)]();
#ifdef DBG
PC->addr = interp_addr;
if (debugger_mode) update_debugger(PC->addr);
#endif
}
PC->addr = interp_addr;
}