#include "../cinterface/callbacks.h"
extern int vdp_68k_irq_ack(int int_level);
#define m68ki_cpu m68k
#define MUL (7)
#ifndef BUILD_TABLES
#include "m68ki_cycles.h"
#endif
#include "m68kconf.h"
#include "m68kcpu.h"
#include "m68kops.h"
#include "shared.h"
#ifdef BUILD_TABLES
static unsigned char m68ki_cycles[0x10000];
#endif
static int irq_latency;
m68ki_cpu_core m68k;
#if M68K_EMULATE_INT_ACK == OPT_ON
static int default_int_ack_callback(int int_level)
{
CPU_INT_LEVEL = 0;
return M68K_INT_ACK_AUTOVECTOR;
}
#endif
#if M68K_EMULATE_RESET == OPT_ON
static void default_reset_instr_callback(void)
{
}
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
static int default_tas_instr_callback(void)
{
return 1;
}
#endif
#if M68K_EMULATE_FC == OPT_ON
static void default_set_fc_callback(unsigned int new_fc)
{
}
#endif
unsigned int m68k_get_reg(m68k_register_t regnum)
{
switch(regnum)
{
case M68K_REG_D0: return m68ki_cpu.dar[0];
case M68K_REG_D1: return m68ki_cpu.dar[1];
case M68K_REG_D2: return m68ki_cpu.dar[2];
case M68K_REG_D3: return m68ki_cpu.dar[3];
case M68K_REG_D4: return m68ki_cpu.dar[4];
case M68K_REG_D5: return m68ki_cpu.dar[5];
case M68K_REG_D6: return m68ki_cpu.dar[6];
case M68K_REG_D7: return m68ki_cpu.dar[7];
case M68K_REG_A0: return m68ki_cpu.dar[8];
case M68K_REG_A1: return m68ki_cpu.dar[9];
case M68K_REG_A2: return m68ki_cpu.dar[10];
case M68K_REG_A3: return m68ki_cpu.dar[11];
case M68K_REG_A4: return m68ki_cpu.dar[12];
case M68K_REG_A5: return m68ki_cpu.dar[13];
case M68K_REG_A6: return m68ki_cpu.dar[14];
case M68K_REG_A7: return m68ki_cpu.dar[15];
case M68K_REG_PC: return MASK_OUT_ABOVE_32(m68ki_cpu.pc);
case M68K_REG_SR: return m68ki_cpu.t1_flag |
(m68ki_cpu.s_flag << 11) |
m68ki_cpu.int_mask |
((m68ki_cpu.x_flag & XFLAG_SET) >> 4) |
((m68ki_cpu.n_flag & NFLAG_SET) >> 4) |
((!m68ki_cpu.not_z_flag) << 2) |
((m68ki_cpu.v_flag & VFLAG_SET) >> 6) |
((m68ki_cpu.c_flag & CFLAG_SET) >> 8);
case M68K_REG_SP: return m68ki_cpu.dar[15];
case M68K_REG_USP: return m68ki_cpu.s_flag ? m68ki_cpu.sp[0] : m68ki_cpu.dar[15];
case M68K_REG_ISP: return m68ki_cpu.s_flag ? m68ki_cpu.dar[15] : m68ki_cpu.sp[4];
#if M68K_EMULATE_PREFETCH
case M68K_REG_PREF_ADDR: return m68ki_cpu.pref_addr;
case M68K_REG_PREF_DATA: return m68ki_cpu.pref_data;
#endif
case M68K_REG_IR: return m68ki_cpu.ir;
default: return 0;
}
}
void m68k_set_reg(m68k_register_t regnum, unsigned int value)
{
switch(regnum)
{
case M68K_REG_D0: REG_D[0] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D1: REG_D[1] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D2: REG_D[2] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D3: REG_D[3] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D4: REG_D[4] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D5: REG_D[5] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D6: REG_D[6] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_D7: REG_D[7] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A0: REG_A[0] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A1: REG_A[1] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A2: REG_A[2] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A3: REG_A[3] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A4: REG_A[4] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A5: REG_A[5] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A6: REG_A[6] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_A7: REG_A[7] = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_PC: m68ki_jump(MASK_OUT_ABOVE_32(value)); return;
case M68K_REG_SR: m68ki_set_sr(value); return;
case M68K_REG_SP: REG_SP = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_USP: if(FLAG_S)
REG_USP = MASK_OUT_ABOVE_32(value);
else
REG_SP = MASK_OUT_ABOVE_32(value);
return;
case M68K_REG_ISP: if(FLAG_S)
REG_SP = MASK_OUT_ABOVE_32(value);
else
REG_ISP = MASK_OUT_ABOVE_32(value);
return;
case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return;
#if M68K_EMULATE_PREFETCH
case M68K_REG_PREF_ADDR: CPU_PREF_ADDR = MASK_OUT_ABOVE_32(value); return;
#endif
default: return;
}
}
#if M68K_EMULATE_INT_ACK == OPT_ON
void m68k_set_int_ack_callback(int (*callback)(int int_level))
{
CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
}
#endif
#if M68K_EMULATE_RESET == OPT_ON
void m68k_set_reset_instr_callback(void (*callback)(void))
{
CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
}
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
void m68k_set_tas_instr_callback(int (*callback)(void))
{
CALLBACK_TAS_INSTR = callback ? callback : default_tas_instr_callback;
}
#endif
#if M68K_EMULATE_FC == OPT_ON
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
{
CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
}
#endif
#ifdef LOGVDP
extern void error(char *format, ...);
extern uint16 v_counter;
#endif
void m68k_update_irq(unsigned int mask)
{
CPU_INT_LEVEL |= (mask << 8);
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
}
void m68k_set_irq(unsigned int int_level)
{
CPU_INT_LEVEL = int_level << 8;
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
}
void m68k_set_irq_delay(unsigned int int_level)
{
if (!irq_latency)
{
if ((REG_IR & 0xF000) != 0x2000)
{
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
irq_latency = 1;
m68ki_trace_t1()
m68ki_use_data_space()
REG_IR = m68ki_read_imm_16();
m68ki_instruction_jump_table[REG_IR]();
m68ki_exception_if_trace()
irq_latency = 0;
}
CPU_INT_LEVEL = int_level << 8;
}
#ifdef LOGVDP
error("[%d(%d)][%d(%d)] IRQ Level = %d(0x%02x) (%x)\n", v_counter, m68k.cycles/3420, m68k.cycles, m68k.cycles%3420,CPU_INT_LEVEL>>8,FLAG_INT_MASK,m68k_get_reg(M68K_REG_PC));
#endif
m68ki_check_interrupts();
}
extern uint8 work_ram[0x10000];
void CDLog68k(uint addr, uint flags)
{
addr &= 0x00FFFFFF;
if(sram.on)
{
if(addr >= sram.start && addr <= sram.end)
{
biz_cdcallback(addr - sram.start, eCDLog_AddrType_SRAM, flags);
return;
}
}
if(addr < 0x400000)
{
uint block64k_rom;
unsigned char* block64k = m68ki_cpu.memory_map[((addr)>>16)&0xff].base;
if(block64k < cart.rom || block64k >= cart.rom + cart.romsize)
return;
block64k_rom = block64k - cart.rom;
addr = ((addr) & 0xffff) + block64k_rom;
if(addr >= cart.romsize)
return;
biz_cdcallback(addr, eCDLog_AddrType_MDCART, flags);
return;
}
if(addr > 0xFF0000)
{
biz_cdcallback(addr & 0xFFFF, eCDLog_AddrType_RAM68k, flags);
return;
}
}
void m68k_run(unsigned int cycles)
{
if (m68k.cycles >= cycles)
{
return;
}
m68ki_check_interrupts();
if (CPU_STOPPED)
{
m68k.cycles = cycles;
return;
}
m68k.cycle_end = cycles;
m68ki_set_address_error_trap()
#ifdef LOGVDP
error("[%d][%d] m68k run to %d cycles (%x), irq mask = %x (%x)\n", v_counter, m68k.cycles, cycles, m68k.pc,FLAG_INT_MASK, CPU_INT_LEVEL);
#endif
while (m68k.cycles < cycles)
{
m68ki_trace_t1()
m68ki_use_data_space()
if (biz_execcb)
biz_execcb(REG_PC);
if(biz_cdcallback)
{
CDLog68k(REG_PC,eCDLog_Flags_Exec68k);
CDLog68k(REG_PC+1,eCDLog_Flags_Exec68k);
}
biz_lastpc = REG_PC;
REG_IR = m68ki_read_imm_16();
m68ki_instruction_jump_table[REG_IR]();
USE_CYCLES(CYC_INSTRUCTION[REG_IR]);
m68ki_exception_if_trace();
}
}
void m68k_init(void)
{
#ifdef BUILD_TABLES
static uint emulation_initialized = 0;
if(!emulation_initialized)
{
m68ki_build_opcode_table();
emulation_initialized = 1;
}
#endif
#if M68K_EMULATE_INT_ACK == OPT_ON
m68k_set_int_ack_callback(NULL);
#endif
#if M68K_EMULATE_RESET == OPT_ON
m68k_set_reset_instr_callback(NULL);
#endif
#if M68K_TAS_HAS_CALLBACK == OPT_ON
m68k_set_tas_instr_callback(NULL);
#endif
#if M68K_EMULATE_FC == OPT_ON
m68k_set_fc_callback(NULL);
#endif
}
void m68k_pulse_reset(void)
{
CPU_STOPPED = 0;
#if M68K_EMULATE_ADDRESS_ERROR
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
#endif
FLAG_T1 = 0;
m68ki_clear_trace()
FLAG_INT_MASK = 0x0700;
CPU_INT_LEVEL = 0;
irq_latency = 0;
m68ki_set_s_flag(SFLAG_SET);
#if M68K_EMULATE_PREFETCH
CPU_PREF_ADDR = 0x1000;
#endif
m68ki_jump(0);
REG_SP = m68ki_read_imm_32();
REG_PC = m68ki_read_imm_32();
m68ki_jump(REG_PC);
#if M68K_EMULATE_ADDRESS_ERROR
CPU_RUN_MODE = RUN_MODE_NORMAL;
#endif
USE_CYCLES(CYC_EXCEPTION[EXCEPTION_RESET]);
}
void m68k_pulse_halt(void)
{
CPU_STOPPED |= STOP_LEVEL_HALT;
}
void m68k_clear_halt(void)
{
CPU_STOPPED &= ~STOP_LEVEL_HALT;
}