more vjaguar cleanup
This commit is contained in:
parent
80cf3a0c48
commit
6388e4a0a8
Binary file not shown.
|
@ -356,7 +356,7 @@ EXPORT void GetRegisters(u32* regs)
|
|||
{
|
||||
for (u32 i = 0; i < 18; i++)
|
||||
{
|
||||
regs[i] = m68k_get_reg(NULL, (m68k_register_t)i);
|
||||
regs[i] = m68k_get_reg((m68k_register_t)i);
|
||||
}
|
||||
memcpy(®s[18], gpu_reg_bank_0, 128);
|
||||
memcpy(®s[50], gpu_reg_bank_1, 128);
|
||||
|
|
|
@ -336,7 +336,7 @@ static void ResetCallbacks(void)
|
|||
|
||||
static void LoadISRStub(void)
|
||||
{
|
||||
uint32_t isrAddr = m68k_get_reg(NULL, M68K_REG_A0);
|
||||
uint32_t isrAddr = m68k_get_reg(M68K_REG_A0);
|
||||
uint32_t addr = 0xF03010;
|
||||
|
||||
#define WRITE_GASM(x) do { GPUWriteWord(addr, x, M68K); addr += 2; } while (0)
|
||||
|
@ -405,7 +405,7 @@ void CDHLEHook(uint32_t which)
|
|||
|
||||
static void CD_init(void)
|
||||
{
|
||||
fprintf(stderr, "CD_init called %08X\n", m68k_get_reg(NULL, M68K_REG_A0));
|
||||
fprintf(stderr, "CD_init called %08X\n", m68k_get_reg(M68K_REG_A0));
|
||||
LoadISRStub();
|
||||
cd_initm = false;
|
||||
}
|
||||
|
@ -414,7 +414,7 @@ static void CD_mode(void)
|
|||
{
|
||||
// bit 0 = speed (0 = single, 1 = double)
|
||||
// bit 1 = mode (0 = audio, 1 = data)
|
||||
cd_mode = m68k_get_reg(NULL, M68K_REG_D0) & 3;
|
||||
cd_mode = m68k_get_reg(M68K_REG_D0) & 3;
|
||||
fprintf(stderr, "CD_mode mode = %d, speed = %d\n", cd_mode >> 1, cd_mode & 1);
|
||||
NO_ERR();
|
||||
}
|
||||
|
@ -426,7 +426,7 @@ static void CD_ack(void)
|
|||
|
||||
static void CD_jeri(void)
|
||||
{
|
||||
bool njerry = m68k_get_reg(NULL, M68K_REG_D0) & 1;
|
||||
bool njerry = m68k_get_reg(M68K_REG_D0) & 1;
|
||||
if (cd_jerry ^ njerry)
|
||||
{
|
||||
fprintf(stderr, "changing jerry mode %d -> %d\n", cd_jerry, njerry);
|
||||
|
@ -437,7 +437,7 @@ static void CD_jeri(void)
|
|||
|
||||
static void CD_spin(void)
|
||||
{
|
||||
fprintf(stderr, "CD_spin: new session %04X\n", m68k_get_reg(NULL, M68K_REG_D1) & 0xFFFF);
|
||||
fprintf(stderr, "CD_spin: new session %04X\n", m68k_get_reg(M68K_REG_D1) & 0xFFFF);
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
|
@ -486,8 +486,8 @@ static void CD_upaus(void)
|
|||
|
||||
static void CD_read(void)
|
||||
{
|
||||
uint32_t dstStart = m68k_get_reg(NULL, M68K_REG_A0);
|
||||
uint32_t dstEnd = m68k_get_reg(NULL, M68K_REG_A1);
|
||||
uint32_t dstStart = m68k_get_reg(M68K_REG_A0);
|
||||
uint32_t dstEnd = m68k_get_reg(M68K_REG_A1);
|
||||
|
||||
fprintf(stderr, "CD READ: dstStart %08X, dstEnd %08X\n", dstStart, dstEnd);
|
||||
|
||||
|
@ -498,7 +498,7 @@ static void CD_read(void)
|
|||
return;
|
||||
}
|
||||
|
||||
uint32_t timecode = m68k_get_reg(NULL, M68K_REG_D0);
|
||||
uint32_t timecode = m68k_get_reg(M68K_REG_D0);
|
||||
|
||||
uint32_t frames = timecode & 0xFF;
|
||||
uint32_t seconds = (timecode >> 8) & 0xFF;
|
||||
|
@ -517,8 +517,8 @@ static void CD_read(void)
|
|||
{
|
||||
if (cd_initm)
|
||||
{
|
||||
uint32_t marker = m68k_get_reg(NULL, M68K_REG_D1);
|
||||
uint32_t circBufSz = m68k_get_reg(NULL, M68K_REG_D2);
|
||||
uint32_t marker = m68k_get_reg(M68K_REG_D1);
|
||||
uint32_t circBufSz = m68k_get_reg(M68K_REG_D2);
|
||||
fprintf(stderr, "cd_initm read: marker %04X, circBufSz %04X\n", marker, circBufSz);
|
||||
uint32_t lba = (minutes * 60 + seconds) * 75 + frames - 150;
|
||||
uint8_t buf2352[2352 + 128];
|
||||
|
@ -630,7 +630,7 @@ static void CD_ptr(void)
|
|||
|
||||
static void CD_osamp(void)
|
||||
{
|
||||
cd_osamp = m68k_get_reg(NULL, M68K_REG_D0) & 3;
|
||||
cd_osamp = m68k_get_reg(M68K_REG_D0) & 3;
|
||||
NO_ERR();
|
||||
}
|
||||
|
||||
|
@ -641,14 +641,14 @@ static void CD_getoc(void)
|
|||
|
||||
static void CD_initm(void)
|
||||
{
|
||||
fprintf(stderr, "CD_initm called %08X\n", m68k_get_reg(NULL, M68K_REG_A0));
|
||||
fprintf(stderr, "CD_initm called %08X\n", m68k_get_reg(M68K_REG_A0));
|
||||
LoadISRStub();
|
||||
cd_initm = true;
|
||||
}
|
||||
|
||||
static void CD_initf(void)
|
||||
{
|
||||
fprintf(stderr, "CD_initf called %08X\n", m68k_get_reg(NULL, M68K_REG_A0));
|
||||
fprintf(stderr, "CD_initf called %08X\n", m68k_get_reg(M68K_REG_A0));
|
||||
LoadISRStub();
|
||||
cd_initm = false;
|
||||
}
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
#include <stdlib.h>
|
||||
#include "dac.h"
|
||||
#include "gpu.h"
|
||||
#include "jagdasm.h"
|
||||
#include "jaguar.h"
|
||||
#include "jerry.h"
|
||||
#include "m68000/m68kinterface.h"
|
||||
|
|
|
@ -27,7 +27,6 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "dsp.h"
|
||||
#include "jagdasm.h"
|
||||
#include "jaguar.h"
|
||||
#include "m68000/m68kinterface.h"
|
||||
#include "tom.h"
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
//
|
||||
// Jaguar RISC Disassembly
|
||||
//
|
||||
// Originally by David Raingeard
|
||||
// GCC/SDL port by Niels Wagenaar (Linux/WIN32) and Carwin Jones (BeOS)
|
||||
// Minor cleanups by James Hammons
|
||||
// (C) 2012 Underground Software
|
||||
//
|
||||
// JLH = James Hammons <jlhamm@acm.org>
|
||||
//
|
||||
// Who When What
|
||||
// --- ---------- -------------------------------------------------------------
|
||||
// JLH 06/01/2012 Created this log (long overdue! ;-)
|
||||
// JLH 01/23/2013 Beautifying of disassembly, including hex digits of opcodes
|
||||
// and operands
|
||||
//
|
||||
|
||||
#include "jagdasm.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include "jaguar.h"
|
||||
|
||||
#define ROPCODE(a) JaguarReadWord(a)
|
||||
|
||||
uint8_t convert_zero[32] =
|
||||
{ 32,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 };
|
||||
|
||||
const char * condition[32] =
|
||||
{
|
||||
"",
|
||||
"nz,",
|
||||
"z,",
|
||||
"???,",
|
||||
"nc,",
|
||||
"nc nz,",
|
||||
"nc z,",
|
||||
"???,",
|
||||
|
||||
"c,",
|
||||
"c nz,",
|
||||
"c z,",
|
||||
"???,",
|
||||
"???,",
|
||||
"???,",
|
||||
"???,",
|
||||
"???,",
|
||||
|
||||
"???,",
|
||||
"???,",
|
||||
"???,",
|
||||
"???,",
|
||||
"nn,",
|
||||
"nn nz,",
|
||||
"nn z,",
|
||||
"???,",
|
||||
|
||||
"n,",
|
||||
"n nz,",
|
||||
"n z,",
|
||||
"???,",
|
||||
"???,",
|
||||
"???,",
|
||||
"???,",
|
||||
"never,"
|
||||
};
|
||||
|
||||
char * signed_16bit(int16_t val)
|
||||
{
|
||||
static char temp[10];
|
||||
|
||||
if (val < 0)
|
||||
sprintf(temp, "-$%X", -val);
|
||||
else
|
||||
sprintf(temp, "$%X", val);
|
||||
|
||||
return temp;
|
||||
}
|
||||
|
||||
unsigned dasmjag(int dsp_type, char * bufferOut, unsigned pc)
|
||||
{
|
||||
char buffer[64];
|
||||
int op = ROPCODE(pc);
|
||||
int reg1 = (op >> 5) & 31;
|
||||
int reg2 = op & 31;
|
||||
int size = 2;
|
||||
pc += 2;
|
||||
|
||||
switch (op >> 10)
|
||||
{
|
||||
case 0: sprintf(buffer, "ADD R%02d,R%02d", reg1, reg2); break;
|
||||
case 1: sprintf(buffer, "ADDC R%02d,R%02d", reg1, reg2); break;
|
||||
case 2: sprintf(buffer, "ADDQ $%X,R%02d", convert_zero[reg1], reg2); break;
|
||||
case 3: sprintf(buffer, "ADDQT $%X,R%02d", convert_zero[reg1], reg2); break;
|
||||
case 4: sprintf(buffer, "SUB R%02d,R%02d", reg1, reg2); break;
|
||||
case 5: sprintf(buffer, "SUBC R%02d,R%02d", reg1, reg2); break;
|
||||
case 6: sprintf(buffer, "SUBQ $%X,R%02d", convert_zero[reg1], reg2); break;
|
||||
case 7: sprintf(buffer, "SUBQT $%X,R%02d", convert_zero[reg1], reg2); break;
|
||||
case 8: sprintf(buffer, "NEG R%02d", reg2); break;
|
||||
case 9: sprintf(buffer, "AND R%02d,R%02d", reg1, reg2); break;
|
||||
case 10: sprintf(buffer, "OR R%02d,R%02d", reg1, reg2); break;
|
||||
case 11: sprintf(buffer, "XOR R%02d,R%02d", reg1, reg2); break;
|
||||
case 12: sprintf(buffer, "NOT R%02d", reg2); break;
|
||||
case 13: sprintf(buffer, "BTST $%X,R%02d", reg1, reg2); break;
|
||||
case 14: sprintf(buffer, "BSET $%X,R%02d", reg1, reg2); break;
|
||||
case 15: sprintf(buffer, "BCLR $%X,R%02d", reg1, reg2); break;
|
||||
case 16: sprintf(buffer, "MULT R%02d,R%02d", reg1, reg2); break;
|
||||
case 17: sprintf(buffer, "IMULT R%02d,R%02d", reg1, reg2); break;
|
||||
case 18: sprintf(buffer, "IMULTN R%02d,R%02d", reg1, reg2); break;
|
||||
case 19: sprintf(buffer, "RESMAC R%02d", reg2); break;
|
||||
case 20: sprintf(buffer, "IMACN R%02d,R%02d", reg1, reg2); break;
|
||||
case 21: sprintf(buffer, "DIV R%02d,R%02d", reg1, reg2); break;
|
||||
case 22: sprintf(buffer, "ABS R%02d", reg2); break;
|
||||
case 23: sprintf(buffer, "SH R%02d,R%02d", reg1, reg2); break;
|
||||
case 24: sprintf(buffer, "SHLQ $%X,R%02d", 32 - reg1, reg2); break;
|
||||
case 25: sprintf(buffer, "SHRQ $%X,R%02d", convert_zero[reg1], reg2); break;
|
||||
case 26: sprintf(buffer, "SHA R%02d,R%02d", reg1, reg2); break;
|
||||
case 27: sprintf(buffer, "SHARQ $%X,R%02d", convert_zero[reg1], reg2); break;
|
||||
case 28: sprintf(buffer, "ROR R%02d,R%02d", reg1, reg2); break;
|
||||
case 29: sprintf(buffer, "RORQ $%X,R%02d", convert_zero[reg1], reg2); break;
|
||||
case 30: sprintf(buffer, "CMP R%02d,R%02d", reg1, reg2); break;
|
||||
case 31: sprintf(buffer, "CMPQ %s,R%02d", signed_16bit((int16_t)(reg1 << 11) >> 11), reg2);break;
|
||||
case 32: if (dsp_type == JAGUAR_GPU)
|
||||
sprintf(buffer, "SAT8 R%02d", reg2);
|
||||
else
|
||||
sprintf(buffer, "SUBQMOD $%X,R%02d", convert_zero[reg1], reg2);
|
||||
break;
|
||||
case 33: if (dsp_type == JAGUAR_GPU)
|
||||
sprintf(buffer, "SAT16 R%02d", reg2);
|
||||
else
|
||||
sprintf(buffer, "SAT16S R%02d", reg2);
|
||||
break;
|
||||
case 34: sprintf(buffer, "MOVE R%02d,R%02d", reg1, reg2); break;
|
||||
case 35: sprintf(buffer, "MOVEQ %d,R%02d", reg1, reg2); break;
|
||||
case 36: sprintf(buffer, "MOVETA R%02d,R%02d", reg1, reg2); break;
|
||||
case 37: sprintf(buffer, "MOVEFA R%02d,R%02d", reg1, reg2); break;
|
||||
case 38: sprintf(buffer, "MOVEI #$%X,R%02d", ROPCODE(pc) | (ROPCODE(pc+2)<<16), reg2); size = 6; break;
|
||||
case 39: sprintf(buffer, "LOADB (R%02d),R%02d", reg1, reg2); break;
|
||||
case 40: sprintf(buffer, "LOADW (R%02d),R%02d", reg1, reg2); break;
|
||||
case 41: sprintf(buffer, "LOAD (R%02d),R%02d", reg1, reg2); break;
|
||||
case 42: if (dsp_type == JAGUAR_GPU)
|
||||
sprintf(buffer, "LOADP (R%02d),R%02d", reg1, reg2);
|
||||
else
|
||||
sprintf(buffer, "SAT32S R%02d", reg2);
|
||||
break;
|
||||
case 43: sprintf(buffer, "LOAD (R14+$%X),R%02d", convert_zero[reg1]*4, reg2);break;
|
||||
case 44: sprintf(buffer, "LOAD (R15+$%X),R%02d", convert_zero[reg1]*4, reg2);break;
|
||||
case 45: sprintf(buffer, "STOREB R%02d,(R%02d)", reg2, reg1); break;
|
||||
case 46: sprintf(buffer, "STOREW R%02d,(R%02d)", reg2, reg1); break;
|
||||
case 47: sprintf(buffer, "STORE R%02d,(R%02d)", reg2, reg1); break;
|
||||
case 48: if (dsp_type == JAGUAR_GPU)
|
||||
sprintf(buffer, "STOREP R%02d,(R%02d)", reg2, reg1);
|
||||
else
|
||||
sprintf(buffer, "MIRROR R%02d", reg2);
|
||||
break;
|
||||
case 49: sprintf(buffer, "STORE R%02d,(R14+$%X)", reg2, convert_zero[reg1]*4);break;
|
||||
case 50: sprintf(buffer, "STORE R%02d,(R15+$%X)", reg2, convert_zero[reg1]*4);break;
|
||||
case 51: sprintf(buffer, "MOVE PC,R%02d", reg2); break;
|
||||
case 52: sprintf(buffer, "JUMP %s(R%02d)", condition[reg2], reg1); break;
|
||||
case 53: sprintf(buffer, "JR %s$%X", condition[reg2], pc + ((int8_t)(reg1 << 3) >> 2)); break;
|
||||
case 54: sprintf(buffer, "MMULT R%02d,R%02d", reg1, reg2); break;
|
||||
case 55: sprintf(buffer, "MTOI R%02d,R%02d", reg1, reg2); break;
|
||||
case 56: sprintf(buffer, "NORMI R%02d,R%02d", reg1, reg2); break;
|
||||
case 57: sprintf(buffer, "NOP"); break;
|
||||
case 58: sprintf(buffer, "LOAD (R14+R%02d),R%02d", reg1, reg2); break;
|
||||
case 59: sprintf(buffer, "LOAD (R15+R%02d),R%02d", reg1, reg2); break;
|
||||
case 60: sprintf(buffer, "STORE R%02d,(R14+R%02d)", reg2, reg1); break;
|
||||
case 61: sprintf(buffer, "STORE R%02d,(R15+R%02d)", reg2, reg1); break;
|
||||
case 62: if (dsp_type == JAGUAR_GPU)
|
||||
sprintf(buffer, "SAT24 R%02d", reg2);
|
||||
else
|
||||
sprintf(buffer, "illegal [%d,%d]", reg1, reg2);
|
||||
break;
|
||||
case 63: if (dsp_type == JAGUAR_GPU)
|
||||
sprintf(buffer, (reg1 ? "UNPACK R%02d" : "PACK R%02d"), reg2);
|
||||
else
|
||||
sprintf(buffer, "ADDQMOD $%X,R%02d", convert_zero[reg1], reg2);
|
||||
break;
|
||||
}
|
||||
|
||||
if (size == 2)
|
||||
sprintf(bufferOut, "%04X %-24s", op, buffer);
|
||||
else
|
||||
{
|
||||
uint16_t word1 = ROPCODE(pc), word2 = ROPCODE(pc + 2);
|
||||
sprintf(bufferOut, "%04X %04X %04X %-24s", op, word1, word2, buffer);
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
#ifndef __JAGDASM__
|
||||
#define __JAGDASM__
|
||||
|
||||
#define JAGUAR_GPU 0
|
||||
#define JAGUAR_DSP 1
|
||||
|
||||
unsigned dasmjag(int dsp_type, char * buffer, unsigned pc);
|
||||
|
||||
#endif
|
|
@ -57,12 +57,12 @@ void M68KInstructionHook(void)
|
|||
{
|
||||
if (jaguarCdInserted)
|
||||
{
|
||||
uint32_t pc = m68k_get_reg(NULL, M68K_REG_PC);
|
||||
uint32_t pc = m68k_get_reg(M68K_REG_PC);
|
||||
if (pc >= 0x3000 && pc <= 0x306C)
|
||||
{
|
||||
CDHLEHook((pc - 0x3000) / 6);
|
||||
// return
|
||||
uint32_t sp = m68k_get_reg(NULL, M68K_REG_SP);
|
||||
uint32_t sp = m68k_get_reg(M68K_REG_SP);
|
||||
m68k_set_reg(M68K_REG_PC, m68k_read_memory_32(sp));
|
||||
m68k_set_reg(M68K_REG_SP, sp + 4);
|
||||
}
|
||||
|
@ -73,12 +73,12 @@ void M68KInstructionHook(void)
|
|||
uint32_t regs[18];
|
||||
for (uint32_t i = 0; i < 18; i++)
|
||||
{
|
||||
regs[i] = m68k_get_reg(NULL, (m68k_register_t)i);
|
||||
regs[i] = m68k_get_reg((m68k_register_t)i);
|
||||
}
|
||||
CPUTraceCallback(regs);
|
||||
}
|
||||
|
||||
MAYBE_CALLBACK(ExecuteCallback, m68k_get_reg(NULL, M68K_REG_PC));
|
||||
MAYBE_CALLBACK(ExecuteCallback, m68k_get_reg(M68K_REG_PC));
|
||||
}
|
||||
|
||||
//
|
||||
|
|
|
@ -70,8 +70,6 @@ extern struct regstruct regs, lastint_regs;
|
|||
/* Possible exceptions sources for M68000_Exception() and Exception() */
|
||||
#define M68000_EXC_SRC_CPU 1 /* Direct CPU exception */
|
||||
#define M68000_EXC_SRC_AUTOVEC 2 /* Auto-vector exception (e.g. VBL) */
|
||||
//#define M68000_EXC_SRC_INT_MFP 3 /* MFP interrupt exception */
|
||||
//#define M68000_EXC_SRC_INT_DSP 4 /* DSP interrupt exception */
|
||||
|
||||
#define SET_CFLG(x) (CFLG = (x))
|
||||
#define SET_NFLG(x) (NFLG = (x))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -10,18 +10,16 @@
|
|||
#include "cpudefs.h"
|
||||
#include "inlines.h"
|
||||
|
||||
uint16_t last_op_for_exception_3;
|
||||
uint32_t last_addr_for_exception_3;
|
||||
uint32_t last_fault_for_exception_3;
|
||||
|
||||
uint16_t last_op_for_exception_3; // Opcode of faulting instruction
|
||||
uint32_t last_addr_for_exception_3; // PC at fault time
|
||||
uint32_t last_fault_for_exception_3; // Address that generated the exception
|
||||
|
||||
int OpcodeFamily; // Used by cpuemu.c...
|
||||
int BusCyclePenalty = 0; // Used by cpuemu.c...
|
||||
int OpcodeFamily;
|
||||
int BusCyclePenalty = 0;
|
||||
int CurrentInstrCycles;
|
||||
|
||||
struct regstruct regs;
|
||||
|
||||
|
||||
//
|
||||
// Make displacement effective address for 68000
|
||||
//
|
||||
|
@ -30,29 +28,12 @@ uint32_t get_disp_ea_000(uint32_t base, uint32_t dp)
|
|||
int reg = (dp >> 12) & 0x0F;
|
||||
int32_t regd = regs.regs[reg];
|
||||
|
||||
#if 1
|
||||
if ((dp & 0x800) == 0)
|
||||
regd = (int32_t)(int16_t)regd;
|
||||
|
||||
return base + (int8_t)dp + regd;
|
||||
#else
|
||||
/* Branch-free code... benchmark this again now that
|
||||
* things are no longer inline.
|
||||
*/
|
||||
int32_t regd16;
|
||||
uint32_t mask;
|
||||
mask = ((dp & 0x800) >> 11) - 1;
|
||||
regd16 = (int32_t)(int16_t)regd;
|
||||
regd16 &= mask;
|
||||
mask = ~mask;
|
||||
base += (int8_t)dp;
|
||||
regd &= mask;
|
||||
regd |= regd16;
|
||||
return base + regd;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Create the Status Register from the flags
|
||||
//
|
||||
|
@ -62,7 +43,6 @@ void MakeSR(void)
|
|||
| (GET_NFLG << 3) | (GET_ZFLG << 2) | (GET_VFLG << 1) | GET_CFLG);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Set up the flags from Status Register
|
||||
//
|
||||
|
@ -91,107 +71,19 @@ void MakeFromSR(void)
|
|||
m68k_areg(regs, 7) = regs.isp;
|
||||
}
|
||||
}
|
||||
|
||||
/* Pending interrupts can occur again after a write to the SR: */
|
||||
//JLH: is this needed?
|
||||
// set_special(SPCFLAG_DOINT);
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Rudimentary exception handling. This is really stripped down from what
|
||||
// was in Hatari.
|
||||
/*
|
||||
NB: Seems that when an address exception occurs, it doesn't get handled properly
|
||||
as per test1.cof. Need to figure out why it keeps going when it should wedge. :-P
|
||||
*/
|
||||
//
|
||||
// Handle exceptions. We need a special case to handle MFP exceptions
|
||||
// on Atari ST, because it's possible to change the MFP's vector base
|
||||
// and get a conflict with 'normal' cpu exceptions.
|
||||
//
|
||||
#if 0
|
||||
/*
|
||||
This is the STOP # function. Dunno if exception handling occurs when it hits here or not, because don't know if the regs.s bit is set or not!
|
||||
Seems to be...
|
||||
|
||||
SR-----------------
|
||||
1111 11
|
||||
5432 1098 7654 3210
|
||||
---- ---- ---- ----
|
||||
1 1
|
||||
|
||||
|
||||
*/
|
||||
unsigned long CPUFUNC(op_4e72_5)(uint32_t opcode) /* STOP */
|
||||
{
|
||||
OpcodeFamily = 44;
|
||||
CurrentInstrCycles = 4;
|
||||
|
||||
if (!regs.s)
|
||||
{
|
||||
Exception(8, 0, M68000_EXC_SRC_CPU);
|
||||
}
|
||||
else
|
||||
{
|
||||
int16_t src = get_iword_prefetch(2);
|
||||
regs.sr = src;
|
||||
MakeFromSR();
|
||||
m68k_setstopped(1);
|
||||
m68k_incpc(4);
|
||||
fill_prefetch_0();
|
||||
}
|
||||
|
||||
return 4;
|
||||
}
|
||||
#endif
|
||||
//tmp...
|
||||
void WriteLog(const char * text, ...);
|
||||
void Exception(int nr, uint32_t oldpc, int ExceptionSource)
|
||||
{
|
||||
uint32_t currpc = m68k_getpc(), newpc;
|
||||
|
||||
// Need to figure out how to report this stuff without using printf on stdout :-/
|
||||
#if 0
|
||||
char excNames[33][64] = {
|
||||
"???", "???", "Bus Error", "Address Error",
|
||||
"Illegal Instruction", "Zero Divide", "CHK", "TrapV",
|
||||
"Privilege Violation", "Trace", "Line A", "Line F",
|
||||
"???", "???", "Format Error", "Uninitialized Interrupt",
|
||||
"???", "???", "???", "???",
|
||||
"???", "???", "???", "???",
|
||||
"Spurious/Autovector", "???", "???", "???",
|
||||
"???", "???", "???", "???",
|
||||
"Trap #"
|
||||
};
|
||||
|
||||
WriteLog("Exception #%i occurred! (%s)\n", nr, (nr < 32 ? excNames[nr] : (nr < 48 ? "Trap #" : "????")));
|
||||
WriteLog("Vector @ #%i = %08X\n", nr, m68k_read_memory_32(nr * 4));
|
||||
//abort();
|
||||
WriteLog("PC = $%08X\n", currpc);
|
||||
WriteLog("A0 = $%08X A1 = $%08X A2 = $%08X A3 = $%08X\n", m68k_areg(regs, 0), m68k_areg(regs, 1), m68k_areg(regs, 2), m68k_areg(regs, 3));
|
||||
WriteLog("A4 = $%08X A5 = $%08X A6 = $%08X A7 = $%08X\n", m68k_areg(regs, 4), m68k_areg(regs, 5), m68k_areg(regs, 6), m68k_areg(regs, 7));
|
||||
WriteLog("D0 = $%08X D1 = $%08X D2 = $%08X D3 = $%08X\n", m68k_dreg(regs, 0), m68k_dreg(regs, 1), m68k_dreg(regs, 2), m68k_dreg(regs, 3));
|
||||
WriteLog("D4 = $%08X D5 = $%08X D6 = $%08X D7 = $%08X\n", m68k_dreg(regs, 4), m68k_dreg(regs, 5), m68k_dreg(regs, 6), m68k_dreg(regs, 7));
|
||||
WriteLog("\n");
|
||||
|
||||
uint32_t disPC = currpc - 10;
|
||||
char buffer[128];
|
||||
|
||||
do
|
||||
{
|
||||
uint32_t oldpc = disPC;
|
||||
disPC += m68k_disassemble(buffer, disPC, 0);
|
||||
WriteLog("%s%08X: %s\n", (oldpc == currpc ? ">" : " "), oldpc, buffer);
|
||||
}
|
||||
while (disPC < (currpc + 10));
|
||||
#endif
|
||||
|
||||
/*if( nr>=2 && nr<10 ) fprintf(stderr,"Exception (-> %i bombs)!\n",nr);*/
|
||||
|
||||
MakeSR();
|
||||
|
||||
// Change to supervisor mode if necessary
|
||||
if (!regs.s)
|
||||
{
|
||||
regs.usp = m68k_areg(regs, 7);
|
||||
|
@ -199,202 +91,15 @@ while (disPC < (currpc + 10));
|
|||
regs.s = 1;
|
||||
}
|
||||
|
||||
// Create 68000 style stack frame
|
||||
m68k_areg(regs, 7) -= 4; // Push PC on stack
|
||||
m68k_areg(regs, 7) -= 4;
|
||||
m68k_write_memory_32(m68k_areg(regs, 7), currpc);
|
||||
m68k_areg(regs, 7) -= 2; // Push SR on stack
|
||||
m68k_areg(regs, 7) -= 2;
|
||||
m68k_write_memory_16(m68k_areg(regs, 7), regs.sr);
|
||||
|
||||
// LOG_TRACE(TRACE_CPU_EXCEPTION, "cpu exception %d currpc %x buspc %x newpc %x fault_e3 %x op_e3 %hx addr_e3 %x\n",
|
||||
// nr, currpc, BusErrorPC, get_long(4 * nr), last_fault_for_exception_3, last_op_for_exception_3, last_addr_for_exception_3);
|
||||
|
||||
#if 0
|
||||
/* 68000 bus/address errors: */
|
||||
if ((nr == 2 || nr == 3) && ExceptionSource == M68000_EXC_SRC_CPU)
|
||||
{
|
||||
uint16_t specialstatus = 1;
|
||||
|
||||
/* Special status word emulation isn't perfect yet... :-( */
|
||||
if (regs.sr & 0x2000)
|
||||
specialstatus |= 0x4;
|
||||
|
||||
m68k_areg(regs, 7) -= 8;
|
||||
|
||||
if (nr == 3) /* Address error */
|
||||
{
|
||||
specialstatus |= (last_op_for_exception_3 & (~0x1F)); /* [NP] unused bits of specialstatus are those of the last opcode ! */
|
||||
put_word(m68k_areg(regs, 7), specialstatus);
|
||||
put_long(m68k_areg(regs, 7) + 2, last_fault_for_exception_3);
|
||||
put_word(m68k_areg(regs, 7) + 6, last_op_for_exception_3);
|
||||
put_long(m68k_areg(regs, 7) + 10, last_addr_for_exception_3);
|
||||
|
||||
//JLH: Not now...
|
||||
#if 0
|
||||
if (bExceptionDebugging)
|
||||
{
|
||||
fprintf(stderr,"Address Error at address $%x, PC=$%x\n", last_fault_for_exception_3, currpc);
|
||||
DebugUI();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else /* Bus error */
|
||||
{
|
||||
specialstatus |= (get_word(BusErrorPC) & (~0x1F)); /* [NP] unused bits of special status are those of the last opcode ! */
|
||||
|
||||
if (bBusErrorReadWrite)
|
||||
specialstatus |= 0x10;
|
||||
|
||||
put_word(m68k_areg(regs, 7), specialstatus);
|
||||
put_long(m68k_areg(regs, 7) + 2, BusErrorAddress);
|
||||
put_word(m68k_areg(regs, 7) + 6, get_word(BusErrorPC)); /* Opcode */
|
||||
|
||||
/* [NP] PC stored in the stack frame is not necessarily pointing to the next instruction ! */
|
||||
/* FIXME : we should have a proper model for this, in the meantime we handle specific cases */
|
||||
if (get_word(BusErrorPC) == 0x21F8) /* move.l $0.w,$24.w (Transbeauce 2 loader) */
|
||||
put_long(m68k_areg(regs, 7) + 10, currpc - 2); /* correct PC is 2 bytes less than usual value */
|
||||
|
||||
/* Check for double bus errors: */
|
||||
if (regs.spcflags & SPCFLAG_BUSERROR)
|
||||
{
|
||||
fprintf(stderr, "Detected double bus error at address $%x, PC=$%lx => CPU halted!\n",
|
||||
BusErrorAddress, (long)currpc);
|
||||
unset_special(SPCFLAG_BUSERROR);
|
||||
|
||||
if (bExceptionDebugging)
|
||||
DebugUI();
|
||||
else
|
||||
DlgAlert_Notice("Detected double bus error => CPU halted!\nEmulation needs to be reset.\n");
|
||||
|
||||
regs.intmask = 7;
|
||||
m68k_setstopped(true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (bExceptionDebugging && BusErrorAddress != 0xFF8A00)
|
||||
{
|
||||
fprintf(stderr,"Bus Error at address $%x, PC=$%lx\n", BusErrorAddress, (long)currpc);
|
||||
DebugUI();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Not now...
|
||||
#if 0
|
||||
/* Set PC and flags */
|
||||
if (bExceptionDebugging && get_long(4 * nr) == 0)
|
||||
{
|
||||
write_log("Uninitialized exception handler #%i!\n", nr);
|
||||
DebugUI();
|
||||
}
|
||||
#endif
|
||||
|
||||
newpc = get_long(4 * nr);
|
||||
|
||||
if (newpc & 1) /* check new pc is odd */
|
||||
{
|
||||
if (nr == 2 || nr == 3) /* address error during bus/address error -> stop emulation */
|
||||
{
|
||||
fprintf(stderr,"Address Error during exception 2/3, aborting new PC=$%x\n", newpc);
|
||||
DebugUI();
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,"Address Error during exception, new PC=$%x\n", newpc);
|
||||
Exception(3, m68k_getpc(), M68000_EXC_SRC_CPU);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
m68k_setpc(m68k_read_memory_32(4 * nr));
|
||||
fill_prefetch_0();
|
||||
/* Handle trace flags depending on current state */
|
||||
//JLH:no exception_trace(nr);
|
||||
|
||||
#if 0
|
||||
/* Handle exception cycles (special case for MFP) */
|
||||
// if (ExceptionSource == M68000_EXC_SRC_INT_MFP)
|
||||
// {
|
||||
// M68000_AddCycles(44 + 12); /* MFP interrupt, 'nr' can be in a different range depending on $fffa17 */
|
||||
// }
|
||||
// else
|
||||
if (nr >= 24 && nr <= 31)
|
||||
{
|
||||
#if 0
|
||||
if (nr == 26) /* HBL */
|
||||
{
|
||||
/* store current cycle pos when then interrupt was received (see video.c) */
|
||||
LastCycleHblException = Cycles_GetCounter(CYCLES_COUNTER_VIDEO);
|
||||
M68000_AddCycles(44 + 12); /* Video Interrupt */
|
||||
}
|
||||
else if (nr == 28) /* VBL */
|
||||
M68000_AddCycles(44 + 12); /* Video Interrupt */
|
||||
else
|
||||
#endif
|
||||
M68000_AddCycles(44 + 4); /* Other Interrupts */
|
||||
}
|
||||
else if (nr >= 32 && nr <= 47)
|
||||
{
|
||||
M68000_AddCycles(34 - 4); /* Trap (total is 34, but cpuemu.c already adds 4) */
|
||||
}
|
||||
else switch(nr)
|
||||
{
|
||||
case 2: M68000_AddCycles(50); break; /* Bus error */
|
||||
case 3: M68000_AddCycles(50); break; /* Address error */
|
||||
case 4: M68000_AddCycles(34); break; /* Illegal instruction */
|
||||
case 5: M68000_AddCycles(38); break; /* Div by zero */
|
||||
case 6: M68000_AddCycles(40); break; /* CHK */
|
||||
case 7: M68000_AddCycles(34); break; /* TRAPV */
|
||||
case 8: M68000_AddCycles(34); break; /* Privilege violation */
|
||||
case 9: M68000_AddCycles(34); break; /* Trace */
|
||||
case 10: M68000_AddCycles(34); break; /* Line-A - probably wrong */
|
||||
case 11: M68000_AddCycles(34); break; /* Line-F - probably wrong */
|
||||
default:
|
||||
/* FIXME: Add right cycles value for MFP interrupts and copro exceptions ... */
|
||||
if (nr < 64)
|
||||
M68000_AddCycles(4); /* Coprocessor and unassigned exceptions (???) */
|
||||
else
|
||||
M68000_AddCycles(44 + 12); /* Must be a MFP or DSP interrupt */
|
||||
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
The routines below take dividend and divisor as parameters.
|
||||
They return 0 if division by zero, or exact number of cycles otherwise.
|
||||
|
||||
The number of cycles returned assumes a register operand.
|
||||
Effective address time must be added if memory operand.
|
||||
|
||||
For 68000 only (not 68010, 68012, 68020, etc).
|
||||
Probably valid for 68008 after adding the extra prefetch cycle.
|
||||
|
||||
|
||||
Best and worst cases are for register operand:
|
||||
(Note the difference with the documented range.)
|
||||
|
||||
|
||||
DIVU:
|
||||
|
||||
Overflow (always): 10 cycles.
|
||||
Worst case: 136 cycles.
|
||||
Best case: 76 cycles.
|
||||
|
||||
|
||||
DIVS:
|
||||
|
||||
Absolute overflow: 16-18 cycles.
|
||||
Signed overflow is not detected prematurely.
|
||||
|
||||
Worst case: 156 cycles.
|
||||
Best case without signed overflow: 122 cycles.
|
||||
Best case with signed overflow: 120 cycles
|
||||
*/
|
||||
|
||||
//
|
||||
// DIVU
|
||||
// Unsigned division
|
||||
|
@ -408,7 +113,6 @@ STATIC_INLINE int getDivu68kCycles_2 (uint32_t dividend, uint16_t divisor)
|
|||
if (divisor == 0)
|
||||
return 0;
|
||||
|
||||
// Overflow
|
||||
if ((dividend >> 16) >= divisor)
|
||||
return (mcycles = 5) * 2;
|
||||
|
||||
|
@ -422,7 +126,6 @@ STATIC_INLINE int getDivu68kCycles_2 (uint32_t dividend, uint16_t divisor)
|
|||
|
||||
dividend <<= 1;
|
||||
|
||||
// If carry from shift
|
||||
if ((int32_t)temp < 0)
|
||||
dividend -= hdivisor;
|
||||
else
|
||||
|
@ -440,16 +143,12 @@ STATIC_INLINE int getDivu68kCycles_2 (uint32_t dividend, uint16_t divisor)
|
|||
return mcycles * 2;
|
||||
}
|
||||
|
||||
|
||||
// This is called by cpuemu.c
|
||||
int getDivu68kCycles(uint32_t dividend, uint16_t divisor)
|
||||
{
|
||||
int v = getDivu68kCycles_2(dividend, divisor) - 4;
|
||||
// write_log ("U%d ", v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// DIVS
|
||||
// Signed division
|
||||
|
@ -468,11 +167,9 @@ STATIC_INLINE int getDivs68kCycles_2(int32_t dividend, int16_t divisor)
|
|||
if (dividend < 0)
|
||||
mcycles++;
|
||||
|
||||
// Check for absolute overflow
|
||||
if (((uint32_t)abs(dividend) >> 16) >= (uint16_t)abs(divisor))
|
||||
return (mcycles + 2) * 2;
|
||||
|
||||
// Absolute quotient
|
||||
aquot = (uint32_t)abs(dividend) / (uint16_t)abs(divisor);
|
||||
|
||||
mcycles += 55;
|
||||
|
@ -485,8 +182,6 @@ STATIC_INLINE int getDivs68kCycles_2(int32_t dividend, int16_t divisor)
|
|||
mcycles++;
|
||||
}
|
||||
|
||||
// Count 15 msbits in absolute of quotient
|
||||
|
||||
for(i=0; i<15; i++)
|
||||
{
|
||||
if ((int16_t)aquot >= 0)
|
||||
|
@ -498,12 +193,8 @@ STATIC_INLINE int getDivs68kCycles_2(int32_t dividend, int16_t divisor)
|
|||
return mcycles * 2;
|
||||
}
|
||||
|
||||
|
||||
// This is called by cpuemu.c
|
||||
int getDivs68kCycles(int32_t dividend, int16_t divisor)
|
||||
{
|
||||
int v = getDivs68kCycles_2(dividend, divisor) - 4;
|
||||
// write_log ("S%d ", v);
|
||||
return v;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,15 +12,12 @@ struct cputbl
|
|||
uint16_t opcode;
|
||||
};
|
||||
|
||||
extern uint16_t last_op_for_exception_3; /* Opcode of faulting instruction */
|
||||
extern uint32_t last_addr_for_exception_3; /* PC at fault time */
|
||||
extern uint32_t last_fault_for_exception_3; /* Address that generated the exception */
|
||||
extern uint16_t last_op_for_exception_3;
|
||||
extern uint32_t last_addr_for_exception_3;
|
||||
extern uint32_t last_fault_for_exception_3;
|
||||
|
||||
/* Family of the latest instruction executed (to check for pairing) */
|
||||
extern int OpcodeFamily; /* see instrmnem in readcpu.h */
|
||||
extern int OpcodeFamily;
|
||||
|
||||
/* How many cycles to add to the current instruction in case a "misaligned" bus access is made */
|
||||
/* (used when addressing mode is d8(an,ix)) */
|
||||
extern int BusCyclePenalty;
|
||||
extern int CurrentInstrCycles;
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -16,35 +16,32 @@ STATIC_INLINE int cctrue(const int cc)
|
|||
{
|
||||
switch (cc)
|
||||
{
|
||||
case 0: return 1; /* T */
|
||||
case 1: return 0; /* F */
|
||||
case 2: return !CFLG && !ZFLG; /* HI */
|
||||
case 3: return CFLG || ZFLG; /* LS */
|
||||
case 4: return !CFLG; /* CC */
|
||||
case 5: return CFLG; /* CS */
|
||||
case 6: return !ZFLG; /* NE */
|
||||
case 7: return ZFLG; /* EQ */
|
||||
case 8: return !VFLG; /* VC */
|
||||
case 9: return VFLG; /* VS */
|
||||
case 10: return !NFLG; /* PL */
|
||||
case 11: return NFLG; /* MI */
|
||||
case 12: return NFLG == VFLG; /* GE */
|
||||
case 13: return NFLG != VFLG; /* LT */
|
||||
case 14: return !ZFLG && (NFLG == VFLG); /* GT */
|
||||
case 15: return ZFLG || (NFLG != VFLG); /* LE */
|
||||
case 0: return 1;
|
||||
case 1: return 0;
|
||||
case 2: return !CFLG && !ZFLG;
|
||||
case 3: return CFLG || ZFLG;
|
||||
case 4: return !CFLG;
|
||||
case 5: return CFLG;
|
||||
case 6: return !ZFLG;
|
||||
case 7: return ZFLG;
|
||||
case 8: return !VFLG;
|
||||
case 9: return VFLG;
|
||||
case 10: return !NFLG;
|
||||
case 11: return NFLG;
|
||||
case 12: return NFLG == VFLG;
|
||||
case 13: return NFLG != VFLG;
|
||||
case 14: return !ZFLG && (NFLG == VFLG);
|
||||
case 15: return ZFLG || (NFLG != VFLG);
|
||||
}
|
||||
|
||||
abort();
|
||||
return 0;
|
||||
}
|
||||
|
||||
//no #define m68k_incpc(o) (regs.pc_p += (o))
|
||||
#define m68k_incpc(o) (regs.pc += (o))
|
||||
|
||||
STATIC_INLINE void m68k_setpc(uint32_t newpc)
|
||||
{
|
||||
//This is only done here... (get_real_address())
|
||||
// regs.pc_p = regs.pc_oldp = get_real_address(newpc);
|
||||
regs.pc = newpc;
|
||||
}
|
||||
|
||||
|
@ -52,29 +49,13 @@ STATIC_INLINE void m68k_setpc(uint32_t newpc)
|
|||
|
||||
STATIC_INLINE uint32_t m68k_getpc(void)
|
||||
{
|
||||
// return regs.pc + ((char *)regs.pc_p - (char *)regs.pc_oldp);
|
||||
return regs.pc;
|
||||
}
|
||||
|
||||
#if 0
|
||||
STATIC_INLINE uint32_t m68k_getpc_p(uint8_t * p)
|
||||
{
|
||||
return regs.pc + ((char *)p - (char *)regs.pc_oldp);
|
||||
}
|
||||
#endif
|
||||
|
||||
STATIC_INLINE void m68k_setstopped(int stop)
|
||||
{
|
||||
regs.stopped = stop;
|
||||
regs.remainingCycles = 0;
|
||||
|
||||
//But trace instructions are only on >68000 cpus, so this is bogus.
|
||||
#if 0
|
||||
/* A traced STOP instruction drops through immediately without
|
||||
actually stopping. */
|
||||
if (stop && (regs.spcflags & SPCFLAG_DOTRACE) == 0)
|
||||
regs.spcflags |= SPCFLAG_STOP;
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC_INLINE void m68k_do_rts(void)
|
||||
|
@ -97,103 +78,27 @@ STATIC_INLINE void m68k_do_jsr(uint32_t oldpc, uint32_t dest)
|
|||
m68k_setpc(dest);
|
||||
}
|
||||
|
||||
#if 0
|
||||
//These do_get_mem_* functions are only used in newcpu...
|
||||
//What it does is use a pointer to make instruction fetching quicker,
|
||||
//though it probably leads to more problems than it solves. Something to
|
||||
//decide using a profiler...
|
||||
#define get_ibyte(o) do_get_mem_byte(regs.pc_p + (o) + 1)
|
||||
#define get_iword(o) do_get_mem_word(regs.pc_p + (o))
|
||||
#define get_ilong(o) do_get_mem_long(regs.pc_p + (o))
|
||||
#else
|
||||
// For now, we'll punt this crap...
|
||||
// (Also, notice that the byte read is at address + 1...)
|
||||
#define get_ibyte(o) m68k_read_memory_8(regs.pc + (o) + 1)
|
||||
#define get_iword(o) m68k_read_memory_16(regs.pc + (o))
|
||||
#define get_ilong(o) m68k_read_memory_32(regs.pc + (o))
|
||||
#endif
|
||||
|
||||
// We don't use this crap, so let's comment out for now...
|
||||
STATIC_INLINE void refill_prefetch(uint32_t currpc, uint32_t offs)
|
||||
{
|
||||
#if 0
|
||||
uint32_t t = (currpc + offs) & ~1;
|
||||
int32_t pc_p_offs = t - currpc;
|
||||
uint8_t * ptr = regs.pc_p + pc_p_offs;
|
||||
uint32_t r;
|
||||
|
||||
#ifdef UNALIGNED_PROFITABLE
|
||||
r = *(uint32_t *)ptr;
|
||||
regs.prefetch = r;
|
||||
#else
|
||||
r = do_get_mem_long(ptr);
|
||||
do_put_mem_long(®s.prefetch, r);
|
||||
#endif
|
||||
/* printf ("PC %lx T %lx PCPOFFS %d R %lx\n", currpc, t, pc_p_offs, r); */
|
||||
regs.prefetch_pc = t;
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC_INLINE uint32_t get_ibyte_prefetch(int32_t o)
|
||||
{
|
||||
#if 0
|
||||
uint32_t currpc = m68k_getpc();
|
||||
uint32_t addr = currpc + o + 1;
|
||||
uint32_t offs = addr - regs.prefetch_pc;
|
||||
|
||||
if (offs > 3)
|
||||
{
|
||||
refill_prefetch(currpc, o + 1);
|
||||
offs = addr - regs.prefetch_pc;
|
||||
}
|
||||
|
||||
uint32_t v = do_get_mem_byte(((uint8_t *)®s.prefetch) + offs);
|
||||
|
||||
if (offs >= 2)
|
||||
refill_prefetch(currpc, 2);
|
||||
|
||||
/* printf ("get_ibyte PC %lx ADDR %lx OFFS %lx V %lx\n", currpc, addr, offs, v); */
|
||||
return v;
|
||||
#else
|
||||
return get_ibyte(o);
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC_INLINE uint32_t get_iword_prefetch(int32_t o)
|
||||
{
|
||||
#if 0
|
||||
uint32_t currpc = m68k_getpc();
|
||||
uint32_t addr = currpc + o;
|
||||
uint32_t offs = addr - regs.prefetch_pc;
|
||||
|
||||
if (offs > 3)
|
||||
{
|
||||
refill_prefetch(currpc, o);
|
||||
offs = addr - regs.prefetch_pc;
|
||||
}
|
||||
|
||||
uint32_t v = do_get_mem_word(((uint8_t *)®s.prefetch) + offs);
|
||||
|
||||
if (offs >= 2)
|
||||
refill_prefetch(currpc, 2);
|
||||
|
||||
/* printf ("get_iword PC %lx ADDR %lx OFFS %lx V %lx\n", currpc, addr, offs, v); */
|
||||
return v;
|
||||
#else
|
||||
return get_iword(o);
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC_INLINE uint32_t get_ilong_prefetch(int32_t o)
|
||||
{
|
||||
#if 0
|
||||
uint32_t v = get_iword_prefetch(o);
|
||||
v <<= 16;
|
||||
v |= get_iword_prefetch(o + 2);
|
||||
return v;
|
||||
#else
|
||||
return get_ilong(o);
|
||||
#endif
|
||||
}
|
||||
|
||||
STATIC_INLINE void fill_prefetch_0(void)
|
||||
|
|
|
@ -1,421 +0,0 @@
|
|||
//
|
||||
// m68kdasm.c: 68000 instruction disassembly
|
||||
//
|
||||
// Originally part of the UAE 68000 cpu core
|
||||
// by Bernd Schmidt
|
||||
//
|
||||
// Adapted to Virtual Jaguar by James Hammons
|
||||
//
|
||||
// This file is distributed under the GNU Public License, version 3 or at your
|
||||
// option any later version. Read the file GPLv3 for details.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#include "cpudefs.h"
|
||||
#include "cpuextra.h"
|
||||
#include "inlines.h"
|
||||
#include "readcpu.h"
|
||||
|
||||
|
||||
// Stuff from m68kinterface.c
|
||||
extern unsigned long IllegalOpcode(uint32_t opcode);
|
||||
extern cpuop_func * cpuFunctionTable[65536];
|
||||
|
||||
// Prototypes
|
||||
void HandleMovem(char * output, uint16_t data, int direction);
|
||||
|
||||
// Local "global" variables
|
||||
static long int m68kpc_offset;
|
||||
|
||||
#if 0
|
||||
#define get_ibyte_1(o) get_byte(regs.pc + (regs.pc_p - regs.pc_oldp) + (o) + 1)
|
||||
#define get_iword_1(o) get_word(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
|
||||
#define get_ilong_1(o) get_long(regs.pc + (regs.pc_p - regs.pc_oldp) + (o))
|
||||
#else
|
||||
#define get_ibyte_1(o) m68k_read_memory_8(regs.pc + (o) + 1)
|
||||
#define get_iword_1(o) m68k_read_memory_16(regs.pc + (o))
|
||||
#define get_ilong_1(o) m68k_read_memory_32(regs.pc + (o))
|
||||
#endif
|
||||
|
||||
|
||||
//int32_t ShowEA(FILE * f, int reg, amodes mode, wordsizes size, char * buf)
|
||||
int32_t ShowEA(int mnemonic, int reg, amodes mode, wordsizes size, char * buf)
|
||||
{
|
||||
uint16_t dp;
|
||||
int8_t disp8;
|
||||
int16_t disp16;
|
||||
int r;
|
||||
uint32_t dispreg;
|
||||
uint32_t addr;
|
||||
int32_t offset = 0;
|
||||
char buffer[80];
|
||||
|
||||
switch (mode)
|
||||
{
|
||||
case Dreg:
|
||||
sprintf(buffer,"D%d", reg);
|
||||
break;
|
||||
case Areg:
|
||||
sprintf(buffer,"A%d", reg);
|
||||
break;
|
||||
case Aind:
|
||||
sprintf(buffer,"(A%d)", reg);
|
||||
break;
|
||||
case Aipi:
|
||||
sprintf(buffer,"(A%d)+", reg);
|
||||
break;
|
||||
case Apdi:
|
||||
sprintf(buffer,"-(A%d)", reg);
|
||||
break;
|
||||
case Ad16:
|
||||
disp16 = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
|
||||
addr = m68k_areg(regs,reg) + (int16_t)disp16;
|
||||
sprintf(buffer,"(A%d,$%X) == $%lX", reg, disp16 & 0xFFFF,
|
||||
(unsigned long)addr);
|
||||
break;
|
||||
case Ad8r:
|
||||
dp = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
|
||||
disp8 = dp & 0xFF;
|
||||
r = (dp & 0x7000) >> 12;
|
||||
dispreg = (dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r));
|
||||
|
||||
if (!(dp & 0x800))
|
||||
dispreg = (int32_t)(int16_t)(dispreg);
|
||||
|
||||
dispreg <<= (dp >> 9) & 3;
|
||||
|
||||
if (dp & 0x100)
|
||||
{
|
||||
int32_t outer = 0, disp = 0;
|
||||
int32_t base = m68k_areg(regs,reg);
|
||||
char name[10];
|
||||
sprintf (name,"A%d, ",reg);
|
||||
if (dp & 0x80) { base = 0; name[0] = 0; }
|
||||
if (dp & 0x40) dispreg = 0;
|
||||
if ((dp & 0x30) == 0x20) { disp = (int32_t)(int16_t)get_iword_1(m68kpc_offset); m68kpc_offset += 2; }
|
||||
if ((dp & 0x30) == 0x30) { disp = get_ilong_1(m68kpc_offset); m68kpc_offset += 4; }
|
||||
base += disp;
|
||||
|
||||
if ((dp & 0x3) == 0x2) { outer = (int32_t)(int16_t)get_iword_1(m68kpc_offset); m68kpc_offset += 2; }
|
||||
if ((dp & 0x3) == 0x3) { outer = get_ilong_1(m68kpc_offset); m68kpc_offset += 4; }
|
||||
|
||||
if (!(dp & 4)) base += dispreg;
|
||||
if (dp & 3) base = m68k_read_memory_32(base);
|
||||
if (dp & 4) base += dispreg;
|
||||
|
||||
addr = base + outer;
|
||||
sprintf(buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%lX", name,
|
||||
dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
|
||||
1 << ((dp >> 9) & 3),
|
||||
(long)disp, (long)outer, (unsigned long)addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr = m68k_areg(regs,reg) + (int32_t)((int8_t)disp8) + dispreg;
|
||||
sprintf (buffer,"(A%d, %c%d.%c*%d, $%X) == $%lX", reg,
|
||||
dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
|
||||
1 << ((dp >> 9) & 3), disp8, (unsigned long)addr);
|
||||
}
|
||||
break;
|
||||
case PC16:
|
||||
addr = m68k_getpc() + m68kpc_offset;
|
||||
disp16 = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
|
||||
addr += (int16_t)disp16;
|
||||
sprintf(buffer,"(PC, $%X) == $%lX", disp16 & 0xFFFF, (unsigned long)addr);
|
||||
break;
|
||||
case PC8r:
|
||||
addr = m68k_getpc() + m68kpc_offset;
|
||||
dp = get_iword_1(m68kpc_offset); m68kpc_offset += 2;
|
||||
disp8 = dp & 0xFF;
|
||||
r = (dp & 0x7000) >> 12;
|
||||
dispreg = dp & 0x8000 ? m68k_areg(regs,r) : m68k_dreg(regs,r);
|
||||
|
||||
if (!(dp & 0x800))
|
||||
dispreg = (int32_t)(int16_t)(dispreg);
|
||||
|
||||
dispreg <<= (dp >> 9) & 3;
|
||||
|
||||
if (dp & 0x100)
|
||||
{
|
||||
int32_t outer = 0,disp = 0;
|
||||
int32_t base = addr;
|
||||
char name[10];
|
||||
sprintf (name,"PC, ");
|
||||
if (dp & 0x80) { base = 0; name[0] = 0; }
|
||||
if (dp & 0x40) dispreg = 0;
|
||||
if ((dp & 0x30) == 0x20) { disp = (int32_t)(int16_t)get_iword_1(m68kpc_offset); m68kpc_offset += 2; }
|
||||
if ((dp & 0x30) == 0x30) { disp = get_ilong_1(m68kpc_offset); m68kpc_offset += 4; }
|
||||
base += disp;
|
||||
|
||||
if ((dp & 0x3) == 0x2)
|
||||
{
|
||||
outer = (int32_t)(int16_t)get_iword_1(m68kpc_offset);
|
||||
m68kpc_offset += 2;
|
||||
}
|
||||
|
||||
if ((dp & 0x3) == 0x3)
|
||||
{
|
||||
outer = get_ilong_1(m68kpc_offset);
|
||||
m68kpc_offset += 4;
|
||||
}
|
||||
|
||||
if (!(dp & 4)) base += dispreg;
|
||||
if (dp & 3) base = m68k_read_memory_32(base);
|
||||
if (dp & 4) base += dispreg;
|
||||
|
||||
addr = base + outer;
|
||||
sprintf(buffer,"(%s%c%d.%c*%d+%ld)+%ld == $%lX", name,
|
||||
dp & 0x8000 ? 'A' : 'D', (int)r, dp & 0x800 ? 'L' : 'W',
|
||||
1 << ((dp >> 9) & 3), (long)disp, (long)outer, (unsigned long)addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
addr += (int32_t)((int8_t)disp8) + dispreg;
|
||||
sprintf(buffer,"(PC, %c%d.%c*%d, $%X) == $%lX", dp & 0x8000 ? 'A' : 'D',
|
||||
(int)r, dp & 0x800 ? 'L' : 'W', 1 << ((dp >> 9) & 3),
|
||||
disp8, (unsigned long)addr);
|
||||
}
|
||||
break;
|
||||
case absw:
|
||||
sprintf(buffer,"$%lX", (unsigned long)(int32_t)(int16_t)get_iword_1(m68kpc_offset));
|
||||
m68kpc_offset += 2;
|
||||
break;
|
||||
case absl:
|
||||
sprintf(buffer,"$%lX", (unsigned long)get_ilong_1(m68kpc_offset));
|
||||
m68kpc_offset += 4;
|
||||
break;
|
||||
case imm:
|
||||
switch (size)
|
||||
{
|
||||
case sz_byte:
|
||||
sprintf(buffer,"#$%X", (unsigned int)(get_iword_1(m68kpc_offset) & 0xFF));
|
||||
m68kpc_offset += 2;
|
||||
break;
|
||||
case sz_word:
|
||||
sprintf(buffer,"#$%X", (unsigned int)(get_iword_1(m68kpc_offset) & 0xFFFF));
|
||||
m68kpc_offset += 2;
|
||||
break;
|
||||
case sz_long:
|
||||
sprintf(buffer,"#$%lX", (unsigned long)(get_ilong_1(m68kpc_offset)));
|
||||
m68kpc_offset += 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case imm0:
|
||||
offset = (int32_t)(int8_t)get_iword_1(m68kpc_offset);
|
||||
m68kpc_offset += 2;
|
||||
sprintf(buffer,"#$%X", (unsigned int)(offset & 0xFF));
|
||||
break;
|
||||
case imm1:
|
||||
offset = (int32_t)(int16_t)get_iword_1(m68kpc_offset);
|
||||
m68kpc_offset += 2;
|
||||
|
||||
if (mnemonic == i_MVMEL)
|
||||
HandleMovem(buffer, offset, 0);
|
||||
else if (mnemonic == i_MVMLE)
|
||||
HandleMovem(buffer, offset, 1);
|
||||
else
|
||||
sprintf(buffer,"#$%X", (unsigned int)(offset & 0xFFFF));
|
||||
|
||||
break;
|
||||
case imm2:
|
||||
offset = (int32_t)get_ilong_1(m68kpc_offset);
|
||||
m68kpc_offset += 4;
|
||||
sprintf(buffer,"#$%lX", (unsigned long)(offset & 0xFFFFFFFF));
|
||||
break;
|
||||
case immi:
|
||||
offset = (int32_t)(int8_t)(reg & 0xFF);
|
||||
sprintf(buffer,"#$%lX", (unsigned long)(offset & 0xFFFFFFFF));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// if (buf == 0)
|
||||
// fprintf(f, "%s", buffer);
|
||||
// else
|
||||
strcat(buf, buffer);
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
void HandleMovem(char * output, uint16_t data, int direction)
|
||||
{
|
||||
uint16_t ascending[16] = {
|
||||
0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
|
||||
0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 };
|
||||
uint16_t descending[16] = {
|
||||
0x8000, 0x4000, 0x2000, 0x1000, 0x0800, 0x0400, 0x0200, 0x0100,
|
||||
0x0080, 0x0040, 0x0020, 0x0010, 0x0008, 0x0004, 0x0002, 0x0001 };
|
||||
|
||||
int i, j, first, runLength, firstPrint = 1;
|
||||
char buf[16];
|
||||
uint16_t * bitMask;
|
||||
|
||||
bitMask = (direction ? descending : ascending);
|
||||
output[0] = 0;
|
||||
|
||||
// Handle D0-D7...
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
if (data & bitMask[i])
|
||||
{
|
||||
first = i;
|
||||
runLength = 0;
|
||||
|
||||
for(j=i+1; j<8 && (data & bitMask[j]); j++)
|
||||
runLength++;
|
||||
|
||||
i += runLength;
|
||||
|
||||
if (firstPrint)
|
||||
firstPrint = 0;
|
||||
else
|
||||
strcat(output, "/");
|
||||
|
||||
sprintf(buf, "D%d", first);
|
||||
strcat(output, buf);
|
||||
|
||||
if (runLength > 0)
|
||||
{
|
||||
sprintf(buf, "-D%d", first + runLength);
|
||||
strcat(output, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle A0-A7...
|
||||
for(i=0; i<8; i++)
|
||||
{
|
||||
if (data & bitMask[i + 8])
|
||||
{
|
||||
first = i;
|
||||
runLength = 0;
|
||||
|
||||
for(j=i+1; j<8 && (data & bitMask[j+8]); j++)
|
||||
runLength++;
|
||||
|
||||
i += runLength;
|
||||
|
||||
if (firstPrint)
|
||||
firstPrint = 0;
|
||||
else
|
||||
strcat(output, "/");
|
||||
|
||||
sprintf(buf, "A%d", first);
|
||||
strcat(output, buf);
|
||||
|
||||
if (runLength > 0)
|
||||
{
|
||||
sprintf(buf, "-A%d", first + runLength);
|
||||
strcat(output, buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unsigned int M68KDisassemble(char * output, uint32_t addr)
|
||||
{
|
||||
char f[256], str[256];
|
||||
char src[256], dst[256];
|
||||
static const char * const ccnames[] =
|
||||
{ "RA","RN","HI","LS","CC","CS","NE","EQ",
|
||||
"VC","VS","PL","MI","GE","LT","GT","LE" };
|
||||
|
||||
str[0] = 0;
|
||||
output[0] = 0;
|
||||
uint32_t newpc = 0;
|
||||
m68kpc_offset = addr - m68k_getpc();
|
||||
long int pcOffsetSave = m68kpc_offset;
|
||||
int opwords;
|
||||
char instrname[20];
|
||||
const struct mnemolookup * lookup;
|
||||
|
||||
uint32_t opcode = get_iword_1(m68kpc_offset);
|
||||
m68kpc_offset += 2;
|
||||
|
||||
if (cpuFunctionTable[opcode] == IllegalOpcode)
|
||||
opcode = 0x4AFC;
|
||||
|
||||
struct instr * dp = table68k + opcode;
|
||||
|
||||
for(lookup=lookuptab; lookup->mnemo!=dp->mnemo; lookup++)
|
||||
;
|
||||
|
||||
strcpy(instrname, lookup->name);
|
||||
char * ccpt = strstr(instrname, "cc");
|
||||
|
||||
if (ccpt)
|
||||
strncpy(ccpt, ccnames[dp->cc], 2);
|
||||
|
||||
sprintf(f, "%s", instrname);
|
||||
strcat(str, f);
|
||||
|
||||
switch (dp->size)
|
||||
{
|
||||
case sz_byte: strcat(str, ".B\t"); break;
|
||||
case sz_word: strcat(str, ".W\t"); break;
|
||||
case sz_long: strcat(str, ".L\t"); break;
|
||||
default: strcat(str, "\t"); break;
|
||||
}
|
||||
|
||||
// Get source and destination operands (if any)
|
||||
src[0] = dst[0] = f[0] = 0;
|
||||
|
||||
if (dp->suse)
|
||||
newpc = m68k_getpc() + m68kpc_offset
|
||||
+ ShowEA(dp->mnemo, dp->sreg, dp->smode, dp->size, src);
|
||||
|
||||
if (dp->duse)
|
||||
newpc = m68k_getpc() + m68kpc_offset
|
||||
+ ShowEA(dp->mnemo, dp->dreg, dp->dmode, dp->size, dst);
|
||||
|
||||
// Handle execptions to the standard rules
|
||||
if (dp->mnemo == i_BSR || dp->mnemo == i_Bcc)
|
||||
sprintf(f, "$%lX", (long)newpc);
|
||||
else if (dp->mnemo == i_DBcc)
|
||||
sprintf(f, "%s, $%lX", src, (long)newpc);
|
||||
else if (dp->mnemo == i_MVMEL)
|
||||
sprintf(f, "%s, %s", dst, src);
|
||||
else
|
||||
sprintf(f, "%s%s%s", src, (dp->suse && dp->duse ? ", " : ""), dst);
|
||||
|
||||
strcat(str, f);
|
||||
|
||||
if (ccpt)
|
||||
{
|
||||
sprintf(f, " (%s)", (cctrue(dp->cc) ? "true" : "false"));
|
||||
strcat(str, f);
|
||||
}
|
||||
|
||||
// Add byte(s) display to front of disassembly
|
||||
long int numberOfBytes = m68kpc_offset - pcOffsetSave;
|
||||
|
||||
for(opwords=0; opwords<5; opwords++)
|
||||
{
|
||||
if (((opwords + 1) * 2) <= numberOfBytes)
|
||||
sprintf(f, "%04X ", get_iword_1(pcOffsetSave + opwords * 2));
|
||||
else
|
||||
sprintf(f, " ");
|
||||
|
||||
strcat(output, f);
|
||||
}
|
||||
|
||||
strcat(output, str);
|
||||
|
||||
return numberOfBytes;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Disassemble one instruction at pc and store in str_buff
|
||||
//
|
||||
unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu_type)
|
||||
{
|
||||
return M68KDisassemble(str_buff, pc);
|
||||
}
|
||||
|
|
@ -12,7 +12,6 @@
|
|||
//
|
||||
|
||||
#include "m68kinterface.h"
|
||||
//#include <pthread.h>
|
||||
#include "cpudefs.h"
|
||||
#include "inlines.h"
|
||||
#include "cpuextra.h"
|
||||
|
@ -35,18 +34,8 @@
|
|||
#define EXCEPTION_INTERRUPT_AUTOVECTOR 24
|
||||
#define EXCEPTION_TRAP_BASE 32
|
||||
|
||||
// These are found in obj/cpustbl.c (generated by gencpu)
|
||||
|
||||
//extern const struct cputbl op_smalltbl_0_ff[]; /* 68040 */
|
||||
//extern const struct cputbl op_smalltbl_1_ff[]; /* 68020 + 68881 */
|
||||
//extern const struct cputbl op_smalltbl_2_ff[]; /* 68020 */
|
||||
//extern const struct cputbl op_smalltbl_3_ff[]; /* 68010 */
|
||||
extern const struct cputbl op_smalltbl_4_ff[]; /* 68000 */
|
||||
extern const struct cputbl op_smalltbl_5_ff[]; /* 68000 slow but compatible. */
|
||||
|
||||
// Externs, supplied by the user...
|
||||
//extern int irq_ack_handler(int);
|
||||
|
||||
// Function prototypes...
|
||||
STATIC_INLINE void m68ki_check_interrupts(void);
|
||||
void m68ki_exception_interrupt(uint32_t intLevel);
|
||||
|
@ -60,158 +49,34 @@ void m68k_set_irq2(unsigned int intLevel);
|
|||
static int32_t initialCycles;
|
||||
cpuop_func * cpuFunctionTable[65536];
|
||||
|
||||
// By virtue of the fact that m68k_set_irq() can be called asychronously by
|
||||
// another thread, we need something along the lines of this:
|
||||
static int checkForIRQToHandle = 0;
|
||||
//static pthread_mutex_t executionLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int IRQLevelToHandle = 0;
|
||||
|
||||
#if 0
|
||||
#define ADD_CYCLES(A) m68ki_remaining_cycles += (A)
|
||||
#define USE_CYCLES(A) m68ki_remaining_cycles -= (A)
|
||||
#define SET_CYCLES(A) m68ki_remaining_cycles = A
|
||||
#define GET_CYCLES() m68ki_remaining_cycles
|
||||
#define USE_ALL_CYCLES() m68ki_remaining_cycles = 0
|
||||
|
||||
#define CPU_INT_LEVEL m68ki_cpu.int_level /* ASG: changed from CPU_INTS_PENDING */
|
||||
#define CPU_INT_CYCLES m68ki_cpu.int_cycles /* ASG */
|
||||
#define CPU_STOPPED m68ki_cpu.stopped
|
||||
#define CPU_PREF_ADDR m68ki_cpu.pref_addr
|
||||
#define CPU_PREF_DATA m68ki_cpu.pref_data
|
||||
#define CPU_ADDRESS_MASK m68ki_cpu.address_mask
|
||||
#define CPU_SR_MASK m68ki_cpu.sr_mask
|
||||
#endif
|
||||
|
||||
#define CPU_DEBUG
|
||||
|
||||
|
||||
void Dasm(uint32_t offset, uint32_t qt)
|
||||
{
|
||||
#ifdef CPU_DEBUG
|
||||
// back up a few instructions...
|
||||
//offset -= 100;
|
||||
static char buffer[2048];//, mem[64];
|
||||
int pc = offset, oldpc;
|
||||
uint32_t i;
|
||||
|
||||
for(i=0; i<qt; i++)
|
||||
{
|
||||
/* oldpc = pc;
|
||||
for(int j=0; j<64; j++)
|
||||
mem[j^0x01] = jaguar_byte_read(pc + j);
|
||||
|
||||
pc += Dasm68000((char *)mem, buffer, 0);
|
||||
WriteLog("%08X: %s\n", oldpc, buffer);//*/
|
||||
oldpc = pc;
|
||||
pc += m68k_disassemble(buffer, pc, 0);//M68K_CPU_TYPE_68000);
|
||||
// WriteLog("%08X: %s\n", oldpc, buffer);//*/
|
||||
printf("%08X: %s\n", oldpc, buffer);//*/
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#ifdef CPU_DEBUG
|
||||
void DumpRegisters(void)
|
||||
{
|
||||
uint32_t i;
|
||||
|
||||
for(i=0; i<16; i++)
|
||||
{
|
||||
printf("%s%i: %08X ", (i < 8 ? "D" : "A"), i & 0x7, regs.regs[i]);
|
||||
|
||||
if ((i & 0x03) == 3)
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void M68KDebugHalt(void)
|
||||
{
|
||||
regs.spcflags |= SPCFLAG_DEBUGGER;
|
||||
}
|
||||
|
||||
|
||||
void M68KDebugResume(void)
|
||||
{
|
||||
regs.spcflags &= ~SPCFLAG_DEBUGGER;
|
||||
}
|
||||
|
||||
|
||||
void m68k_set_cpu_type(unsigned int type)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
// Pulse the RESET line on the CPU
|
||||
void m68k_pulse_reset(void)
|
||||
{
|
||||
static uint32_t emulation_initialized = 0;
|
||||
|
||||
// The first call to this function initializes the opcode handler jump table
|
||||
if (!emulation_initialized)
|
||||
{
|
||||
#if 0
|
||||
m68ki_build_opcode_table();
|
||||
m68k_set_int_ack_callback(NULL);
|
||||
m68k_set_bkpt_ack_callback(NULL);
|
||||
m68k_set_reset_instr_callback(NULL);
|
||||
m68k_set_pc_changed_callback(NULL);
|
||||
m68k_set_fc_callback(NULL);
|
||||
m68k_set_instr_hook_callback(NULL);
|
||||
#else
|
||||
// Build opcode handler table here...
|
||||
read_table68k();
|
||||
do_merges();
|
||||
BuildCPUFunctionTable();
|
||||
#endif
|
||||
emulation_initialized = 1;
|
||||
}
|
||||
|
||||
// if (CPU_TYPE == 0) /* KW 990319 */
|
||||
// m68k_set_cpu_type(M68K_CPU_TYPE_68000);
|
||||
|
||||
#if 0
|
||||
/* Clear all stop levels and eat up all remaining cycles */
|
||||
CPU_STOPPED = 0;
|
||||
SET_CYCLES(0);
|
||||
|
||||
/* Turn off tracing */
|
||||
FLAG_T1 = FLAG_T0 = 0;
|
||||
m68ki_clear_trace();
|
||||
/* Interrupt mask to level 7 */
|
||||
FLAG_INT_MASK = 0x0700;
|
||||
/* Reset VBR */
|
||||
REG_VBR = 0;
|
||||
/* Go to supervisor mode */
|
||||
m68ki_set_sm_flag(SFLAG_SET | MFLAG_CLEAR);
|
||||
|
||||
/* Invalidate the prefetch queue */
|
||||
#if M68K_EMULATE_PREFETCH
|
||||
/* Set to arbitrary number since our first fetch is from 0 */
|
||||
CPU_PREF_ADDR = 0x1000;
|
||||
#endif /* M68K_EMULATE_PREFETCH */
|
||||
|
||||
/* Read the initial stack pointer and program counter */
|
||||
m68ki_jump(0);
|
||||
REG_SP = m68ki_read_imm_32();
|
||||
REG_PC = m68ki_read_imm_32();
|
||||
m68ki_jump(REG_PC);
|
||||
#else
|
||||
checkForIRQToHandle = 0;
|
||||
regs.spcflags = 0;
|
||||
regs.stopped = 0;
|
||||
regs.remainingCycles = 0;
|
||||
|
||||
regs.intmask = 0x07;
|
||||
regs.s = 1; // Supervisor mode ON
|
||||
regs.s = 1;
|
||||
|
||||
// Read initial SP and PC
|
||||
m68k_areg(regs, 7) = m68k_read_memory_32(0);
|
||||
m68k_setpc(m68k_read_memory_32(4));
|
||||
refill_prefetch(m68k_getpc(), 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -219,392 +84,124 @@ int m68k_execute(int num_cycles)
|
|||
{
|
||||
if (regs.stopped)
|
||||
{
|
||||
regs.remainingCycles = 0; // int32_t
|
||||
regs.interruptCycles = 0; // uint32_t
|
||||
regs.remainingCycles = 0;
|
||||
regs.interruptCycles = 0;
|
||||
|
||||
return num_cycles;
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* Set our pool of clock cycles available */
|
||||
SET_CYCLES(num_cycles);
|
||||
m68ki_initial_cycles = num_cycles;
|
||||
|
||||
/* ASG: update cycles */
|
||||
USE_CYCLES(CPU_INT_CYCLES);
|
||||
CPU_INT_CYCLES = 0;
|
||||
|
||||
/* Return point if we had an address error */
|
||||
m68ki_set_address_error_trap(); /* auto-disable (see m68kcpu.h) */
|
||||
#else
|
||||
regs.remainingCycles = num_cycles;
|
||||
/*int32_t*/ initialCycles = num_cycles;
|
||||
initialCycles = num_cycles;
|
||||
|
||||
regs.remainingCycles -= regs.interruptCycles;
|
||||
regs.interruptCycles = 0;
|
||||
#endif
|
||||
|
||||
/* Main loop. Keep going until we run out of clock cycles */
|
||||
do
|
||||
{
|
||||
// This is so our debugging code can break in on a dime.
|
||||
// Otherwise, this is just extra slow down :-P
|
||||
if (regs.spcflags & SPCFLAG_DEBUGGER)
|
||||
{
|
||||
// Not sure this is correct... :-P
|
||||
num_cycles = initialCycles - regs.remainingCycles;
|
||||
regs.remainingCycles = 0; // int32_t
|
||||
regs.interruptCycles = 0; // uint32_t
|
||||
|
||||
return num_cycles;
|
||||
}
|
||||
#if 0
|
||||
/* Set tracing accodring to T1. (T0 is done inside instruction) */
|
||||
m68ki_trace_t1(); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
/* Set the address space for reads */
|
||||
m68ki_use_data_space(); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
/* Call external hook to peek at CPU */
|
||||
m68ki_instr_hook(); /* auto-disable (see m68kcpu.h) */
|
||||
|
||||
/* Record previous program counter */
|
||||
REG_PPC = REG_PC;
|
||||
|
||||
/* Read an instruction and call its handler */
|
||||
REG_IR = m68ki_read_imm_16();
|
||||
m68ki_instruction_jump_table[REG_IR]();
|
||||
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
|
||||
|
||||
/* Trace m68k_exception, if necessary */
|
||||
m68ki_exception_if_trace(); /* auto-disable (see m68kcpu.h) */
|
||||
#else
|
||||
//Testing Hover Strike...
|
||||
#if 0
|
||||
//Dasm(regs.pc, 1);
|
||||
static int hitCount = 0;
|
||||
static int inRoutine = 0;
|
||||
static int instSeen;
|
||||
|
||||
//if (regs.pc == 0x80340A)
|
||||
if (regs.pc == 0x803416)
|
||||
{
|
||||
hitCount++;
|
||||
inRoutine = 1;
|
||||
instSeen = 0;
|
||||
printf("%i: $80340A start. A0=%08X, A1=%08X ", hitCount, regs.regs[8], regs.regs[9]);
|
||||
}
|
||||
else if (regs.pc == 0x803422)
|
||||
{
|
||||
inRoutine = 0;
|
||||
printf("(%i instructions)\n", instSeen);
|
||||
}
|
||||
|
||||
if (inRoutine)
|
||||
instSeen++;
|
||||
#endif
|
||||
// AvP testing... (problem was: 32 bit addresses on 24 bit address cpu--FIXED)
|
||||
#if 0
|
||||
static int go = 0;
|
||||
|
||||
if (regs.pc == 0x94BA)
|
||||
{
|
||||
go = 1;
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (regs.pc == 0x94C6)
|
||||
go = 0;
|
||||
|
||||
// if (regs.regs[10] == 0xFFFFFFFF && go)
|
||||
if (go)
|
||||
{
|
||||
// printf("A2=-1, PC=%08X\n", regs.pc);
|
||||
// go = 0;
|
||||
// Dasm(regs.pc, 130);
|
||||
Dasm(regs.pc, 1);
|
||||
DumpRegisters();
|
||||
}
|
||||
//94BA: 2468 0000 MOVEA.L (A0,$0000) == $0002328A, A2
|
||||
//94BE: 200A MOVE.L A2, D0
|
||||
//94C0: 6A02 BPL.B $94C4
|
||||
//94C2: 2452 MOVEA.L (A2), A2 ; <--- HERE
|
||||
//94C4: 4283 CLR.L D3
|
||||
#endif
|
||||
// pthread_mutex_lock(&executionLock);
|
||||
if (checkForIRQToHandle)
|
||||
{
|
||||
checkForIRQToHandle = 0;
|
||||
m68k_set_irq2(IRQLevelToHandle);
|
||||
}
|
||||
|
||||
#ifdef M68K_HOOK_FUNCTION
|
||||
M68KInstructionHook();
|
||||
#endif
|
||||
uint32_t opcode = get_iword(0);
|
||||
//if ((opcode & 0xFFF8) == 0x31C0)
|
||||
//{
|
||||
// printf("MOVE.W D%i, EA\n", opcode & 0x07);
|
||||
//}
|
||||
int32_t cycles = (int32_t)(*cpuFunctionTable[opcode])(opcode);
|
||||
regs.remainingCycles -= cycles;
|
||||
// pthread_mutex_unlock(&executionLock);
|
||||
|
||||
//printf("Executed opcode $%04X (%i cycles)...\n", opcode, cycles);
|
||||
#endif
|
||||
}
|
||||
while (regs.remainingCycles > 0);
|
||||
|
||||
#if 0
|
||||
/* set previous PC to current PC for the next entry into the loop */
|
||||
REG_PPC = REG_PC;
|
||||
|
||||
/* ASG: update cycles */
|
||||
USE_CYCLES(CPU_INT_CYCLES);
|
||||
CPU_INT_CYCLES = 0;
|
||||
|
||||
/* return how many clocks we used */
|
||||
return m68ki_initial_cycles - GET_CYCLES();
|
||||
#else
|
||||
regs.remainingCycles -= regs.interruptCycles;
|
||||
regs.interruptCycles = 0;
|
||||
|
||||
// Return # of clock cycles used
|
||||
return initialCycles - regs.remainingCycles;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
void m68k_set_irq(unsigned int intLevel)
|
||||
{
|
||||
// We need to check for stopped state as well...
|
||||
if (regs.stopped)
|
||||
{
|
||||
m68k_set_irq2(intLevel);
|
||||
return;
|
||||
}
|
||||
|
||||
// Since this can be called asynchronously, we need to fix it so that it
|
||||
// doesn't fuck up the main execution loop.
|
||||
IRQLevelToHandle = intLevel;
|
||||
checkForIRQToHandle = 1;
|
||||
}
|
||||
|
||||
|
||||
/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
|
||||
void m68k_set_irq2(unsigned int intLevel)
|
||||
{
|
||||
// pthread_mutex_lock(&executionLock);
|
||||
// printf("m68k_set_irq: Could not get the lock!!!\n");
|
||||
|
||||
int oldLevel = regs.intLevel;
|
||||
regs.intLevel = intLevel;
|
||||
|
||||
// A transition from < 7 to 7 always interrupts (NMI)
|
||||
// Note: Level 7 can also level trigger like a normal IRQ
|
||||
if (oldLevel != 0x07 && regs.intLevel == 0x07)
|
||||
m68ki_exception_interrupt(7); // Edge triggered level 7 (NMI)
|
||||
m68ki_exception_interrupt(7);
|
||||
else
|
||||
m68ki_check_interrupts(); // Level triggered (IRQ)
|
||||
|
||||
// pthread_mutex_unlock(&executionLock);
|
||||
m68ki_check_interrupts();
|
||||
}
|
||||
|
||||
|
||||
// Check for interrupts
|
||||
STATIC_INLINE void m68ki_check_interrupts(void)
|
||||
{
|
||||
#if 0
|
||||
if(CPU_INT_LEVEL > FLAG_INT_MASK)
|
||||
m68ki_exception_interrupt(CPU_INT_LEVEL>>8);
|
||||
#else
|
||||
if (regs.intLevel > regs.intmask)
|
||||
m68ki_exception_interrupt(regs.intLevel);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Service an interrupt request and start exception processing
|
||||
void m68ki_exception_interrupt(uint32_t intLevel)
|
||||
{
|
||||
#if 0
|
||||
uint vector;
|
||||
uint sr;
|
||||
uint new_pc;
|
||||
|
||||
/* Turn off the stopped state */
|
||||
CPU_STOPPED &= ~STOP_LEVEL_STOP;
|
||||
|
||||
/* If we are halted, don't do anything */
|
||||
if(CPU_STOPPED)
|
||||
return;
|
||||
|
||||
/* Acknowledge the interrupt */
|
||||
vector = m68ki_int_ack(int_level);
|
||||
|
||||
/* Get the interrupt vector */
|
||||
if(vector == M68K_INT_ACK_AUTOVECTOR)
|
||||
/* Use the autovectors. This is the most commonly used implementation */
|
||||
vector = EXCEPTION_INTERRUPT_AUTOVECTOR+int_level;
|
||||
else if(vector == M68K_INT_ACK_SPURIOUS)
|
||||
/* Called if no devices respond to the interrupt acknowledge */
|
||||
vector = EXCEPTION_SPURIOUS_INTERRUPT;
|
||||
else if(vector > 255)
|
||||
{
|
||||
M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n",
|
||||
m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector));
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start exception processing */
|
||||
sr = m68ki_init_exception();
|
||||
|
||||
/* Set the interrupt mask to the level of the one being serviced */
|
||||
FLAG_INT_MASK = int_level<<8;
|
||||
|
||||
/* Get the new PC */
|
||||
new_pc = m68ki_read_data_32((vector<<2) + REG_VBR);
|
||||
|
||||
/* If vector is uninitialized, call the uninitialized interrupt vector */
|
||||
if(new_pc == 0)
|
||||
new_pc = m68ki_read_data_32((EXCEPTION_UNINITIALIZED_INTERRUPT<<2) + REG_VBR);
|
||||
|
||||
/* Generate a stack frame */
|
||||
m68ki_stack_frame_0000(REG_PC, sr, vector);
|
||||
|
||||
if(FLAG_M && CPU_TYPE_IS_EC020_PLUS(CPU_TYPE))
|
||||
{
|
||||
/* Create throwaway frame */
|
||||
m68ki_set_sm_flag(FLAG_S); /* clear M */
|
||||
sr |= 0x2000; /* Same as SR in master stack frame except S is forced high */
|
||||
m68ki_stack_frame_0001(REG_PC, sr, vector);
|
||||
}
|
||||
|
||||
m68ki_jump(new_pc);
|
||||
|
||||
/* Defer cycle counting until later */
|
||||
CPU_INT_CYCLES += CYC_EXCEPTION[vector];
|
||||
|
||||
#if !M68K_EMULATE_INT_ACK
|
||||
/* Automatically clear IRQ if we are not using an acknowledge scheme */
|
||||
CPU_INT_LEVEL = 0;
|
||||
#endif /* M68K_EMULATE_INT_ACK */
|
||||
#else
|
||||
// Turn off the stopped state (N.B.: normal 68K behavior!)
|
||||
regs.stopped = 0;
|
||||
|
||||
//JLH: need to add halt state?
|
||||
// prolly, for debugging/alpine mode... :-/
|
||||
// but then again, this should be handled already by the main execution loop :-P
|
||||
// If we are halted, don't do anything
|
||||
// if (regs.halted)
|
||||
// return;
|
||||
|
||||
// Acknowledge the interrupt (NOTE: This is a user supplied function!)
|
||||
uint32_t vector = irq_ack_handler(intLevel);
|
||||
|
||||
// Get the interrupt vector
|
||||
if (vector == M68K_INT_ACK_AUTOVECTOR)
|
||||
// Use the autovectors. This is the most commonly used implementation
|
||||
vector = EXCEPTION_INTERRUPT_AUTOVECTOR + intLevel;
|
||||
else if (vector == M68K_INT_ACK_SPURIOUS)
|
||||
// Called if no devices respond to the interrupt acknowledge
|
||||
vector = EXCEPTION_SPURIOUS_INTERRUPT;
|
||||
else if (vector > 255)
|
||||
{
|
||||
// M68K_DO_LOG_EMU((M68K_LOG_FILEHANDLE "%s at %08x: Interrupt acknowledge returned invalid vector $%x\n",
|
||||
// m68ki_cpu_names[CPU_TYPE], ADDRESS_68K(REG_PC), vector));
|
||||
return;
|
||||
}
|
||||
|
||||
// Start exception processing
|
||||
uint32_t sr = m68ki_init_exception();
|
||||
|
||||
// Set the interrupt mask to the level of the one being serviced
|
||||
regs.intmask = intLevel;
|
||||
|
||||
#if 0
|
||||
extern int startM68KTracing;
|
||||
if (startM68KTracing)
|
||||
{
|
||||
printf("IRQ: old PC=%06X, ", regs.pc);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Get the new PC
|
||||
uint32_t newPC = m68k_read_memory_32(vector << 2);
|
||||
|
||||
#if 0
|
||||
if (startM68KTracing)
|
||||
{
|
||||
printf("new PC=%06X, vector=%u, ", newPC, vector);
|
||||
}
|
||||
#endif
|
||||
|
||||
// If vector is uninitialized, call the uninitialized interrupt vector
|
||||
if (newPC == 0)
|
||||
newPC = m68k_read_memory_32(EXCEPTION_UNINITIALIZED_INTERRUPT << 2);
|
||||
|
||||
// Generate a stack frame
|
||||
m68ki_stack_frame_3word(regs.pc, sr);
|
||||
|
||||
m68k_setpc(newPC);
|
||||
#if 0
|
||||
if (startM68KTracing)
|
||||
{
|
||||
printf("(PC=%06X)\n", regs.pc);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Defer cycle counting until later
|
||||
regs.interruptCycles += 56; // NOT ACCURATE-- !!! FIX !!!
|
||||
// CPU_INT_CYCLES += CYC_EXCEPTION[vector];
|
||||
#endif
|
||||
regs.interruptCycles += 56;
|
||||
}
|
||||
|
||||
|
||||
// Initiate exception processing
|
||||
STATIC_INLINE uint32_t m68ki_init_exception(void)
|
||||
{
|
||||
#if 0
|
||||
/* Save the old status register */
|
||||
uint sr = m68ki_get_sr();
|
||||
|
||||
/* Turn off trace flag, clear pending traces */
|
||||
FLAG_T1 = FLAG_T0 = 0;
|
||||
m68ki_clear_trace();
|
||||
/* Enter supervisor mode */
|
||||
m68ki_set_s_flag(SFLAG_SET);
|
||||
|
||||
return sr;
|
||||
#else
|
||||
MakeSR();
|
||||
uint32_t sr = regs.sr; // Save old status register
|
||||
regs.s = 1; // Set supervisor mode
|
||||
uint32_t sr = regs.sr;
|
||||
regs.s = 1;
|
||||
|
||||
return sr;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// 3 word stack frame (68000 only)
|
||||
STATIC_INLINE void m68ki_stack_frame_3word(uint32_t pc, uint32_t sr)
|
||||
{
|
||||
#if 0
|
||||
m68ki_push_32(pc);
|
||||
m68ki_push_16(sr);
|
||||
#else
|
||||
// Push PC on stack:
|
||||
m68k_areg(regs, 7) -= 4;
|
||||
m68k_write_memory_32(m68k_areg(regs, 7), pc);
|
||||
// Push SR on stack:
|
||||
m68k_areg(regs, 7) -= 2;
|
||||
m68k_write_memory_16(m68k_areg(regs, 7), sr);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned int m68k_get_reg(void * context, m68k_register_t reg)
|
||||
unsigned int m68k_get_reg(m68k_register_t reg)
|
||||
{
|
||||
if (reg <= M68K_REG_A7)
|
||||
return regs.regs[reg];
|
||||
|
@ -621,7 +218,6 @@ unsigned int m68k_get_reg(void * context, m68k_register_t reg)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void m68k_set_reg(m68k_register_t reg, unsigned int value)
|
||||
{
|
||||
if (reg <= M68K_REG_A7)
|
||||
|
@ -637,7 +233,6 @@ void m68k_set_reg(m68k_register_t reg, unsigned int value)
|
|||
regs.regs[15] = value;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// Check if the instruction is a valid one
|
||||
//
|
||||
|
@ -651,106 +246,54 @@ unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cp
|
|||
return 1;
|
||||
}
|
||||
|
||||
|
||||
// Dummy functions, for now, until we prove the concept here. :-)
|
||||
|
||||
// Temp, while we're using the Musashi disassembler...
|
||||
#if 0
|
||||
unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int m68k_cycles_run(void) {} /* Number of cycles run so far */
|
||||
int m68k_cycles_remaining(void) {} /* Number of cycles left */
|
||||
//void m68k_modify_timeslice(int cycles) {} /* Modify cycles left */
|
||||
//void m68k_end_timeslice(void) {} /* End timeslice now */
|
||||
|
||||
|
||||
void m68k_modify_timeslice(int cycles)
|
||||
{
|
||||
regs.remainingCycles = cycles;
|
||||
}
|
||||
|
||||
|
||||
void m68k_end_timeslice(void)
|
||||
{
|
||||
#if 0
|
||||
m68ki_initial_cycles = GET_CYCLES();
|
||||
SET_CYCLES(0);
|
||||
#else
|
||||
initialCycles = regs.remainingCycles;
|
||||
regs.remainingCycles = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
unsigned long IllegalOpcode(uint32_t opcode)
|
||||
{
|
||||
#if 0
|
||||
uint32_t pc = m68k_getpc ();
|
||||
#endif
|
||||
if ((opcode & 0xF000) == 0xF000)
|
||||
{
|
||||
Exception(0x0B, 0, M68000_EXC_SRC_CPU); // LineF exception...
|
||||
Exception(0x0B, 0, M68000_EXC_SRC_CPU);
|
||||
return 4;
|
||||
}
|
||||
else if ((opcode & 0xF000) == 0xA000)
|
||||
{
|
||||
Exception(0x0A, 0, M68000_EXC_SRC_CPU); // LineA exception...
|
||||
Exception(0x0A, 0, M68000_EXC_SRC_CPU);
|
||||
return 4;
|
||||
}
|
||||
|
||||
#if 0
|
||||
write_log ("Illegal instruction: %04x at %08lx\n", opcode, (long)pc);
|
||||
#endif
|
||||
|
||||
Exception(0x04, 0, M68000_EXC_SRC_CPU); // Illegal opcode exception...
|
||||
Exception(0x04, 0, M68000_EXC_SRC_CPU);
|
||||
return 4;
|
||||
}
|
||||
|
||||
|
||||
void BuildCPUFunctionTable(void)
|
||||
{
|
||||
int i;
|
||||
unsigned long opcode;
|
||||
|
||||
// We're only using the "fast" 68000 emulation here, not the "compatible"
|
||||
// ("fast" doesn't throw exceptions, so we're using "compatible" now :-P)
|
||||
#if 0
|
||||
const struct cputbl * tbl = (currprefs.cpu_compatible
|
||||
? op_smalltbl_5_ff : op_smalltbl_4_ff);
|
||||
#else
|
||||
//let's try "compatible" and see what happens here...
|
||||
// const struct cputbl * tbl = op_smalltbl_4_ff;
|
||||
const struct cputbl * tbl = op_smalltbl_5_ff;
|
||||
#endif
|
||||
|
||||
// Log_Printf(LOG_DEBUG, "Building CPU function table (%d %d %d).\n",
|
||||
// currprefs.cpu_level, currprefs.cpu_compatible, currprefs.address_space_24);
|
||||
|
||||
// Set all instructions to Illegal...
|
||||
for(opcode=0; opcode<65536; opcode++)
|
||||
cpuFunctionTable[opcode] = IllegalOpcode;
|
||||
|
||||
// Move functions from compact table into our full function table...
|
||||
for(i=0; tbl[i].handler!=NULL; i++)
|
||||
cpuFunctionTable[tbl[i].opcode] = tbl[i].handler;
|
||||
|
||||
//JLH: According to readcpu.c, handler is set to -1 and never changes.
|
||||
// Actually, it does read this crap in readcpu.c, do_merges() does it... :-P
|
||||
// Again, seems like a build time thing could be done here...
|
||||
#if 1
|
||||
for(opcode=0; opcode<65536; opcode++)
|
||||
{
|
||||
// if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > currprefs.cpu_level)
|
||||
if (table68k[opcode].mnemo == i_ILLG || table68k[opcode].clev > 0)
|
||||
continue;
|
||||
|
||||
if (table68k[opcode].handler != -1)
|
||||
{
|
||||
//printf("Relocate: $%04X->$%04X\n", table68k[opcode].handler, opcode);
|
||||
cpuop_func * f = cpuFunctionTable[table68k[opcode].handler];
|
||||
|
||||
if (f == IllegalOpcode)
|
||||
|
@ -759,5 +302,4 @@ void BuildCPUFunctionTable(void)
|
|||
cpuFunctionTable[opcode] = f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -69,7 +69,6 @@ typedef enum
|
|||
*/
|
||||
#define M68K_INT_ACK_SPURIOUS 0xFFFFFFFE
|
||||
|
||||
void m68k_set_cpu_type(unsigned int);
|
||||
void m68k_pulse_reset(void);
|
||||
int m68k_execute(int num_cycles);
|
||||
void m68k_set_irq(unsigned int int_level);
|
||||
|
@ -90,45 +89,24 @@ int irq_ack_handler(int);
|
|||
|
||||
// Convenience functions
|
||||
|
||||
// Uncomment this to have the emulated CPU call a hook function after every instruction
|
||||
// NB: This must be implemented by the user!
|
||||
#define M68K_HOOK_FUNCTION
|
||||
#ifdef M68K_HOOK_FUNCTION
|
||||
void M68KInstructionHook(void);
|
||||
#endif
|
||||
|
||||
// Functions to allow debugging
|
||||
void M68KDebugHalt(void);
|
||||
void M68KDebugResume(void);
|
||||
|
||||
/* Peek at the internals of a CPU context. This can either be a context
|
||||
* retrieved using m68k_get_context() or the currently running context.
|
||||
* If context is NULL, the currently running CPU context will be used.
|
||||
*/
|
||||
unsigned int m68k_get_reg(void * context, m68k_register_t reg);
|
||||
/* Peek at the internals of the currently running CPU context */
|
||||
unsigned int m68k_get_reg(m68k_register_t reg);
|
||||
|
||||
/* Poke values into the internals of the currently running CPU context */
|
||||
void m68k_set_reg(m68k_register_t reg, unsigned int value);
|
||||
|
||||
// Dummy functions, for now...
|
||||
|
||||
/* Check if an instruction is valid for the specified CPU type */
|
||||
unsigned int m68k_is_valid_instruction(unsigned int instruction, unsigned int cpu_type);
|
||||
|
||||
/* Disassemble 1 instruction using the epecified CPU type at pc. Stores
|
||||
* disassembly in str_buff and returns the size of the instruction in bytes.
|
||||
*/
|
||||
unsigned int m68k_disassemble(char * str_buff, unsigned int pc, unsigned int cpu_type);
|
||||
|
||||
/* These functions let you read/write/modify the number of cycles left to run
|
||||
* while m68k_execute() is running.
|
||||
* These are useful if the 68k accesses a memory-mapped port on another device
|
||||
* that requires immediate processing by another CPU.
|
||||
*/
|
||||
int m68k_cycles_run(void); // Number of cycles run so far
|
||||
int m68k_cycles_remaining(void); // Number of cycles left
|
||||
void m68k_modify_timeslice(int cycles); // Modify cycles left
|
||||
void m68k_end_timeslice(void); // End timeslice now
|
||||
void m68k_modify_timeslice(int cycles);
|
||||
void m68k_end_timeslice(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -16,9 +16,6 @@
|
|||
/* 2008/04/26 [NP] Handle sz_byte for Areg as a valid srcmode if current instruction is a MOVE */
|
||||
/* (e.g. move.b a1,(a0) ($1089)) (fix Blood Money on Superior 65) */
|
||||
|
||||
|
||||
//const char ReadCpu_fileid[] = "Hatari readcpu.c : " __DATE__ " " __TIME__;
|
||||
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
|
||||
|
@ -219,12 +216,6 @@ static void build_insn(int insn)
|
|||
int flaglive = 0, flagdead = 0;
|
||||
id = defs68k[insn];
|
||||
|
||||
/* Note: We treat anything with unknown flags as a jump. That
|
||||
is overkill, but "the programmer" was lazy quite often, and
|
||||
*this* programmer can't be bothered to work out what can and
|
||||
can't trap. Usually, this will be overwritten with the gencomp
|
||||
based information, anyway. */
|
||||
|
||||
for(j=0; j<5; j++)
|
||||
{
|
||||
switch (id.flaginfo[j].flagset)
|
||||
|
@ -304,14 +295,12 @@ out1:
|
|||
if (bitval[bitj] == 0)
|
||||
bitval[bitj] = 8;
|
||||
|
||||
/* first check whether this one does not match after all */
|
||||
if (bitval[bitz] == 3 || bitval[bitC] == 1)
|
||||
continue;
|
||||
|
||||
if (bitcnt[bitI] && (bitval[bitI] == 0x00 || bitval[bitI] == 0xff))
|
||||
continue;
|
||||
|
||||
/* bitI and bitC get copied to biti and bitc */
|
||||
if (bitcnt[bitI])
|
||||
{
|
||||
bitval[biti] = bitval[bitI]; bitpos[biti] = bitpos[bitI];
|
||||
|
@ -367,15 +356,12 @@ out1:
|
|||
|
||||
mnemonic[mnp] = 0;
|
||||
|
||||
/* now, we have read the mnemonic and the size */
|
||||
while (opcstr[pos] && isspace((unsigned)opcstr[pos]))
|
||||
pos++;
|
||||
|
||||
/* A goto a day keeps the D******a away. */
|
||||
if (opcstr[pos] == 0)
|
||||
goto endofline;
|
||||
|
||||
/* parse the source address */
|
||||
usesrc = 1;
|
||||
switch (opcstr[pos++])
|
||||
{
|
||||
|
@ -422,7 +408,6 @@ out1:
|
|||
|
||||
if (CPU_EMU_SIZE < 4)
|
||||
{
|
||||
/* Used for branch instructions */
|
||||
srctype = 1;
|
||||
srcgather = 1;
|
||||
srcpos = bitpos[biti];
|
||||
|
@ -434,7 +419,6 @@ out1:
|
|||
|
||||
if (CPU_EMU_SIZE < 3)
|
||||
{
|
||||
/* 1..8 for ADDQ/SUBQ and rotshi insns */
|
||||
srcgather = 1;
|
||||
srctype = 3;
|
||||
srcpos = bitpos[bitj];
|
||||
|
@ -446,7 +430,6 @@ out1:
|
|||
|
||||
if (CPU_EMU_SIZE < 5)
|
||||
{
|
||||
/* 0..15 */
|
||||
srcgather = 1;
|
||||
srctype = 2;
|
||||
srcpos = bitpos[bitJ];
|
||||
|
@ -469,7 +452,6 @@ out1:
|
|||
|
||||
if (CPU_EMU_SIZE < 5)
|
||||
{
|
||||
/* 0..15 */
|
||||
srcgather = 1;
|
||||
srctype = 5;
|
||||
srcpos = bitpos[bitK];
|
||||
|
@ -481,7 +463,6 @@ out1:
|
|||
|
||||
if (CPU_EMU_SIZE < 5)
|
||||
{
|
||||
/* 0..3 */
|
||||
srcgather = 1;
|
||||
srctype = 7;
|
||||
srcpos = bitpos[bitp];
|
||||
|
@ -514,7 +495,6 @@ out1:
|
|||
|
||||
if (opcstr[pos] == '!')
|
||||
{
|
||||
/* exclusion */
|
||||
do
|
||||
{
|
||||
pos++;
|
||||
|
@ -532,7 +512,6 @@ out1:
|
|||
{
|
||||
if (opcstr[pos + 4] == '-')
|
||||
{
|
||||
/* replacement */
|
||||
if (mode_from_str(opcstr + pos) == srcmode)
|
||||
srcmode = mode_from_str(opcstr + pos + 5);
|
||||
else
|
||||
|
@ -542,7 +521,6 @@ out1:
|
|||
}
|
||||
else
|
||||
{
|
||||
/* normal */
|
||||
while(mode_from_str(opcstr + pos) != srcmode)
|
||||
{
|
||||
pos += 4;
|
||||
|
@ -562,7 +540,6 @@ out1:
|
|||
}
|
||||
}
|
||||
|
||||
/* Some addressing modes are invalid as destination */
|
||||
if (srcmode == imm || srcmode == PC16 || srcmode == PC8r)
|
||||
goto nomatch;
|
||||
|
||||
|
@ -589,7 +566,6 @@ out1:
|
|||
|
||||
if (opcstr[pos] == '!')
|
||||
{
|
||||
/* exclusion */
|
||||
do
|
||||
{
|
||||
pos++;
|
||||
|
@ -607,7 +583,6 @@ out1:
|
|||
{
|
||||
if (opcstr[pos + 4] == '-')
|
||||
{
|
||||
/* replacement */
|
||||
if (mode_from_str(opcstr + pos) == srcmode)
|
||||
srcmode = mode_from_str(opcstr + pos + 5);
|
||||
else
|
||||
|
@ -617,7 +592,6 @@ out1:
|
|||
}
|
||||
else
|
||||
{
|
||||
/* normal */
|
||||
while(mode_from_str(opcstr+pos) != srcmode)
|
||||
{
|
||||
pos += 4;
|
||||
|
@ -639,7 +613,6 @@ out1:
|
|||
default: abort();
|
||||
}
|
||||
|
||||
/* safety check - might have changed */
|
||||
if (srcmode != Areg && srcmode != Dreg && srcmode != Aind
|
||||
&& srcmode != Ad16 && srcmode != Ad8r && srcmode != Aipi
|
||||
&& srcmode != Apdi && srcmode != immi)
|
||||
|
@ -647,8 +620,7 @@ out1:
|
|||
srcgather = 0;
|
||||
}
|
||||
|
||||
// if (srcmode == Areg && sz == sz_byte)
|
||||
if (srcmode == Areg && sz == sz_byte && strcmp(mnemonic, "MOVE") != 0 ) // [NP] move.b is valid on 68000
|
||||
if (srcmode == Areg && sz == sz_byte && strcmp(mnemonic, "MOVE") != 0 )
|
||||
goto nomatch;
|
||||
|
||||
if (opcstr[pos] != ',')
|
||||
|
@ -656,7 +628,6 @@ out1:
|
|||
|
||||
pos++;
|
||||
|
||||
/* parse the destination address */
|
||||
usedst = 1;
|
||||
|
||||
switch (opcstr[pos++])
|
||||
|
@ -736,7 +707,6 @@ out1:
|
|||
|
||||
if (opcstr[pos] == '!')
|
||||
{
|
||||
/* exclusion */
|
||||
do
|
||||
{
|
||||
pos++;
|
||||
|
@ -754,7 +724,6 @@ out1:
|
|||
{
|
||||
if (opcstr[pos+4] == '-')
|
||||
{
|
||||
/* replacement */
|
||||
if (mode_from_str(opcstr + pos) == destmode)
|
||||
destmode = mode_from_str(opcstr + pos + 5);
|
||||
else
|
||||
|
@ -764,7 +733,6 @@ out1:
|
|||
}
|
||||
else
|
||||
{
|
||||
/* normal */
|
||||
while(mode_from_str(opcstr + pos) != destmode)
|
||||
{
|
||||
pos += 4;
|
||||
|
@ -784,7 +752,6 @@ out1:
|
|||
}
|
||||
}
|
||||
|
||||
/* Some addressing modes are invalid as destination */
|
||||
if (destmode == imm || destmode == PC16 || destmode == PC8r)
|
||||
goto nomatch;
|
||||
|
||||
|
@ -810,7 +777,6 @@ out1:
|
|||
|
||||
if (opcstr[pos] == '!')
|
||||
{
|
||||
/* exclusion */
|
||||
do
|
||||
{
|
||||
pos++;
|
||||
|
@ -828,7 +794,6 @@ out1:
|
|||
{
|
||||
if (opcstr[pos+4] == '-')
|
||||
{
|
||||
/* replacement */
|
||||
if (mode_from_str(opcstr + pos) == destmode)
|
||||
destmode = mode_from_str(opcstr + pos + 5);
|
||||
else
|
||||
|
@ -838,7 +803,6 @@ out1:
|
|||
}
|
||||
else
|
||||
{
|
||||
/* normal */
|
||||
while (mode_from_str(opcstr + pos) != destmode)
|
||||
{
|
||||
pos += 4;
|
||||
|
@ -860,7 +824,6 @@ out1:
|
|||
default: abort();
|
||||
}
|
||||
|
||||
/* safety check - might have changed */
|
||||
if (destmode != Areg && destmode != Dreg && destmode != Aind
|
||||
&& destmode != Ad16 && destmode != Ad8r && destmode != Aipi
|
||||
&& destmode != Apdi)
|
||||
|
@ -870,13 +833,7 @@ out1:
|
|||
|
||||
if (destmode == Areg && sz == sz_byte)
|
||||
goto nomatch;
|
||||
#if 0
|
||||
if (sz == sz_byte && (destmode == Aipi || destmode == Apdi)) {
|
||||
dstgather = 0;
|
||||
}
|
||||
#endif
|
||||
endofline:
|
||||
/* now, we have a match */
|
||||
if (table68k[opc].mnemo != i_ILLG)
|
||||
fprintf(stderr, "Double match: %x: %s\n", opc, opcstr);
|
||||
|
||||
|
@ -921,22 +878,15 @@ endofline:
|
|||
table68k[opc].stype = srctype;
|
||||
table68k[opc].plev = id.plevel;
|
||||
table68k[opc].clev = id.cpulevel;
|
||||
#if 0
|
||||
for (i = 0; i < 5; i++) {
|
||||
table68k[opc].flaginfo[i].flagset = id.flaginfo[i].flagset;
|
||||
table68k[opc].flaginfo[i].flaguse = id.flaginfo[i].flaguse;
|
||||
}
|
||||
#endif
|
||||
table68k[opc].flagdead = flagdead;
|
||||
table68k[opc].flaglive = flaglive;
|
||||
table68k[opc].isjmp = isjmp;
|
||||
|
||||
nomatch:
|
||||
/* FOO! */;
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void read_table68k(void)
|
||||
{
|
||||
int i;
|
||||
|
@ -952,21 +902,15 @@ void read_table68k(void)
|
|||
build_insn(i);
|
||||
}
|
||||
|
||||
|
||||
static int mismatch;
|
||||
|
||||
|
||||
static void handle_merges (long int opcode)
|
||||
static void handle_merges(long int opcode)
|
||||
{
|
||||
uint16_t smsk;
|
||||
uint16_t dmsk;
|
||||
int sbitdst, dstend;
|
||||
int srcreg, dstreg;
|
||||
|
||||
//0011 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.W s,d[!Areg]
|
||||
//31C3 ->
|
||||
//0011 0001 1100 0011 : DDD = 0, ddd = 7, sss = 0, SSS = 3
|
||||
|
||||
if (table68k[opcode].spos == -1)
|
||||
{
|
||||
sbitdst = 1;
|
||||
|
@ -1019,9 +963,6 @@ static void handle_merges (long int opcode)
|
|||
code = (code & ~smsk) | (srcreg << table68k[opcode].spos);
|
||||
code = (code & ~dmsk) | (dstreg << table68k[opcode].dpos);
|
||||
|
||||
/* Check whether this is in fact the same instruction.
|
||||
* The instructions should never differ, except for the
|
||||
* Bcc.(BW) case. */
|
||||
if (table68k[code].mnemo != table68k[opcode].mnemo
|
||||
|| table68k[code].size != table68k[opcode].size
|
||||
|| table68k[code].suse != table68k[opcode].suse
|
||||
|
@ -1051,52 +992,11 @@ static void handle_merges (long int opcode)
|
|||
if (code != opcode)
|
||||
{
|
||||
table68k[code].handler = opcode;
|
||||
|
||||
#if 0
|
||||
if (opcode == 0x31C3 || code == 0x31C3)
|
||||
{
|
||||
printf("Relocate... ($%04X->$%04X)\n", (uint16_t)opcode, code);
|
||||
printf(" handler: %08X\n", table68k[code].handler);
|
||||
printf(" dreg: %i\n", table68k[code].dreg);
|
||||
printf(" sreg: %i\n", table68k[code].sreg);
|
||||
printf(" dpos: %i\n", table68k[code].dpos);
|
||||
printf(" spos: %i\n", table68k[code].spos);
|
||||
printf(" sduse: %i\n", table68k[code].sduse);
|
||||
printf("flagdead: %i\n", table68k[code].flagdead);
|
||||
printf("flaglive: %i\n", table68k[code].flaglive);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
long int handler;
|
||||
unsigned char dreg;
|
||||
unsigned char sreg;
|
||||
signed char dpos;
|
||||
signed char spos;
|
||||
unsigned char sduse;
|
||||
int flagdead:8, flaglive:8;
|
||||
unsigned int mnemo:8;
|
||||
unsigned int cc:4;
|
||||
unsigned int plev:2;
|
||||
unsigned int size:2;
|
||||
unsigned int smode:5;
|
||||
unsigned int stype:3;
|
||||
unsigned int dmode:5;
|
||||
unsigned int suse:1;
|
||||
unsigned int duse:1;
|
||||
unsigned int unused1:1;
|
||||
unsigned int clev:3;
|
||||
unsigned int isjmp:1;
|
||||
unsigned int unused2:4;
|
||||
*/
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// What this really does is expand the # of handlers, which is why the
|
||||
// opcode has to be passed into the opcode handler...
|
||||
// E.g., $F620 maps into $F621-F627 as well; this code does this expansion.
|
||||
void do_merges(void)
|
||||
{
|
||||
long int opcode;
|
||||
|
@ -1115,9 +1015,7 @@ void do_merges(void)
|
|||
nr_cpuop_funcs = nr;
|
||||
}
|
||||
|
||||
|
||||
int get_no_mismatches(void)
|
||||
{
|
||||
return mismatch;
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
|
||||
#include "sysdeps.h"
|
||||
|
||||
|
||||
ENUMDECL {
|
||||
Dreg, Areg, Aind, Aipi, Apdi, Ad16, Ad8r,
|
||||
absw, absl, PC16, PC8r, imm, imm0, imm1, imm2, immi, am_unknown, am_illg
|
||||
|
@ -44,7 +43,7 @@ ENUMDECL {
|
|||
i_CINVL, i_CINVP, i_CINVA, i_CPUSHL, i_CPUSHP, i_CPUSHA, i_MOVE16,
|
||||
i_MMUOP,
|
||||
|
||||
MAX_OPCODE_FAMILY /* should always be last of the list */
|
||||
MAX_OPCODE_FAMILY
|
||||
} ENUMNAME (instrmnem);
|
||||
|
||||
extern const struct mnemolookup {
|
||||
|
|
|
@ -27,67 +27,11 @@
|
|||
#include <assert.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef __STDC__
|
||||
#error "Your compiler is not ANSI. Get a real one."
|
||||
#endif
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#if EEXIST == ENOTEMPTY
|
||||
#define BROKEN_OS_PROBABLY_AIX
|
||||
#endif
|
||||
|
||||
#ifdef __NeXT__
|
||||
#define S_IRUSR S_IREAD
|
||||
#define S_IWUSR S_IWRITE
|
||||
#define S_IXUSR S_IEXEC
|
||||
#define S_ISDIR(val) (S_IFDIR & val)
|
||||
struct utimbuf
|
||||
{
|
||||
time_t actime;
|
||||
time_t modtime;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(WARPUP)
|
||||
#include "devices/timer.h"
|
||||
#include "osdep/posixemu.h"
|
||||
#define RETSIGTYPE
|
||||
#define USE_ZFILE
|
||||
#define strcasecmp stricmp
|
||||
#define memcpy q_memcpy
|
||||
#define memset q_memset
|
||||
#define strdup my_strdup
|
||||
#define random rand
|
||||
#define creat(x,y) open("T:creat",O_CREAT|O_RDWR|O_TRUNC,777)
|
||||
extern void * q_memset(void *, int, size_t);
|
||||
extern void * q_memcpy(void *, const void *, size_t);
|
||||
#endif
|
||||
|
||||
|
||||
/* Acorn specific stuff */
|
||||
#ifdef ACORN
|
||||
|
||||
#define S_IRUSR S_IREAD
|
||||
#define S_IWUSR S_IWRITE
|
||||
#define S_IXUSR S_IEXEC
|
||||
|
||||
#define strcasecmp stricmp
|
||||
|
||||
#endif
|
||||
|
||||
/* We can only rely on GNU C getting enums right. Mickeysoft VSC++ is known
|
||||
* to have problems, and it's likely that other compilers choke too. */
|
||||
#ifdef __GNUC__
|
||||
#define ENUMDECL typedef enum
|
||||
#define ENUMNAME(name) name
|
||||
#else
|
||||
#define ENUMDECL enum
|
||||
#define ENUMNAME(name) ; typedef int name
|
||||
#endif
|
||||
|
||||
/* When using GNU C, make abort more useful. */
|
||||
#ifdef __GNUC__
|
||||
|
@ -98,11 +42,6 @@ extern void * q_memcpy(void *, const void *, size_t);
|
|||
} while (0)
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef O_BINARY
|
||||
#define O_BINARY 0
|
||||
#endif
|
||||
|
||||
#ifndef STATIC_INLINE
|
||||
#define STATIC_INLINE static __inline__
|
||||
#endif
|
||||
|
|
|
@ -1,260 +0,0 @@
|
|||
% 0: bit 0
|
||||
% 1: bit 1
|
||||
% c: condition code
|
||||
% C: condition codes, except F
|
||||
% f: direction
|
||||
% i: immediate
|
||||
% I: immediate, except 00 and ff
|
||||
% j: immediate 1..8
|
||||
% J: immediate 0..15
|
||||
% k: immediate 0..7
|
||||
% K: immediate 0..63
|
||||
% p: immediate 0..3 (CINV and CPUSH: cache field)
|
||||
% s: source mode
|
||||
% S: source reg
|
||||
% d: dest mode
|
||||
% D: dest reg
|
||||
% r: reg
|
||||
% z: size
|
||||
%
|
||||
% Actually, a sssSSS may appear as a destination, and
|
||||
% vice versa. The only difference between sssSSS and
|
||||
% dddDDD are the valid addressing modes. There is
|
||||
% no match for immediate and pc-rel. addressing modes
|
||||
% in case of dddDDD.
|
||||
%
|
||||
% Arp: --> -(Ar)
|
||||
% ArP: --> (Ar)+
|
||||
% L: (xxx.L)
|
||||
%
|
||||
% Fields on a line:
|
||||
% 16 chars bitpattern :
|
||||
% CPU level / privilege level :
|
||||
% CPU level 0: 68000
|
||||
% 1: 68010
|
||||
% 2: 68020
|
||||
% privilege level 0: not privileged
|
||||
% 1: unprivileged only on 68000 (check regs.s)
|
||||
% 2: privileged (check regs.s)
|
||||
% 3: privileged if size == word (check regs.s)
|
||||
% Flags set by instruction: XNZVC :
|
||||
% Flags used by instruction: XNZVC :
|
||||
% - means flag unaffected / unused
|
||||
% 0 means flag reset
|
||||
% 1 means flag set
|
||||
% ? means programmer was too lazy to check or instruction may trap
|
||||
% + means instruction is conditional branch
|
||||
% everything else means flag set/used
|
||||
% / means instruction is unconditional branch/call
|
||||
% x means flag is unknown and well-behaved programs shouldn't check it
|
||||
% srcaddr status destaddr status :
|
||||
% bitmasks of
|
||||
% 1 means fetched
|
||||
% 2 means stored
|
||||
% 4 means jump offset
|
||||
% 8 means jump address
|
||||
% instruction
|
||||
%
|
||||
|
||||
0000 0000 0011 1100:00:XNZVC:XNZVC:10: ORSR.B #1
|
||||
0000 0000 0111 1100:02:?????:?????:10: ORSR.W #1
|
||||
0000 0zz0 11ss sSSS:20:?????:?????:11: CHK2.z #1,s[!Dreg,Areg,Aipi,Apdi,Immd]
|
||||
0000 0000 zzdd dDDD:00:-NZ00:-----:13: OR.z #z,d[!Areg]
|
||||
0000 0010 0011 1100:00:XNZVC:XNZVC:10: ANDSR.B #1
|
||||
0000 0010 0111 1100:02:?????:?????:10: ANDSR.W #1
|
||||
0000 0010 zzdd dDDD:00:-NZ00:-----:13: AND.z #z,d[!Areg]
|
||||
0000 0100 zzdd dDDD:00:XNZVC:-----:13: SUB.z #z,d[!Areg]
|
||||
0000 0110 zzdd dDDD:00:XNZVC:-----:13: ADD.z #z,d[!Areg]
|
||||
0000 0110 11ss sSSS:20:?????:?????:10: CALLM s[!Dreg,Areg,Aipi,Apdi,Immd]
|
||||
0000 0110 11ss sSSS:20:?????:?????:10: RTM s[Dreg,Areg]
|
||||
0000 1000 00ss sSSS:00:--Z--:-----:11: BTST #1,s[!Areg]
|
||||
0000 1000 01ss sSSS:00:--Z--:-----:13: BCHG #1,s[!Areg,Immd]
|
||||
0000 1000 10ss sSSS:00:--Z--:-----:13: BCLR #1,s[!Areg,Immd]
|
||||
0000 1000 11ss sSSS:00:--Z--:-----:13: BSET #1,s[!Areg,Immd]
|
||||
0000 1010 0011 1100:00:XNZVC:XNZVC:10: EORSR.B #1
|
||||
0000 1010 0111 1100:02:?????:?????:10: EORSR.W #1
|
||||
0000 1010 zzdd dDDD:00:-NZ00:-----:13: EOR.z #z,d[!Areg]
|
||||
0000 1100 zzss sSSS:00:-NZVC:-----:11: CMP.z #z,s[!Areg,Immd]
|
||||
|
||||
0000 1010 11ss sSSS:20:?????:?????:13: CAS.B #1,s[!Dreg,Areg,Immd,PC8r,PC16]
|
||||
0000 1100 11ss sSSS:20:?????:?????:13: CAS.W #1,s[!Dreg,Areg,Immd,PC8r,PC16]
|
||||
0000 1100 1111 1100:20:?????:?????:10: CAS2.W #2
|
||||
0000 1110 zzss sSSS:22:?????:?????:13: MOVES.z #1,s[!Dreg,Areg,Immd,PC8r,PC16]
|
||||
0000 1110 11ss sSSS:20:?????:?????:13: CAS.L #1,s[!Dreg,Areg,Immd,PC8r,PC16]
|
||||
0000 1110 1111 1100:20:?????:?????:10: CAS2.L #2
|
||||
|
||||
0000 rrr1 00dd dDDD:00:-----:-----:12: MVPMR.W d[Areg-Ad16],Dr
|
||||
0000 rrr1 01dd dDDD:00:-----:-----:12: MVPMR.L d[Areg-Ad16],Dr
|
||||
0000 rrr1 10dd dDDD:00:-----:-----:12: MVPRM.W Dr,d[Areg-Ad16]
|
||||
0000 rrr1 11dd dDDD:00:-----:-----:12: MVPRM.L Dr,d[Areg-Ad16]
|
||||
0000 rrr1 00ss sSSS:00:--Z--:-----:11: BTST Dr,s[!Areg]
|
||||
0000 rrr1 01ss sSSS:00:--Z--:-----:13: BCHG Dr,s[!Areg,Immd]
|
||||
0000 rrr1 10ss sSSS:00:--Z--:-----:13: BCLR Dr,s[!Areg,Immd]
|
||||
0000 rrr1 11ss sSSS:00:--Z--:-----:13: BSET Dr,s[!Areg,Immd]
|
||||
|
||||
0001 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.B s,d[!Areg]
|
||||
0010 DDDd ddss sSSS:00:-----:-----:12: MOVEA.L s,d[Areg]
|
||||
0010 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.L s,d[!Areg]
|
||||
0011 DDDd ddss sSSS:00:-----:-----:12: MOVEA.W s,d[Areg]
|
||||
0011 DDDd ddss sSSS:00:-NZ00:-----:12: MOVE.W s,d[!Areg]
|
||||
|
||||
0100 0000 zzdd dDDD:00:XxZxC:X-Z--:30: NEGX.z d[!Areg]
|
||||
0100 0000 11dd dDDD:01:?????:?????:10: MVSR2.W d[!Areg]
|
||||
0100 0010 zzdd dDDD:00:-0100:-----:20: CLR.z d[!Areg]
|
||||
0100 0010 11dd dDDD:10:?????:?????:10: MVSR2.B d[!Areg]
|
||||
0100 0100 zzdd dDDD:00:XNZVC:-----:30: NEG.z d[!Areg]
|
||||
0100 0100 11ss sSSS:00:XNZVC:-----:10: MV2SR.B s[!Areg]
|
||||
0100 0110 zzdd dDDD:00:-NZ00:-----:30: NOT.z d[!Areg]
|
||||
0100 0110 11ss sSSS:02:?????:?????:10: MV2SR.W s[!Areg]
|
||||
0100 1000 0000 1rrr:20:-----:-----:31: LINK.L Ar,#2
|
||||
0100 1000 00dd dDDD:00:X?Z?C:X-Z--:30: NBCD.B d[!Areg]
|
||||
0100 1000 0100 1kkk:20:?????:?????:10: BKPT #k
|
||||
0100 1000 01ss sSSS:00:-NZ00:-----:30: SWAP.W s[Dreg]
|
||||
0100 1000 01ss sSSS:00:-----:-----:00: PEA.L s[!Dreg,Areg,Aipi,Apdi,Immd]
|
||||
0100 1000 10dd dDDD:00:-NZ00:-----:30: EXT.W d[Dreg]
|
||||
0100 1000 10dd dDDD:00:-----:-----:02: MVMLE.W #1,d[!Dreg,Areg,Aipi]
|
||||
0100 1000 11dd dDDD:00:-NZ00:-----:30: EXT.L d[Dreg]
|
||||
0100 1000 11dd dDDD:00:-----:-----:02: MVMLE.L #1,d[!Dreg,Areg,Aipi]
|
||||
0100 1001 11dd dDDD:20:-NZ00:-----:30: EXT.B d[Dreg]
|
||||
0100 1010 zzss sSSS:00:-NZ00:-----:10: TST.z s
|
||||
0100 1010 11dd dDDD:00:?????:?????:30: TAS.B d[!Areg]
|
||||
0100 1010 1111 1100:00:?????:?????:00: ILLEGAL
|
||||
0100 1100 00ss sSSS:20:-NZVC:-----:13: MULL.L #1,s[!Areg]
|
||||
0100 1100 01ss sSSS:20:?????:?????:13: DIVL.L #1,s[!Areg]
|
||||
0100 1100 10ss sSSS:00:-----:-----:01: MVMEL.W #1,s[!Dreg,Areg,Apdi,Immd]
|
||||
0100 1100 11ss sSSS:00:-----:-----:01: MVMEL.L #1,s[!Dreg,Areg,Apdi,Immd]
|
||||
0100 1110 0100 JJJJ:00:-----:XNZVC:10: TRAP #J
|
||||
0100 1110 0101 0rrr:00:-----:-----:31: LINK.W Ar,#1
|
||||
0100 1110 0101 1rrr:00:-----:-----:30: UNLK.L Ar
|
||||
0100 1110 0110 0rrr:02:-----:-----:10: MVR2USP.L Ar
|
||||
0100 1110 0110 1rrr:02:-----:-----:20: MVUSP2R.L Ar
|
||||
0100 1110 0111 0000:02:-----:-----:00: RESET
|
||||
0100 1110 0111 0001:00:-----:-----:00: NOP
|
||||
0100 1110 0111 0010:02:XNZVC:-----:10: STOP #1
|
||||
0100 1110 0111 0011:02:XNZVC:-----:00: RTE
|
||||
0100 1110 0111 0100:00:?????:?????:10: RTD #1
|
||||
0100 1110 0111 0101:00:-----:-----:00: RTS
|
||||
0100 1110 0111 0110:00:-----:XNZVC:00: TRAPV
|
||||
0100 1110 0111 0111:00:XNZVC:-----:00: RTR
|
||||
0100 1110 0111 1010:12:?????:?????:10: MOVEC2 #1
|
||||
0100 1110 0111 1011:12:?????:?????:10: MOVE2C #1
|
||||
0100 1110 10ss sSSS:00://///://///:80: JSR.L s[!Dreg,Areg,Aipi,Apdi,Immd]
|
||||
0100 rrr1 00ss sSSS:20:?????:?????:11: CHK.L s[!Areg],Dr
|
||||
0100 rrr1 10ss sSSS:00:?????:?????:11: CHK.W s[!Areg],Dr
|
||||
0100 1110 11ss sSSS:00://///://///:80: JMP.L s[!Dreg,Areg,Aipi,Apdi,Immd]
|
||||
0100 rrr1 11ss sSSS:00:-----:-----:02: LEA.L s[!Dreg,Areg,Aipi,Apdi,Immd],Ar
|
||||
|
||||
0101 jjj0 01dd dDDD:00:-----:-----:13: ADDA.W #j,d[Areg]
|
||||
0101 jjj0 10dd dDDD:00:-----:-----:13: ADDA.L #j,d[Areg]
|
||||
0101 jjj0 zzdd dDDD:00:XNZVC:-----:13: ADD.z #j,d[!Areg]
|
||||
0101 jjj1 01dd dDDD:00:-----:-----:13: SUBA.W #j,d[Areg]
|
||||
0101 jjj1 10dd dDDD:00:-----:-----:13: SUBA.L #j,d[Areg]
|
||||
0101 jjj1 zzdd dDDD:00:XNZVC:-----:13: SUB.z #j,d[!Areg]
|
||||
0101 cccc 1100 1rrr:00:-----:-++++:31: DBcc.W Dr,#1
|
||||
0101 cccc 11dd dDDD:00:-----:-++++:20: Scc.B d[!Areg]
|
||||
0101 cccc 1111 1010:20:?????:?????:10: TRAPcc #1
|
||||
0101 cccc 1111 1011:20:?????:?????:10: TRAPcc #2
|
||||
0101 cccc 1111 1100:20:?????:?????:00: TRAPcc
|
||||
|
||||
% Bxx.L is 68020 only, but setting the CPU level to 2 would give illegal
|
||||
% instruction exceptions when compiling a 68000 only emulation, which isn't
|
||||
% what we want either.
|
||||
0110 0001 0000 0000:00://///://///:40: BSR.W #1
|
||||
0110 0001 IIII IIII:00://///://///:40: BSR.B #i
|
||||
0110 0001 1111 1111:00://///://///:40: BSR.L #2
|
||||
0110 CCCC 0000 0000:00:-----:-++++:40: Bcc.W #1
|
||||
0110 CCCC IIII IIII:00:-----:-++++:40: Bcc.B #i
|
||||
0110 CCCC 1111 1111:00:-----:-++++:40: Bcc.L #2
|
||||
|
||||
0111 rrr0 iiii iiii:00:-NZ00:-----:12: MOVE.L #i,Dr
|
||||
|
||||
1000 rrr0 zzss sSSS:00:-NZ00:-----:13: OR.z s[!Areg],Dr
|
||||
1000 rrr0 11ss sSSS:00:?????:?????:13: DIVU.W s[!Areg],Dr
|
||||
1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: SBCD.B d[Dreg],Dr
|
||||
1000 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: SBCD.B d[Areg-Apdi],Arp
|
||||
1000 rrr1 zzdd dDDD:00:-NZ00:-----:13: OR.z Dr,d[!Areg,Dreg]
|
||||
1000 rrr1 01dd dDDD:20:?????:?????:12: PACK d[Dreg],Dr
|
||||
1000 rrr1 01dd dDDD:20:?????:?????:12: PACK d[Areg-Apdi],Arp
|
||||
1000 rrr1 10dd dDDD:20:?????:?????:12: UNPK d[Dreg],Dr
|
||||
1000 rrr1 10dd dDDD:20:?????:?????:12: UNPK d[Areg-Apdi],Arp
|
||||
1000 rrr1 11ss sSSS:00:?????:?????:13: DIVS.W s[!Areg],Dr
|
||||
|
||||
1001 rrr0 zzss sSSS:00:XNZVC:-----:13: SUB.z s,Dr
|
||||
1001 rrr0 11ss sSSS:00:-----:-----:13: SUBA.W s,Ar
|
||||
1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: SUBX.z d[Dreg],Dr
|
||||
1001 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: SUBX.z d[Areg-Apdi],Arp
|
||||
1001 rrr1 zzdd dDDD:00:XNZVC:-----:13: SUB.z Dr,d[!Areg,Dreg]
|
||||
1001 rrr1 11ss sSSS:00:-----:-----:13: SUBA.L s,Ar
|
||||
|
||||
1011 rrr0 zzss sSSS:00:-NZVC:-----:11: CMP.z s,Dr
|
||||
1011 rrr0 11ss sSSS:00:-NZVC:-----:11: CMPA.W s,Ar
|
||||
1011 rrr1 11ss sSSS:00:-NZVC:-----:11: CMPA.L s,Ar
|
||||
1011 rrr1 zzdd dDDD:00:-NZVC:-----:11: CMPM.z d[Areg-Aipi],ArP
|
||||
1011 rrr1 zzdd dDDD:00:-NZ00:-----:13: EOR.z Dr,d[!Areg]
|
||||
|
||||
1100 rrr0 zzss sSSS:00:-NZ00:-----:13: AND.z s[!Areg],Dr
|
||||
1100 rrr0 11ss sSSS:00:-NZ00:-----:13: MULU.W s[!Areg],Dr
|
||||
1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: ABCD.B d[Dreg],Dr
|
||||
1100 rrr1 00dd dDDD:00:XxZxC:X-Z--:13: ABCD.B d[Areg-Apdi],Arp
|
||||
1100 rrr1 zzdd dDDD:00:-NZ00:-----:13: AND.z Dr,d[!Areg,Dreg]
|
||||
1100 rrr1 01dd dDDD:00:-----:-----:33: EXG.L Dr,d[Dreg]
|
||||
1100 rrr1 01dd dDDD:00:-----:-----:33: EXG.L Ar,d[Areg]
|
||||
1100 rrr1 10dd dDDD:00:-----:-----:33: EXG.L Dr,d[Areg]
|
||||
1100 rrr1 11ss sSSS:00:-NZ00:-----:13: MULS.W s[!Areg],Dr
|
||||
|
||||
1101 rrr0 zzss sSSS:00:XNZVC:-----:13: ADD.z s,Dr
|
||||
1101 rrr0 11ss sSSS:00:-----:-----:13: ADDA.W s,Ar
|
||||
1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: ADDX.z d[Dreg],Dr
|
||||
1101 rrr1 zzdd dDDD:00:XNZVC:X-Z--:13: ADDX.z d[Areg-Apdi],Arp
|
||||
1101 rrr1 zzdd dDDD:00:XNZVC:-----:13: ADD.z Dr,d[!Areg,Dreg]
|
||||
1101 rrr1 11ss sSSS:00:-----:-----:13: ADDA.L s,Ar
|
||||
|
||||
1110 jjjf zz00 0RRR:00:XNZVC:-----:13: ASf.z #j,DR
|
||||
1110 jjjf zz00 1RRR:00:XNZ0C:-----:13: LSf.z #j,DR
|
||||
1110 jjjf zz01 0RRR:00:XNZ0C:X----:13: ROXf.z #j,DR
|
||||
1110 jjjf zz01 1RRR:00:-NZ0C:-----:13: ROf.z #j,DR
|
||||
1110 rrrf zz10 0RRR:00:XNZVC:X----:13: ASf.z Dr,DR
|
||||
1110 rrrf zz10 1RRR:00:XNZ0C:X----:13: LSf.z Dr,DR
|
||||
1110 rrrf zz11 0RRR:00:XNZ0C:X----:13: ROXf.z Dr,DR
|
||||
1110 rrrf zz11 1RRR:00:-NZ0C:-----:13: ROf.z Dr,DR
|
||||
1110 000f 11dd dDDD:00:XNZVC:-----:13: ASfW.W d[!Dreg,Areg]
|
||||
1110 001f 11dd dDDD:00:XNZ0C:-----:13: LSfW.W d[!Dreg,Areg]
|
||||
1110 010f 11dd dDDD:00:XNZ0C:X----:13: ROXfW.W d[!Dreg,Areg]
|
||||
1110 011f 11dd dDDD:00:-NZ0C:-----:13: ROfW.W d[!Dreg,Areg]
|
||||
|
||||
1110 1000 11ss sSSS:20:?????:?????:11: BFTST #1,s[!Areg,Apdi,Aipi,Immd]
|
||||
1110 1001 11ss sSSS:20:?????:?????:11: BFEXTU #1,s[!Areg,Apdi,Aipi,Immd]
|
||||
1110 1010 11ss sSSS:20:?????:?????:13: BFCHG #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
|
||||
1110 1011 11ss sSSS:20:?????:?????:11: BFEXTS #1,s[!Areg,Apdi,Aipi,Immd]
|
||||
1110 1100 11ss sSSS:20:?????:?????:13: BFCLR #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
|
||||
1110 1101 11ss sSSS:20:?????:?????:11: BFFFO #1,s[!Areg,Apdi,Aipi,Immd]
|
||||
1110 1110 11ss sSSS:20:?????:?????:13: BFSET #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
|
||||
1110 1111 11ss sSSS:20:?????:?????:13: BFINS #1,s[!Areg,Apdi,Aipi,Immd,PC8r,PC16]
|
||||
|
||||
% floating point co processor
|
||||
1111 0010 00ss sSSS:30:?????:?????:11: FPP #1,s
|
||||
1111 0010 01ss sSSS:30:?????:?????:11: FDBcc #1,s[Areg-Dreg]
|
||||
1111 0010 01ss sSSS:30:?????:?????:11: FScc #1,s[!Areg,Immd,PC8r,PC16]
|
||||
1111 0010 0111 1010:30:?????:?????:10: FTRAPcc #1
|
||||
1111 0010 0111 1011:30:?????:?????:10: FTRAPcc #2
|
||||
1111 0010 0111 1100:30:?????:?????:00: FTRAPcc
|
||||
1111 0010 10KK KKKK:30:?????:?????:11: FBcc #K,#1
|
||||
1111 0010 11KK KKKK:30:?????:?????:11: FBcc #K,#2
|
||||
1111 0011 00ss sSSS:32:?????:?????:20: FSAVE s[!Dreg,Areg,Aipi,Immd,PC8r,PC16]
|
||||
1111 0011 01ss sSSS:32:?????:?????:10: FRESTORE s[!Dreg,Areg,Apdi,Immd]
|
||||
|
||||
1111 0101 iiii iSSS:40:?????:?????:11: MMUOP #i,s
|
||||
|
||||
% 68040 instructions
|
||||
1111 0100 pp00 1rrr:42:-----:-----:02: CINVL #p,Ar
|
||||
1111 0100 pp01 0rrr:42:-----:-----:02: CINVP #p,Ar
|
||||
1111 0100 pp01 1rrr:42:-----:-----:00: CINVA #p
|
||||
1111 0100 pp10 1rrr:42:-----:-----:02: CPUSHL #p,Ar
|
||||
1111 0100 pp11 0rrr:42:-----:-----:02: CPUSHP #p,Ar
|
||||
1111 0100 pp11 1rrr:42:-----:-----:00: CPUSHA #p
|
||||
% destination register number is encoded in the following word
|
||||
1111 0110 0010 0rrr:40:-----:-----:12: MOVE16 ArP,AxP
|
||||
1111 0110 00ss sSSS:40:-----:-----:12: MOVE16 s[Dreg-Aipi],L
|
||||
1111 0110 00dd dDDD:40:-----:-----:12: MOVE16 L,d[Areg-Aipi]
|
||||
1111 0110 00ss sSSS:40:-----:-----:12: MOVE16 s[Aind],L
|
||||
1111 0110 00dd dDDD:40:-----:-----:12: MOVE16 L,d[Aipi-Aind]
|
Loading…
Reference in New Issue