MCUME/MCUME_pico2/picocastaway/famec.cpp

2062 wiersze
53 KiB
C++

/****************************************************************************/
/* FAME (Fast and Accurate Motorola 68000 Emulation Library) */
/* Emulador de 68000 en C */
/* Autor: Oscar Orallo Pelaez */
/* Fecha de comienzo: 03-10-2006 */
/* Ultima actualizacion: 28-10-2009 */
/* Based on the excellent FAMEC emulator by Stephane Dallongueville */
/****************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "dcastaway.h"
#include "mem.h"
#ifdef _MSC_VER
/* Ignore unary minus applied to unsigned type */
#pragma warning( disable : 4146 )
#endif
/* Options */
/*
Do not use the following lines to enable/disable features
They are here as a reference only
Define them in your project as you need instead
*/
/* #define FAME_INLINE_LOOP */
/* #define FAME_IRQ_CLOCKING */
/* #define FAME_CHECK_BRANCHES */
/* #define FAME_DIRECT_MAPPING */
/* #define FAME_EXTRA_INLINE */
/* #define FAME_EMULATE_TRACE */
/* #define FAME_BYPASS_TAS_WRITEBACK */
/* #define FAME_ACCURATE_TIMING */
/* #define FAME_GLOBAL_CONTEXT */
/* #define FAME_DEBUG */
/* #define FAME_GOTOS */
/* #define FAME_BIG_ENDIAN */
#define FAME_SECURE_ALL_BANKS
#ifndef FAME_ADDR_BITS
#define FAME_ADDR_BITS 24
#endif
#ifndef FAME_PC_BITS
#define FAME_PC_BITS 24
#endif
#ifndef FAME_FETCHBITS
#define FAME_FETCHBITS 12
#endif
#ifndef FAME_DATABITS
#define FAME_DATABITS 12
#endif
#ifndef FAME_PREFIX
#define FAME_PREFIX m68k
#endif
/* Options */
#define CONCAT(P1,P2) P1##P2
#define FAME_FNT(P,F) CONCAT(P,_##F)
#define FAME_DT(P,D) CONCAT(P,D)
#define FAME_API(F) FAME_FNT(FAME_PREFIX,F)
#define FAME_CONTEXT FAME_DT(FAME_PREFIX,context)
#ifndef INLINE
#define INLINE
#endif
#ifndef FAME_EXTRA_INLINE
#define EXTRA_INLINE
#else
#define EXTRA_INLINE INLINE
#endif
/* Return codes */
#define M68K_OK 0
#define M68K_RUNNING 1
#define M68K_NO_SUP_ADDR_SPACE 2
#define M68K_INV_REG -1
/* Hardware interrupt state */
#define M68K_IRQ_LEVEL_ERROR -1
#define M68K_IRQ_INV_PARAMS -2
/* Defines to specify hardware interrupt type */
#define M68K_AUTOVECTORED_IRQ -1
#define M68K_SPURIOUS_IRQ -2
/* Defines to specify address space */
#define M68K_SUP_ADDR_SPACE 0
#define M68K_USER_ADDR_SPACE 2
#define M68K_PROG_ADDR_SPACE 0
#define M68K_DATA_ADDR_SPACE 1
/******************************/
/* 68K core types definitions */
/******************************/
#if FAME_ADDR_BITS < 32
#define M68K_ADDR_MASK ((1 << FAME_ADDR_BITS)-1)
#else
#define M68K_ADDR_MASK 0xFFFFFFFF
#endif
#define M68K_FETCHSFT (FAME_ADDR_BITS - FAME_FETCHBITS)
#define M68K_FETCHBANK (1 << FAME_FETCHBITS)
#define M68K_FETCHMASK (M68K_FETCHBANK - 1)
#define M68K_DATASFT (FAME_ADDR_BITS - FAME_DATABITS)
#define M68K_DATABANK (1 << FAME_DATABITS)
#define M68K_DATAMASK (M68K_DATABANK - 1)
#define M68K_SR_C_SFT 8
#define M68K_SR_V_SFT 7
#define M68K_SR_Z_SFT 0
#define M68K_SR_N_SFT 7
#define M68K_SR_X_SFT 8
#define M68K_SR_S_SFT 13
#define M68K_SR_T_SFT 15
#define M68K_SR_C (1 << M68K_SR_C_SFT)
#define M68K_SR_V (1 << M68K_SR_V_SFT)
#define M68K_SR_Z 0
#define M68K_SR_N (1 << M68K_SR_N_SFT)
#define M68K_SR_X (1 << M68K_SR_X_SFT)
#define M68K_SR_S (1 << M68K_SR_S_SFT)
#define M68K_SR_T (1 << M68K_SR_T_SFT)
#define M68K_CCR_MASK 0x1F
#ifdef FAME_IRQ_CLOCKING
#define INT_TIMING 44
#else
#define INT_TIMING 0
#endif
#ifdef FAME_EMULATE_TRACE
#define M68K_SR_MASK (M68K_SR_T | M68K_SR_S | 0x0700 | M68K_CCR_MASK)
#else
#define M68K_SR_MASK (M68K_SR_S | 0x0700 | M68K_CCR_MASK)
#endif
/* exception defines taken from musashi core */
#define M68K_RESET_EX 1
#define M68K_BUS_ERROR_EX 2
#define M68K_ADDRESS_ERROR_EX 3
#define M68K_ILLEGAL_INSTRUCTION_EX 4
#define M68K_ZERO_DIVIDE_EX 5
#define M68K_CHK_EX 6
#define M68K_TRAPV_EX 7
#define M68K_PRIVILEGE_VIOLATION_EX 8
#define M68K_TRACE_EX 9
#define M68K_1010_EX 10
#define M68K_1111_EX 11
#define M68K_FORMAT_ERROR_EX 14
#define M68K_UNINITIALIZED_INTERRUPT_EX 15
#define M68K_SPURIOUS_INTERRUPT_EX 24
#define M68K_INTERRUPT_AUTOVECTOR_EX 24
#define M68K_TRAP_BASE_EX 32
#define M68K_INT_ACK_AUTOVECTOR -1
/*#define M68K_RUNNING 0x01 */
#define M68K_HALTED 0x80
#define M68K_WAITING 0x04
#define M68K_DISABLE 0x20
/* #define M68K_FAULTED 0x40 */
#define M68K_EMULATE_GROUP_0 0x02
#define M68K_EMULATE_TRACE 0x08
#define M68K_DO_TRACE 0x10
#ifdef FAME_LITTLE_ENDIAN
#ifdef FAME_BIG_ENDIAN
#undef FAME_BIG_ENDIAN
#endif
#else
#ifndef FAME_BIG_ENDIAN
#if defined(__hppa__) || \
defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \
(defined(__MIPS__) && defined(__MISPEB__)) || \
defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \
defined(__sparc__)
#define FAME_BIG_ENDIAN
#else
#define FAME_LITTLE_ENDIAN
#endif
#endif
#endif
/*
internals core macros
*/
#define DREG(X) (FAME_CONTEXT.dreg[(X)].D)
#define DREGu32(X) (FAME_CONTEXT.dreg[(X)].D)
#define DREGs32(X) (FAME_CONTEXT.dreg[(X)].SD)
#define DREGu16(X) (FAME_CONTEXT.dreg[(X)].w.W)
#define DREGs16(X) (FAME_CONTEXT.dreg[(X)].sw.SW)
#define DREGu8(X) (FAME_CONTEXT.dreg[(X)].b.B)
#define DREGs8(X) (FAME_CONTEXT.dreg[(X)].sb.SB)
#define AREG(X) (FAME_CONTEXT.areg[(X)].D)
#define AREGu32(X) (FAME_CONTEXT.areg[(X)].D)
#define AREGs32(X) (FAME_CONTEXT.areg[(X)].SD)
#define AREGu16(X) (FAME_CONTEXT.areg[(X)].w.W)
#define AREGs16(X) (FAME_CONTEXT.areg[(X)].sw.SW)
#define ASP (FAME_CONTEXT.asp)
#define LSL(A, C) ((A) << (C))
#define LSR(A, C) ((A) >> (C))
#define LSR_32(A, C) ((C) < 32 ? (A) >> (C) : 0)
#define LSL_32(A, C) ((C) < 32 ? (A) << (C) : 0)
#define ROL_8(A, C) (LSL(A, C) | LSR(A, 8-(C)))
#define ROL_9(A, C) (LSL(A, C) | LSR(A, 9-(C)))
#define ROL_16(A, C) (LSL(A, C) | LSR(A, 16-(C)))
#define ROL_17(A, C) (LSL(A, C) | LSR(A, 17-(C)))
#define ROL_32(A, C) (LSL_32(A, C) | LSR_32(A, 32-(C)))
#define ROL_33(A, C) (LSL_32(A, C) | LSR_32(A, 33-(C)))
#define ROR_8(A, C) (LSR(A, C) | LSL(A, 8-(C)))
#define ROR_9(A, C) (LSR(A, C) | LSL(A, 9-(C)))
#define ROR_16(A, C) (LSR(A, C) | LSL(A, 16-(C)))
#define ROR_17(A, C) (LSR(A, C) | LSL(A, 17-(C)))
#define ROR_32(A, C) (LSR_32(A, C) | LSL_32(A, 32-(C)))
#define ROR_33(A, C) (LSR_32(A, C) | LSL_32(A, 33-(C)))
/* Flag setup */
#define SET_FLAGS_Z_VC0 \
flag_C = 0; \
flag_V = 0; \
flag_NotZ = res;
#define SET_FLAGS_NZ_VC0 \
SET_FLAGS_Z_VC0 \
flag_N = res;
#define SET_FLAGS_DIV_ZERO \
flag_V = 0; \
flag_C = 0;
#define SET_FLAGS_DIV_OVERFLOW \
flag_C = 0; \
flag_V = M68K_SR_V; \
flag_N = M68K_SR_N; \
/* Z flag is undefined on division overflow */ \
/* but is set here to match FAME versions */ \
flag_NotZ = 1; \
#ifdef FAME_DEBUG
#define DEBUG_OPCODE(OP) printf(":Opcode %.4X\n",Opcode);
#else
#define DEBUG_OPCODE(OP)
#endif
#ifdef FAME_GOTOS
#define NEXT \
FETCH_WORD(Opcode); \
DEBUG_OPCODE(Opcode) \
goto *JumpTable[Opcode];
#ifdef FAME_INLINE_LOOP
#define RET(A) \
io_cycle_counter -= (A); \
if (io_cycle_counter <= 0) goto famec_Exec_End; \
NEXT
#else
#define RET(A) \
io_cycle_counter -= (A); \
if (io_cycle_counter <= 0) goto famec_Exec_End; \
goto famec_Exec;
#endif
#define RET_STOP(C) \
io_cycle_counter -= (C); \
if (io_cycle_counter > 0) io_cycle_counter = 0; \
goto famec_Exec_End;
#else
//printf("%8x",PC);
//printf("=>%8x\n",Opcode);
#define NEXT \
do { \
FETCH_WORD(Opcode); \
DEBUG_OPCODE(Opcode) \
JumpTable[Opcode](); \
} while(io_cycle_counter>0);
#ifdef FAME_INLINE_LOOP
#define RET(A) \
io_cycle_counter -= (A); \
if (io_cycle_counter > 0) \
{ \
FETCH_WORD(Opcode); \
DEBUG_OPCODE(Opcode) \
JumpTable[Opcode](); \
} \
return;
#else
#define RET(A) \
io_cycle_counter -= (A); \
return;
#endif
#define RET_STOP(C) \
io_cycle_counter -= (C); \
if (io_cycle_counter > 0) io_cycle_counter = 0; \
return;
#endif
#define M68K_PPL (FAME_CONTEXT.sr >> 8) & 7
#if FAME_PC_BITS == 32
#define UNBASED_PC PC
#define READ_BASED_PC BasePC[(PC & M68K_ADDR_MASK) >> 1]
#define READ_BASED_PC_IDX(IDX) BasePC[((PC & M68K_ADDR_MASK) >> 1) + IDX]
#define SET_PC(A) \
BasePC = (u16 *)Fetch[(((A) & M68K_ADDR_MASK) >> M68K_FETCHSFT) & M68K_FETCHMASK]; \
PC = A;
#define INC_PC(I) (PC += I)
#else
#define UNBASED_PC ((u32)PC - BasePC)
#ifdef ALL_IN_RAM
#define READ_BASED_PC (*PC)
#define READ_BASED_PC_IDX(IDX) (PC[IDX])
#else
#define READ_BASED_PC ((u32)PC<RAM2BASE?ReadW((u32)PC):*PC)
#define READ_BASED_PC_IDX(IDX) ((u32)(&PC[IDX])<RAM2BASE?ReadW((u32)(&PC[IDX])):PC[IDX])
#endif
#define SET_PC(A) \
BasePC = Fetch[((A) >> M68K_FETCHSFT) & M68K_FETCHMASK]; \
PC = (u16*)(((A) & M68K_ADDR_MASK) + BasePC);
#define INC_PC(I) (PC += (I) >> 1)
#endif
#define READ_BYTE_F(A, D) \
D = Read_Byte(A) & 0xFF;
#define READ_WORD_F(A, D) \
D = Read_Word(A) & 0xFFFF;
#define READ_LONG_F(A, D) \
D = Read_Word((A)) << 16; \
D |= Read_Word((A) + 2) & 0xFFFF;
#define READ_LONG_DEC_F(A, D) \
D = Read_Word((A) + 2) & 0xFFFF; \
D |= Read_Word((A)) << 16;
#define READSX_LONG_F(A, D) \
D = Read_Word((A)) << 16; \
D |= Read_Word((A) + 2) & 0xFFFF;
#define WRITE_LONG_F(A, D) \
Write_Word((A), (D) >> 16); \
Write_Word((A) + 2, (D) & 0xFFFF);
#define WRITE_LONG_DEC_F(A, D) \
Write_Word((A) + 2, (D) & 0xFFFF); \
Write_Word((A), (D) >> 16);
#define FETCH_LONG(A) \
(A) = READ_BASED_PC_IDX(1) | (READ_BASED_PC_IDX(0) << 16); \
INC_PC(4);
#define PUSH_32_F(D) \
AREG(7) -= 4; \
Write_Word(AREG(7), (D) >> 16); \
Write_Word(AREG(7) + 2, (D) & 0xFFFF);
#define POP_32_F(D) \
D = Read_Word(AREG(7)) << 16; \
D |= Read_Word(AREG(7) + 2) & 0xFFFF; \
AREG(7) += 4;
#define GET_SWORD \
((s16)READ_BASED_PC)
#define FETCH_BYTE(A) \
(A) = READ_BASED_PC & 0xFF; INC_PC(2);
#define FETCH_SBYTE(A) \
(A) = (s8)((READ_BASED_PC) & 0xFF); INC_PC(2);
#define FETCH_WORD(A) \
(A) = READ_BASED_PC; INC_PC(2);
#define FETCH_SWORD(A) \
(A) = (s16)READ_BASED_PC; INC_PC(2);
#define DECODE_EXT_WORD \
{ \
u32 ext = READ_BASED_PC; INC_PC(2); \
adr += (s8)(ext); \
if (ext & 0x0800) adr += DREGs32(ext >> 12); \
else adr += DREGs16(ext >> 12); \
}
#define READSX_BYTE_F(A, D) \
D = (s8)Read_Byte(A);
#define READSX_WORD_F(A, D) \
D = (s16)Read_Word(A);
#define WRITE_BYTE_F(A, D) \
Write_Byte(A, D);
#define WRITE_WORD_F(A, D) \
Write_Word(A, D);
#define PUSH_16_F(D) \
Write_Word(AREG(7) -= 2, D); \
#define POP_16_F(D) \
D = (u16)Read_Word(AREG(7)); \
AREG(7) += 2;
#define GET_CCR \
(((flag_C >> (M68K_SR_C_SFT - 0)) & 1) | \
((flag_V >> (M68K_SR_V_SFT - 1)) & 2) | \
(((!flag_NotZ) & 1) << 2) | \
((flag_N >> (M68K_SR_N_SFT - 3)) & 8) | \
((flag_X >> (M68K_SR_X_SFT - 4)) & 0x10))
#ifdef FAME_EMULATE_TRACE
#define GET_SR \
((flag_S << 0) | \
(flag_I << 8) | \
(flag_T ) | \
GET_CCR)
#else
#define GET_SR \
((flag_S << 0) | \
(flag_I << 8) | \
GET_CCR)
#endif
#define SET_CCR(A) \
flag_C = (A) << (M68K_SR_C_SFT - 0); \
flag_V = (A) << (M68K_SR_V_SFT - 1); \
flag_NotZ = ~(A) & 4; \
flag_N = (A) << (M68K_SR_N_SFT - 3); \
flag_X = (A) << (M68K_SR_X_SFT - 4);
#ifdef FAME_EMULATE_TRACE
#define SET_SR(A) \
SET_CCR(A) \
flag_T = (A) & M68K_SR_T; \
flag_S = (A) & M68K_SR_S; \
flag_I = ((A) >> 8) & 7;
#else
#define SET_SR(A) \
SET_CCR(A) \
flag_S = (A) & M68K_SR_S; \
flag_I = ((A) >> 8) & 7;
#endif
#define CHECK_INT_TO_JUMP(CLK) \
if (interrupt_chk()) \
{ \
/* \
si los ciclos restantes son menores o iguales \
que los de la instruccion en curso, \
no proceder a fijar el contador, pues cycles_needed \
sera negativo, haciendo que el calculo de ciclos \
ejecutados al final de emulate sea incorrecto \
*/ \
if(io_cycle_counter > (CLK)) \
{ \
cycles_needed=io_cycle_counter-(CLK); \
io_cycle_counter=0; \
} \
}
#define BANKEND_TAG ((u32)-1)
#define SETUP_FETCH_BANK(FNT, BANK) \
{ \
u32 i = 0; \
while (BANK[i].low_addr != BANKEND_TAG) \
{ \
FNT(BANK[i].low_addr, BANK[i].high_addr, BANK[i].offset); \
i++; \
} \
}
#define SETUP_DATA_BANK(FNT, BANK) \
{ \
u32 i = 0; \
while (BANK[i].low_addr != BANKEND_TAG) \
{ \
FNT(BANK[i].low_addr, BANK[i].high_addr, BANK[i].mem_handler, BANK[i].data); \
i++; \
} \
}
#ifdef FAME_CHECK_BRANCHES
#ifdef FAME_GOTOS
#define CHECK_BRANCH_EXCEPTION_GOTO_END goto famec_Exec_End;
#else
#define CHECK_BRANCH_EXCEPTION_GOTO_END io_cycle_counter=0; return;
#endif
#define CHECK_BRANCH_EXCEPTION(_PC_) \
if ((_PC_)&1) \
{ \
u32 pr_PC=UNBASED_PC; \
FAME_CONTEXT.execinfo |= M68K_EMULATE_GROUP_0; \
execute_exception_group_0(M68K_ADDRESS_ERROR_EX, 0, pr_PC, 0x12 ); \
CHECK_BRANCH_EXCEPTION_GOTO_END \
}
#else
#define CHECK_BRANCH_EXCEPTION(_PC_)
#endif
typedef unsigned char u8;
typedef signed char s8;
typedef unsigned short u16;
typedef signed short s16;
typedef unsigned int u32;
typedef signed int s32;
#ifdef FAME_EMULATE_TRACE
static u32 flag_T;
#endif
static u32 flag_C;
static u32 flag_V;
static u32 flag_NotZ;
static u32 flag_N;
static u32 flag_X; /* 16 bytes aligned */
static u32 flag_S;
static u32 flag_I;
typedef union
{
#ifndef FAME_BIG_ENDIAN
struct
{
u8 B,B1,B2,B3;
} b;
struct
{
s8 SB,SB1,SB2,SB3;
} sb;
struct
{
u16 W,W1;
} w;
struct
{
s16 SW,SW1;
} sw;
#else
struct
{
u8 B3,B2,B1,B;
} b;
struct
{
s8 SB3,SB2,SB1,SB;
} sb;
struct
{
u16 W1,W;
} w;
struct
{
s16 SW1,SW;
} sw;
#endif
u32 D;
s32 SD;
} famec_union32;
/* M68K registers */
typedef enum
{
M68K_REG_D0=0,
M68K_REG_D1,
M68K_REG_D2,
M68K_REG_D3,
M68K_REG_D4,
M68K_REG_D5,
M68K_REG_D6,
M68K_REG_D7,
M68K_REG_A0,
M68K_REG_A1,
M68K_REG_A2,
M68K_REG_A3,
M68K_REG_A4,
M68K_REG_A5,
M68K_REG_A6,
M68K_REG_A7,
M68K_REG_ASP,
M68K_REG_PC,
M68K_REG_SR
} m68k_register;
/* The memory blocks must be in native (Motorola) format */
typedef struct
{
u32 low_addr;
u32 high_addr;
u32 offset;
} M68K_PROGRAM;
/* The memory blocks must be in native (Motorola) format */
typedef struct
{
u32 low_addr;
u32 high_addr;
void *mem_handler;
void *data;
} M68K_DATA;
/* M68K CPU CONTEXT */
typedef struct
{
M68K_PROGRAM *fetch;
M68K_DATA *read_byte;
M68K_DATA *read_word;
M68K_DATA *write_byte;
M68K_DATA *write_word;
M68K_PROGRAM *sv_fetch;
M68K_DATA *sv_read_byte;
M68K_DATA *sv_read_word;
M68K_DATA *sv_write_byte;
M68K_DATA *sv_write_word;
M68K_PROGRAM *user_fetch;
M68K_DATA *user_read_byte;
M68K_DATA *user_read_word;
M68K_DATA *user_write_byte;
M68K_DATA *user_write_word;
void (*reset_handler)(void);
void (*iack_handler)(u32 level);
u32 *icust_handler;
famec_union32 dreg[8];
famec_union32 areg[8];
u32 asp;
u32 pc;
u32 cycles_counter;
u8 interrupts[8];
u16 sr;
u16 execinfo;
} M68K_CONTEXT;
/* Custom function handler */
typedef void (*icust_handler_func)(u32 vector);
/*
global variable
*/
/* Main CPU context */
#ifdef FAME_GLOBAL_CONTEXT
M68K_CONTEXT FAME_CONTEXT;
s32 io_cycle_counter;
#else
static M68K_CONTEXT FAME_CONTEXT;
static s32 io_cycle_counter;
#endif
static s32 cycles_needed=0;
static s32 cycles_to_do=0;
#if FAME_PC_BITS == 32
static u32 PC;
static u16* BasePC;
#else
static u16 *PC;
static u32 BasePC;
#endif
static u32 Fetch[M68K_FETCHBANK];
/* Lookup IRQ level to attend */
/* Indexed by interrupts[0] */
static const u8 irq_level_lookup[256] =
{
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7
};
typedef u8 (*mem8_handler_func)(s32 address);
typedef u16 (*mem16_handler_func)(s32 address);
typedef u32 (*mem32_handler_func)(s32 address);
typedef void (*memw_handler_func)(s32 address, s32 data);
#ifdef FAME_SECURE_ALL_BANKS
static unsigned char dummy_fetch[(1<<M68K_FETCHSFT)];
#endif
#ifdef FAME_DIRECT_MAPPING
typedef struct
{
void *mem_handler;
void *data;
} M68K_INTERNAL_DATA;
#ifdef FAME_SECURE_ALL_BANKS
static void dummy_write(unsigned adr, unsigned btr){}
static int dummy_read(unsigned adr)
{
return -1;
}
#endif
static M68K_INTERNAL_DATA DataRB[M68K_DATABANK];
static M68K_INTERNAL_DATA DataRW[M68K_DATABANK];
static M68K_INTERNAL_DATA DataWB[M68K_DATABANK];
static M68K_INTERNAL_DATA DataWW[M68K_DATABANK];
#else
#define DataRB FAME_CONTEXT.read_byte
#define DataRW FAME_CONTEXT.read_word
#define DataWB FAME_CONTEXT.write_byte
#define DataWW FAME_CONTEXT.write_word
#endif
/* Custom function handler */
typedef void (*opcode_func)(void);
static u32 initialised = 0;
/* exception cycle table (taken from musashi core) */
static const s32 exception_cycle_table[256] =
{
4, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
50, /* 2: Bus Error */
50, /* 3: Address Error */
34, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero */
40, /* 6: CHK */
34, /* 7: TRAPV */
34, /* 8: Privilege Violation */
34, /* 9: Trace */
4, /* 10: */
4, /* 11: */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation */
4, /* 14: Format Error */
44, /* 15: Uninitialized Interrupt */
4, /* 16: RESERVED */
4, /* 17: RESERVED */
4, /* 18: RESERVED */
4, /* 19: RESERVED */
4, /* 20: RESERVED */
4, /* 21: RESERVED */
4, /* 22: RESERVED */
4, /* 23: RESERVED */
INT_TIMING, /* 24: Spurious Interrupt */
INT_TIMING, /* 25: Level 1 Interrupt Autovector */
INT_TIMING, /* 26: Level 2 Interrupt Autovector */
INT_TIMING, /* 27: Level 3 Interrupt Autovector */
INT_TIMING, /* 28: Level 4 Interrupt Autovector */
INT_TIMING, /* 29: Level 5 Interrupt Autovector */
INT_TIMING, /* 30: Level 6 Interrupt Autovector */
INT_TIMING, /* 31: Level 7 Interrupt Autovector */
34, /* 32: TRAP #0 */
34, /* 33: TRAP #1 */
34, /* 34: TRAP #2 */
34, /* 35: TRAP #3 */
34, /* 36: TRAP #4 */
34, /* 37: TRAP #5 */
34, /* 38: TRAP #6 */
34, /* 39: TRAP #7 */
34, /* 40: TRAP #8 */
34, /* 41: TRAP #9 */
34, /* 42: TRAP #10 */
34, /* 43: TRAP #11 */
34, /* 44: TRAP #12 */
34, /* 45: TRAP #13 */
34, /* 46: TRAP #14 */
34, /* 47: TRAP #15 */
4, /* 48: FP Branch or Set on Unknown Condition */
4, /* 49: FP Inexact Result */
4, /* 50: FP Divide by Zero */
4, /* 51: FP Underflow */
4, /* 52: FP Operand Error */
4, /* 53: FP Overflow */
4, /* 54: FP Signaling NAN */
4, /* 55: FP Unimplemented Data Type */
4, /* 56: MMU Configuration Error */
4, /* 57: MMU Illegal Operation Error */
4, /* 58: MMU Access Level Violation Error */
4, /* 59: RESERVED */
4, /* 60: RESERVED */
4, /* 61: RESERVED */
4, /* 62: RESERVED */
4, /* 63: RESERVED */
/* 64-255: User Defined */
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4
};
/*
helper functions
*/
static void famec_SetDummyFetch(void)
{
#ifdef FAME_SECURE_ALL_BANKS
u32 i,j;
i = (0 >> M68K_FETCHSFT) & M68K_FETCHMASK;
j = (0xFFFFFFFF >> M68K_FETCHSFT) & M68K_FETCHMASK;
while (i <= j)
{
Fetch[i] = ((u32)&dummy_fetch)-(i*(1<<M68K_FETCHSFT));
i++;
}
#endif
}
static void famec_SetFetch(u32 low_adr, u32 high_adr, u32 fetch_adr)
{
u32 i, j;
i = (low_adr >> M68K_FETCHSFT) & M68K_FETCHMASK;
j = (high_adr >> M68K_FETCHSFT) & M68K_FETCHMASK;
while (i <= j)
Fetch[i++] = fetch_adr;
}
#ifdef FAME_DIRECT_MAPPING
static void famec_SetDummyData(void)
{
#ifdef FAME_SECURE_ALL_BANKS
u32 i, j;
i = (0 >> M68K_DATASFT) & M68K_DATAMASK;
j = (0xFFFFFFFF >> M68K_DATASFT) & M68K_DATAMASK;
while (i <= j)
{
DataRB[i].mem_handler = DataRW[i].mem_handler = (void *)&dummy_read;
DataWB[i].mem_handler = DataWW[i].mem_handler = (void *)&dummy_write;
DataRB[i].data = DataRW[i].data = DataWB[i].data = DataWW[i].data = NULL;
i++;
}
#endif
}
static void famec_SetDataRB(u32 low_adr, u32 high_adr, void *mh, void *dt)
{
u32 i, j;
i = (low_adr >> M68K_DATASFT) & M68K_DATAMASK;
j = (high_adr >> M68K_DATASFT) & M68K_DATAMASK;
while (i <= j)
{
DataRB[i].mem_handler = mh;
DataRB[i++].data = dt;
}
}
static void famec_SetDataRW(u32 low_adr, u32 high_adr, void *mh, void *dt)
{
u32 i, j;
i = (low_adr >> M68K_DATASFT) & M68K_DATAMASK;
j = (high_adr >> M68K_DATASFT) & M68K_DATAMASK;
while (i <= j)
{
DataRW[i].mem_handler = mh;
DataRW[i++].data = dt;
}
}
static void famec_SetDataWB(u32 low_adr, u32 high_adr, void *mh, void *dt)
{
u32 i, j;
i = (low_adr >> M68K_DATASFT) & M68K_DATAMASK;
j = (high_adr >> M68K_DATASFT) & M68K_DATAMASK;
while (i <= j)
{
DataWB[i].mem_handler = mh;
DataWB[i++].data = dt;
}
}
static void famec_SetDataWW(u32 low_adr, u32 high_adr, void *mh, void *dt)
{
u32 i, j;
i = (low_adr >> M68K_DATASFT) & M68K_DATAMASK;
j = (high_adr >> M68K_DATASFT) & M68K_DATAMASK;
while (i <= j)
{
DataWW[i].mem_handler = mh;
DataWW[i++].data = dt;
}
}
#endif
static void famec_SetBanks(void)
{
famec_SetDummyFetch();
SETUP_FETCH_BANK(famec_SetFetch, FAME_CONTEXT.fetch)
#ifdef FAME_DIRECT_MAPPING
famec_SetDummyData();
SETUP_DATA_BANK(famec_SetDataRB, FAME_CONTEXT.read_byte)
SETUP_DATA_BANK(famec_SetDataRW, FAME_CONTEXT.read_word)
SETUP_DATA_BANK(famec_SetDataWB, FAME_CONTEXT.write_byte)
SETUP_DATA_BANK(famec_SetDataWW, FAME_CONTEXT.write_word)
#endif
}
#ifdef FAME_ACCURATE_TIMING
/*
Functions used to compute accurate opcode timing (MUL/DIV)
*/
static EXTRA_INLINE u8 bitset_count(u32 data)
{
unsigned int const MASK1 = 0x55555555;
unsigned int const MASK2 = 0x33333333;
unsigned int const MASK4 = 0x0f0f0f0f;
unsigned int const MASK6 = 0x0000003f;
unsigned int const w = (data & MASK1) + ((data >> 1) & MASK1);
unsigned int const x = (w & MASK2) + ((w >> 2) & MASK2);
unsigned int const y = ((x + (x >> 4)) & MASK4);
unsigned int const z = (y + (y >> 8));
unsigned int const c = (z + (z >> 16)) & MASK6;
return c;
}
/*
DIVU
Unsigned division
*/
static u32 getDivu68kCycles(u32 dividend, u16 divisor)
{
u32 mcycles;
u32 hdivisor;
int i;
if ( (u16) divisor == 0)
return 0;
/* Overflow */
if ( (dividend >> 16) >= divisor)
return (mcycles = 5) * 2;
mcycles = 38;
hdivisor = ((u32) divisor) << 16;
for ( i = 0; i < 15; i++)
{
u32 temp;
temp = dividend;
dividend <<= 1;
/* If carry from shift */
if ( (int) temp < 0)
{
dividend -= hdivisor;
}
else
{
mcycles += 2;
if ( dividend >= hdivisor)
{
dividend -= hdivisor;
mcycles--;
}
}
}
return mcycles * 2;
}
/*
DIVS
Signed division
*/
static u32 getDivs68kCycles(s32 dividend, s16 divisor)
{
u32 mcycles;
u32 aquot;
int i;
if ( (s16) divisor == 0)
return 0;
mcycles = 6;
if ( dividend < 0)
mcycles++;
/* Check for absolute overflow */
if ( ((u32) abs( dividend) >> 16) >= (u16) abs( divisor))
{
return (mcycles + 2) * 2;
}
/* Absolute quotient */
aquot = (u32) abs( dividend) / (u16) abs( divisor);
mcycles += 55;
if ( divisor >= 0)
{
if ( dividend >= 0)
mcycles--;
else
mcycles++;
}
/* Count 15 msbits in absolute of quotient */
for ( i = 0; i < 15; i++)
{
if ( (s16) aquot >= 0)
mcycles++;
aquot <<= 1;
}
return mcycles * 2;
}
#endif
/*
Read / Write functions
*/
static EXTRA_INLINE u32 Read_Byte(u32 addr)
{
u32 i=0;
s32 val;
addr&=M68K_ADDR_MASK;
#ifdef FAME_DEBUG
printf("Reading byte from addr = 0x%08X\n",addr);
#endif
#ifndef FAME_DIRECT_MAPPING
while ( ((FAME_CONTEXT.read_byte[i].low_addr > addr) || (FAME_CONTEXT.read_byte[i].high_addr < addr)) && (FAME_CONTEXT.read_byte[i].low_addr != BANKEND_TAG) )
i++;
if (FAME_CONTEXT.read_byte[i].low_addr == BANKEND_TAG)
return (u32)-1;
#else
i=addr>>M68K_DATASFT;
#endif
if (DataRB[i].mem_handler)
val= (*((mem8_handler_func *)&DataRB[i].mem_handler))(addr);
else
#ifndef FAME_BIG_ENDIAN
val = *((u8 *)(((u32)DataRB[i].data) + (addr^1)));
#else
val = *((u8 *)(((u32)DataRB[i].data) + (addr)));
#endif
#ifdef FAME_DEBUG
printf("Reading 0x%08X = 0x%04X...\n",addr,val);
#endif
return val;
}
static EXTRA_INLINE u32 Read_Word(u32 addr)
{
u32 i=0;
s32 val;
addr&=M68K_ADDR_MASK;
#ifdef FAME_DEBUG
printf("Reading from addr = 0x%08X\n",addr);
#endif
#ifndef FAME_DIRECT_MAPPING
while ( ((FAME_CONTEXT.read_word[i].low_addr > addr) || (FAME_CONTEXT.read_word[i].high_addr < addr)) && (FAME_CONTEXT.read_word[i].low_addr != BANKEND_TAG) )
i++;
if (FAME_CONTEXT.read_word[i].low_addr == BANKEND_TAG)
return (u32)-1;
#else
i=addr>>M68K_DATASFT;
#endif
if (DataRW[i].mem_handler)
val= (*((mem16_handler_func *)&DataRW[i].mem_handler))(addr);
else
val = *((u16 *)(((u32)DataRW[i].data) + addr));
#ifdef FAME_DEBUG
printf("Reading 0x%08X = 0x%04X...\n",addr,val);
#endif
return val;
}
static EXTRA_INLINE void Write_Byte(u32 addr, u32 data)
{
u32 i=0;
addr&=M68K_ADDR_MASK;
#ifdef FAME_DEBUG
printf("Writing byte 0x%08X = 0x%04X...\n",addr,data);
#endif
#ifndef FAME_DIRECT_MAPPING
while ( ((FAME_CONTEXT.write_byte[i].low_addr > addr) || (FAME_CONTEXT.write_byte[i].high_addr < addr)) && (FAME_CONTEXT.write_byte[i].low_addr != BANKEND_TAG) )
i++;
if (FAME_CONTEXT.write_byte[i].low_addr == BANKEND_TAG)
return;
#else
i=addr>>M68K_DATASFT;
#endif
if (DataWB[i].mem_handler != NULL)
(*((memw_handler_func *)&DataWB[i].mem_handler))(addr,data);
else
#ifndef FAME_BIG_ENDIAN
*((u8 *)(((u32)DataWB[i].data)+ (addr^1))) = data;
#else
*((u8 *)(((u32)DataWB[i].data)+ (addr))) = data;
#endif
}
static EXTRA_INLINE void Write_Word(u32 addr, u32 data)
{
u32 i=0;
addr&=M68K_ADDR_MASK;
#ifdef FAME_DEBUG
printf("Writing 0x%08X = 0x%04X...\n",addr,data);
#endif
#ifndef FAME_DIRECT_MAPPING
while ( ((FAME_CONTEXT.write_word[i].low_addr > addr) || (FAME_CONTEXT.write_word[i].high_addr < addr)) && (FAME_CONTEXT.write_word[i].low_addr != BANKEND_TAG) )
i++;
if (FAME_CONTEXT.write_word[i].low_addr == BANKEND_TAG)
return;
#else
i=addr>>M68K_DATASFT;
#endif
if (DataWW[i].mem_handler != NULL)
(*((memw_handler_func *)&DataWW[i].mem_handler))(addr,data);
else
*((u16 *)(((u32)DataWW[i].data) + addr)) = data;
}
static u32 Opcode;
/*
Chequea las interrupciones y las inicia
*/
static EXTRA_INLINE s32 interrupt_chk(void)
{
/* Bit 0 MUST be zero at all times */
assert((FAME_CONTEXT.interrupts[0] & 1) == 0);
if (FAME_CONTEXT.interrupts[0])
{
/* There is a pending IRQ */
const u8 irql = irq_level_lookup[FAME_CONTEXT.interrupts[0]];
if (irql == 7) /* NMI */
return irql;
else if (irql > flag_I)
return irql;
}
#ifdef FAME_EMULATE_TRACE
if (flag_T)
{
/*
FAME_CONTEXT.execinfo |= M68K_EMULATE_TRACE;
cycles_needed= io_cycle_counter;
io_cycle_counter=0;
*/
return -1;
}
#endif
return 0;
}
static EXTRA_INLINE void execute_exception(s32 vect)
{
/* comprobar si hay tabla funciones manejadoras */
if (FAME_CONTEXT.icust_handler && FAME_CONTEXT.icust_handler[vect])
{
FAME_CONTEXT.sr = GET_SR;
FAME_CONTEXT.pc = UNBASED_PC;
(*(icust_handler_func*)&FAME_CONTEXT.icust_handler[vect])(vect);
}
else
{
u32 newPC;
u32 oldPC;
u32 oldSR = GET_SR;
READ_LONG_F(vect * 4, newPC)
/* swap A7 and USP */
if (!flag_S)
{
u32 tmpSP;
tmpSP = ASP;
ASP = AREG(7);
AREG(7) = tmpSP;
}
oldPC = UNBASED_PC;
PUSH_32_F(oldPC)
PUSH_16_F(oldSR)
/* adjust SR */
flag_S = M68K_SR_S;
SET_PC(newPC)
}
io_cycle_counter -= exception_cycle_table[vect];
}
static EXTRA_INLINE void interrupt_attend(s32 line)
{
/* al atender la IRQ, la CPU sale del estado parado */
FAME_CONTEXT.execinfo &= ~M68K_HALTED;
/* Desactivar interrupcion */
FAME_CONTEXT.interrupts[0] &= ~(1 << ((u32)line));
execute_exception(FAME_CONTEXT.interrupts[(u32)line]);
/* comprobar si hay rutina de acknowledge */
if (FAME_CONTEXT.iack_handler != NULL)
FAME_CONTEXT.iack_handler(line);
flag_I = (u32)line;
}
/* Group 0 exceptions are not handled actually */
static EXTRA_INLINE void execute_exception_group_0(s32 vect, u16 inst_reg, s32 addr, u16 spec_info)
{
execute_exception(vect);
if (!(FAME_CONTEXT.icust_handler && FAME_CONTEXT.icust_handler[vect]))
{
PUSH_16_F(inst_reg);
PUSH_32_F(addr);
PUSH_16_F(spec_info);
}
}
/* Performs the required actions to finish the emulate call */
static EXTRA_INLINE void finish_emulate(const s32 cycles_to_add)
{
FAME_CONTEXT.sr = GET_SR;
FAME_CONTEXT.pc = UNBASED_PC;
FAME_CONTEXT.execinfo &= ~M68K_RUNNING;
/* Actualizar contador de ciclos */
FAME_CONTEXT.cycles_counter += cycles_to_add;
#ifdef FAME_DEBUG
printf("<-PC=0x%08X (%p-%p)\n",UNBASED_PC,PC,BasePC);
#endif
}
#ifndef FAME_GOTOS
#define OPCODE(N_OP) static void OP_##N_OP(void)
#define CAST_OP(N_OP) (opcode_func)&OP_##N_OP
#include "famec_opcodes.h"
#else
#define OPCODE(N_OP) OP_##N_OP:
#define CAST_OP(N_OP) (opcode_func)&&OP_##N_OP
#endif
//static opcode_func JumpTable[0x10000];
#include "jumptable.h"
/***********************/
/* core main functions */
/***********************/
/***************************************************************************/
/* m68k_init() */
/* Debe ser llamado para inicializar la tabla de saltos de instruccion */
/* No recibe parametros y no devuelve nada */
/***************************************************************************/
void FAME_API(init)(void)
{
#ifdef FAME_DEBUG
puts("Initializing FAME...");
#endif
#ifndef FAME_GOTOS
//BUILD_OPCODE_TABLE
initialised = 1;
#endif
#ifdef FAME_DEBUG
puts("FAME initialized.");
#endif
}
/******************************************************************************/
/* m68k_reset() */
/* Parametros: Ninguno */
/* Retorno: Exito de la operacion */
/* M68K_OK (0): La funcion se ha ejecutado satisfactoriamente */
/* M68K_RUNNING (1): No se puede resetear porque la CPU esta en ejecucion */
/* M68K_NO_SUP_ADDR_SPACE (2): No se puede resetear porque no hay mapa */
/* de memoria supervisor de extraccion de opcodes */
/******************************************************************************/
u32 FAME_API(reset)(void)
{
#ifndef FAME_GOTOS
assert(initialised);
#endif
/* Si la CPU esta en ejecucion, salir con M68K_RUNNING */
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
return M68K_RUNNING;
/* Si no hay mapa de memoria supervisor, salir con M68K_NO_SUP_ADDR_SPACE */
if (!FAME_CONTEXT.sv_fetch)
return M68K_NO_SUP_ADDR_SPACE;
FAME_CONTEXT.fetch = FAME_CONTEXT.sv_fetch;
FAME_CONTEXT.read_byte = FAME_CONTEXT.sv_read_byte;
FAME_CONTEXT.read_word = FAME_CONTEXT.sv_read_word;
FAME_CONTEXT.write_byte = FAME_CONTEXT.sv_write_byte;
FAME_CONTEXT.write_word = FAME_CONTEXT.sv_write_word;
/* Resetear registros */
memset(&FAME_CONTEXT.dreg[0], 0, 16*4);
/* Resetear interrupts, execinfo y ASP */
memset(&FAME_CONTEXT.interrupts[0], 0, 8);
FAME_CONTEXT.execinfo = 0;
ASP = 0;
/* Fijar registro de estado */
FAME_CONTEXT.sr = 0x2700;
/* Obtener puntero de pila inicial y PC */
READ_LONG_F(0, AREG(7));
READ_LONG_F(4, FAME_CONTEXT.pc);
#ifdef FAME_DEBUG
puts("Reset 68k done!\n");
printf("PC = 0x%08X\n",FAME_CONTEXT.pc);
#endif
return M68K_OK;
}
/******************************************************************************/
/* m68k_raise_irq(level,vector) */
/* Parametros: level = nivel de interrupcion */
/* vector = puntero a la direccion de la rutina de atencion */
/* -1 auto, -2 interrupcion espuria */
/* Retorno: Exito de la operacion */
/* 0 La interrupcion se ha habilitado satisfactoriamente */
/* -1 No se ha podido habilitar porque ya existe otra interrupcion */
/* en ese nivel. */
/* -2 No se ha podido habilitar porque el vector no es valido o */
/* el nivel es igual a 0. */
/******************************************************************************/
s32 FAME_API(raise_irq)(s32 level, s32 vector)
{
/* Enmascarar nivel de interrupcion */
level &=7;
/* Nivel de interrupcion = 0 no es valido */
if (!level) return M68K_IRQ_INV_PARAMS;
/* Comprobar si existe una interrupcion activada en ese nivel */
if (FAME_CONTEXT.interrupts[0] & (1 << level))
return M68K_IRQ_LEVEL_ERROR;
/* El vector de interrupcion no puede ser > 255 ni menor que -2 */
if ((vector > 255) || (vector < M68K_SPURIOUS_IRQ))
{
return M68K_IRQ_INV_PARAMS;
}
/* Dar de alta la interrupcion en interrupts */
FAME_CONTEXT.interrupts[0] |= (1 << level);
switch (vector)
{
case M68K_SPURIOUS_IRQ:
FAME_CONTEXT.interrupts[level] = 0x18;
break;
case M68K_AUTOVECTORED_IRQ:
FAME_CONTEXT.interrupts[level] = level + 0x18;
break;
default:
FAME_CONTEXT.interrupts[level] = vector;
break;
}
#ifdef FAME_DEBUG
printf("RAISE interrupts[%i]=0x%X\n",level,FAME_CONTEXT.interrupts[level]);
#endif
/* Testear si la CPU esta detenida (mediante STOP) */
if (FAME_CONTEXT.execinfo & M68K_HALTED)
{
/* Si la IRQ es NMI o si supera la mascara de interrupcion, */
/* salir de estado parado */
if ((level == 7) || (level > ((FAME_CONTEXT.sr >> 8) & 0x7)))
{
FAME_CONTEXT.execinfo &= ~M68K_HALTED;
}
}
return M68K_OK;
}
/******************************************************************************/
/* m68k_lower_irq(level) */
/* Parametros: Nivel de la interrupcion a retirar */
/* Retorno: Exito de la operacion */
/* 0 La interrupcion se ha retirado satisfactoriamente */
/* -1 No se ha podido retirar porque esa interrupcion */
/* no esta habilitada. */
/* -2 No se ha podido retirar porque el nivel es 0 o mayor */
/* o igual que 7 (no se puede retirar la NMI) */
/******************************************************************************/
s32 FAME_API(lower_irq)(s32 level)
{
/* Enmascarar nivel de interrupcion */
level &=7;
/* Nivel de interrupcion = 0 no es valido */
if (!level) return M68K_IRQ_INV_PARAMS;
/* La interrupcion de nivel 7 (NMI) no se puede bajar */
if (level > 6)
{
return M68K_IRQ_INV_PARAMS;
}
/* Comprobar que la interrupcion este activada */
if (FAME_CONTEXT.interrupts[0] & (1 << level))
{
/* Dar de baja la interrupcion */
FAME_CONTEXT.interrupts[0] &= ~(1 << level);
}
else
{
return M68K_IRQ_LEVEL_ERROR;
}
return M68K_OK;
}
/******************************************************************************/
/* m68k_get_context_size */
/* No recibe parametros */
/* Retorno: Tamano del contexto en bytes */
/******************************************************************************/
s32 FAME_API(get_context_size)(void)
{
return sizeof(M68K_CONTEXT);
}
/***************************************************************************/
/* m68k_get_context(address) */
/* Parametro: Direccion del contexto */
/* No retorna ningun valor */
/***************************************************************************/
void FAME_API(get_context)(void *context)
{
memcpy(context,&FAME_CONTEXT,sizeof(M68K_CONTEXT));
}
/***************************************************************************/
/* m68k_set_context(address) */
/* Parametro: Direccion del contexto */
/* No retorna ningun valor */
/***************************************************************************/
void FAME_API(set_context)(void *context)
{
memcpy(&FAME_CONTEXT,context,sizeof(M68K_CONTEXT));
famec_SetBanks();
}
/****************************************************************************/
/* m68k_get_pc() */
/* No recibe parametros */
/* Retorna 68k PC */
/****************************************************************************/
u32 FAME_API(get_pc)(void)
{
return (FAME_CONTEXT.execinfo & M68K_RUNNING) ? UNBASED_PC : FAME_CONTEXT.pc;
}
/***************************************************************************/
/* m68k_get_register(register) */
/* Parametro: Registro a obtener valor (indice) */
/* Retorno: Valor del registro requerido */
/* Observacion: En caso de que el indice no sea correcto */
/* la funcion devolvera -1 */
/***************************************************************************/
s32 FAME_API(get_register)(m68k_register reg)
{
switch (reg)
{
case M68K_REG_D0:
case M68K_REG_D1:
case M68K_REG_D2:
case M68K_REG_D3:
case M68K_REG_D4:
case M68K_REG_D5:
case M68K_REG_D6:
case M68K_REG_D7:
return DREG(reg - M68K_REG_D0);
case M68K_REG_A0:
case M68K_REG_A1:
case M68K_REG_A2:
case M68K_REG_A3:
case M68K_REG_A4:
case M68K_REG_A5:
case M68K_REG_A6:
case M68K_REG_A7:
return AREG(reg - M68K_REG_A0);
case M68K_REG_ASP:
return ASP;
case M68K_REG_PC:
return FAME_API(get_pc)();
case M68K_REG_SR:
return (FAME_CONTEXT.execinfo & M68K_RUNNING) ? GET_SR : FAME_CONTEXT.sr;
default:
return M68K_INV_REG;
}
}
/***********************************************************************/
/* m68k_set_register(register,value) */
/* Parametros: Registro (indice) y valor a asignar */
/* Retorno: Exito de la operacion */
/* 0 La operacion se ha realizado satisfactoriamente */
/* 1 El indice del registro no es valido (fuera de limites) */
/***********************************************************************/
s32 FAME_API(set_register)(m68k_register reg, u32 value)
{
switch (reg)
{
case M68K_REG_D0:
case M68K_REG_D1:
case M68K_REG_D2:
case M68K_REG_D3:
case M68K_REG_D4:
case M68K_REG_D5:
case M68K_REG_D6:
case M68K_REG_D7:
DREG(reg - M68K_REG_D0) = value;
break;
case M68K_REG_A0:
case M68K_REG_A1:
case M68K_REG_A2:
case M68K_REG_A3:
case M68K_REG_A4:
case M68K_REG_A5:
case M68K_REG_A6:
case M68K_REG_A7:
AREG(reg - M68K_REG_A0) = value;
break;
case M68K_REG_ASP:
ASP = value;
break;
case M68K_REG_PC:
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
{
SET_PC(value);
}
else
{
FAME_CONTEXT.pc = value;
}
break;
case M68K_REG_SR:
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
{
SET_SR(value);
}
else
{
FAME_CONTEXT.sr = value & 0xFFFF;
}
break;
default:
return M68K_INV_REG;
}
return M68K_OK;
}
/*********************************************************/
/* m68k_fetch(address,access_type) */
/* Lee una palabra del espacio de memoria del 68k */
/* Parametro: Direccion de la palabra y tipo de acceso */
/* Retorno: La palabra o -1 en caso de dir. no valida */
/*********************************************************/
s32 FAME_API(fetch)(u32 addr, u32 memory_space)
{
u32 i=0;
s32 val;
M68K_DATA *ds = NULL;
M68K_PROGRAM *ps = NULL;
switch (memory_space & 2)
{
case M68K_SUP_ADDR_SPACE:
if ((memory_space & 1) == M68K_PROG_ADDR_SPACE)
ps = FAME_CONTEXT.sv_fetch;
else
ds = FAME_CONTEXT.sv_read_word;
break;
case M68K_USER_ADDR_SPACE:
if ((memory_space & 1) == M68K_PROG_ADDR_SPACE)
ps = FAME_CONTEXT.user_fetch;
else
ds = FAME_CONTEXT.user_read_word;
break;
}
if (ps == NULL)
{
while ( ((ds[i].low_addr > addr) || (ds[i].high_addr < addr)) && (ds[i].low_addr != BANKEND_TAG) )
{
#ifdef FAME_DEBUG
printf("RW not found in %d region... 0x%08X - 0x%08X --> 0x%08X\n",i,ds[i].low_addr,ds[i].high_addr,addr);
#endif
i++;
}
if (ds[i].low_addr == BANKEND_TAG)
{
/* Error de BUS */
#ifdef FAME_DEBUG
printf("ERROR de BUS en region %d...\n",i);
#endif
return -1;
}
else
{
if (ds[i].mem_handler != NULL)
{
#ifdef FAME_DEBUG
puts("Handled...\n");
#endif
val= (*((mem16_handler_func *)&ds[i].mem_handler))(addr);
}
else
{
#ifdef FAME_DEBUG
printf("Ptr en region %d... addr: %p\n",i,ds[i].data);
#endif
val = *((u16 *)(((u32)ds[i].data) + addr));
#ifdef FAME_DEBUG
puts("read");
#endif
}
}
#ifdef FAME_DEBUG
printf("Reading 0x%08X = 0x%04X...\n",addr,val);
#endif
}
else
{
u32 tmp=Fetch[((addr) >> M68K_FETCHSFT) & M68K_FETCHMASK];
u16 *p= (u16*)(((addr) & M68K_ADDR_MASK) + (tmp));
if (tmp == 0)
val = ReadW(addr);
else
val = *p;
#ifdef FAME_DEBUG
printf("@%08X *%p=%04X\n",addr,p,val);
#endif
}
return val;
}
/******************************************************/
/* m68k_get_cycles_counter() */
/* Retorna el cycles_counter */
/* Parametro: Ninguno */
/* Retorno: cycles_counter */
/******************************************************/
u32 FAME_API(get_cycles_counter)(void)
{
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
return (cycles_to_do - io_cycle_counter) + FAME_CONTEXT.cycles_counter;
else
return FAME_CONTEXT.cycles_counter;
}
/******************************************************/
/* m68k_trip_cycles_counter() */
/* Retorna el cycles_counter y lo reinicializa */
/* Parametro: Ninguno */
/* Retorno: cycles_counter */
/******************************************************/
u32 FAME_API(trip_cycles_counter)(void)
{
s32 ret=FAME_CONTEXT.cycles_counter;
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
{
cycles_to_do-=io_cycle_counter;
io_cycle_counter=0;
}
io_cycle_counter=FAME_CONTEXT.cycles_counter=0;
return ret;
}
/**********************************************************/
/* m68k_control_cycles_counter(n) */
/* Retorna el cycles_counter y lo reinicializa si */
/* cycles_counter = n */
/* Parametro: ciclos = n */
/* Retorno: cycles_counter */
/**********************************************************/
u32 FAME_API(control_cycles_counter)(s32 cycles)
{
return (cycles)?FAME_API(trip_cycles_counter)():FAME_API(get_cycles_counter)();
}
/******************************************************/
/* m68k_release_timeslice() */
/* Finaliza la ejecucion del micro */
/* los ciclos sin ejecutar quedan en cycles_counter */
/* Parametro: Ninguno */
/* Retorno: Ninguno */
/******************************************************/
void FAME_API(release_timeslice)(void)
{
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
{
io_cycle_counter = 0;
}
}
/******************************************************/
/* m68k_stop_emulating() */
/* Finaliza la ejecucion del micro si esta en */
/* ejecucion. los ciclos ejecutados seran menos */
/* de lo normal reflejando asi la salida */
/* Parametro: Ninguno */
/* Retorno: Ninguno */
/******************************************************/
void FAME_API(stop_emulating)(void)
{
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
{
/*
es necesario quitar los ciclos de cycles_counter
para que no sean vistos como ejecutados al final
de emulate, ya que stop_emulating incrementa
el contador con los ejecutados realmente, no los
ciclos requeridos por la llamada a emulate
*/
FAME_CONTEXT.cycles_counter -= io_cycle_counter;
io_cycle_counter = 0;
}
}
/******************************************************/
/* m68k_add_cycles() */
/* Incrementa los ciclos de reloj a ejecutar por la */
/* CPU en las llamadas a emulate */
/* Parametro: Ninguno */
/* Retorno: Ninguno */
/******************************************************/
void FAME_API(add_cycles)(s32 cycles)
{
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
{
/*
when the CPU is running, io_cycle_counter stores the remaining cycles to be run
therefore, we have to substract in order to "increment" the clock counter
*/
io_cycle_counter -= cycles;
}
else
{
FAME_CONTEXT.cycles_counter += cycles;
}
}
/******************************************************/
/* m68k_release_cycles() */
/* Decrementa los ciclos de reloj a ejecutar por la */
/* CPU en las llamadas a emulate */
/* Parametro: Ninguno */
/* Retorno: Ninguno */
/******************************************************/
void FAME_API(release_cycles)(s32 cycles)
{
if (FAME_CONTEXT.execinfo & M68K_RUNNING)
{
/*
when the CPU is running, io_cycle_counter stores the remaining cycles to be run
therefore, we have to add in order to "decrement" the clock counter
*/
io_cycle_counter += cycles;
}
else
{
FAME_CONTEXT.cycles_counter -= cycles;
}
}
/*****************************************************************************/
/* m68k_get_cpu_state() */
/* No recibe parametros */
/* Retorna el estado de la CPU */
/*****************************************************************************/
u32 FAME_API(get_cpu_state)(void)
{
return FAME_CONTEXT.execinfo;
}
/*
main exec function
*/
/*
m68k_emulate()
Parametros: Numero de ciclos a ejecutar
Retorno: Exito de la operacion
0 La operacion se ha realizado satisfactoriamente
-1 La CPU esta detenida debido a un ERROR DE BUS DOBLE (linea)
El PC ha salido de los limites (bucle no en linea)
*/
u32 FAME_API(emulate)(s32 cycles)
{
#ifdef FAME_GOTOS
if (!initialised)
{
//BUILD_OPCODE_TABLE
initialised = 1;
}
#else
assert(initialised);
#endif
#ifdef FAME_DEBUG
printf("m68k_emulate(%d)\n",cycles);
#endif
#if 0
/* El bit M68K_FAULTED no esta actualmente en uso */
/* Comprobar si la CPU esta detenida debido a un doble error de bus */
if (FAME_CONTEXT.execinfo & M68K_FAULTED) return (u32)-1;
#endif
/* Poner la CPU en estado de ejecucion */
FAME_CONTEXT.execinfo |= M68K_RUNNING;
/* Cache SR */
SET_SR(FAME_CONTEXT.sr)
/* Cache PPL */
flag_I = M68K_PPL;
/* Fijar PC */
SET_PC(FAME_CONTEXT.pc)
#ifdef FAME_DEBUG
printf("->PC=0x%08X (%p-%p)\n",UNBASED_PC,PC,BasePC);
#endif
/* guardar ciclos de ejecucion solicitados */
io_cycle_counter = cycles_to_do = cycles;
cycles_needed = 0;
#ifdef FAME_EMULATE_TRACE
if (!(FAME_CONTEXT.execinfo & M68K_EMULATE_TRACE))
#endif
{
s32 line = interrupt_chk();
if (line > 0)
{
interrupt_attend(line);
#ifdef FAME_IRQ_CLOCKING
if(io_cycle_counter <= 0)
{
finish_emulate(cycles_to_do - io_cycle_counter);
return M68K_OK;
}
#endif
}
#ifdef FAME_EMULATE_TRACE
else if (flag_T)
{
/* al atender la excepcion de traza, la CPU sale del estado parado */
FAME_CONTEXT.execinfo &= ~M68K_HALTED;
FAME_CONTEXT.execinfo |= M68K_EMULATE_TRACE;
cycles_needed= io_cycle_counter;
io_cycle_counter=0;
}
#endif
}
/* Comprobar si la CPU esta parada */
if (FAME_CONTEXT.execinfo & M68K_HALTED)
{
/* La CPU esta detenida mediante la instruccion STOP */
/* Agregar ciclos de reloj requeridos */
finish_emulate(cycles_to_do);
return M68K_OK;
}
#ifdef FAME_GOTOS
famec_Exec:
#endif
#ifdef FAME_DEBUG
printf("Antes de NEXT... PC = 0x%08X\n",UNBASED_PC);
#endif
NEXT
#ifdef FAME_GOTOS
#include "famec_opcodes.h"
famec_Exec_End:
#endif
#ifdef FAME_EMULATE_TRACE
if (FAME_CONTEXT.execinfo & M68K_EMULATE_TRACE)
{
io_cycle_counter= cycles_needed;
cycles_needed=0;
FAME_CONTEXT.execinfo &= ~M68K_EMULATE_TRACE;
FAME_CONTEXT.execinfo |= M68K_DO_TRACE;
execute_exception(M68K_TRACE_EX);
flag_T=0;
if (io_cycle_counter > 0)
{
NEXT
}
}
else
#endif
if (cycles_needed>0)
{
s32 line=interrupt_chk();
io_cycle_counter= cycles_needed;
cycles_needed=0;
if (line>0)
{
interrupt_attend(line);
}
#ifdef FAME_EMULATE_TRACE
else
if (!(flag_T))
#endif
if (io_cycle_counter > 0)
{
NEXT
}
}
finish_emulate(cycles_to_do - io_cycle_counter);
return M68K_OK;
}