mirror of
https://github.com/ekeeke/Genesis-Plus-GX.git
synced 2024-12-30 21:21:49 +01:00
250 lines
9.5 KiB
C
250 lines
9.5 KiB
C
#ifndef M68K__HEADER
|
|
#define M68K__HEADER
|
|
|
|
/* ======================================================================== */
|
|
/* ========================= LICENSING & COPYRIGHT ======================== */
|
|
/* ======================================================================== */
|
|
/*
|
|
* MUSASHI
|
|
* Version 3.32
|
|
*
|
|
* A portable Motorola M680x0 processor emulation engine.
|
|
* Copyright Karl Stenerud. All rights reserved.
|
|
*
|
|
* This code may be freely used for non-commercial purposes as long as this
|
|
* copyright notice remains unaltered in the source code and any binary files
|
|
* containing this code in compiled form.
|
|
*
|
|
* All other licensing terms must be negotiated with the author
|
|
* (Karl Stenerud).
|
|
*
|
|
* The latest version of this code can be obtained at:
|
|
* http://kstenerud.cjb.net
|
|
*/
|
|
|
|
/* Modified by Eke-Eke for Genesis Plus GX:
|
|
|
|
- removed unused stuff to reduce memory usage / optimize execution (multiple CPU types support, NMI support, ...)
|
|
- moved stuff to compile statically in a single object file
|
|
- implemented support for global cycle count (shared by 68k & Z80 CPU)
|
|
- added support for interrupt latency (Sesame's Street Counting Cafe, Fatal Rewind)
|
|
- added proper cycle use on reset
|
|
- added cycle accurate timings for MUL/DIV instructions (thanks to Jorge Cwik !)
|
|
- fixed undocumented flags for DIV instructions (Blood Shot)
|
|
|
|
*/
|
|
|
|
/* ======================================================================== */
|
|
/* ============================= CONFIGURATION ============================ */
|
|
/* ======================================================================== */
|
|
|
|
/* Import the configuration for this build */
|
|
#include "m68kconf.h"
|
|
|
|
|
|
/* ======================================================================== */
|
|
/* ============================ GENERAL DEFINES =========================== */
|
|
|
|
/* ======================================================================== */
|
|
|
|
/* There are 7 levels of interrupt to the 68K.
|
|
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
|
|
*/
|
|
#define M68K_IRQ_NONE 0
|
|
#define M68K_IRQ_1 1
|
|
#define M68K_IRQ_2 2
|
|
#define M68K_IRQ_3 3
|
|
#define M68K_IRQ_4 4
|
|
#define M68K_IRQ_5 5
|
|
#define M68K_IRQ_6 6
|
|
#define M68K_IRQ_7 7
|
|
|
|
|
|
/* Special interrupt acknowledge values.
|
|
* Use these as special returns from the interrupt acknowledge callback
|
|
* (specified later in this header).
|
|
*/
|
|
|
|
/* Causes an interrupt autovector (0x18 + interrupt level) to be taken.
|
|
* This happens in a real 68K if VPA or AVEC is asserted during an interrupt
|
|
* acknowledge cycle instead of DTACK.
|
|
*/
|
|
#define M68K_INT_ACK_AUTOVECTOR 0xffffffff
|
|
|
|
/* Causes the spurious interrupt vector (0x18) to be taken
|
|
* This happens in a real 68K if BERR is asserted during the interrupt
|
|
* acknowledge cycle (i.e. no devices responded to the acknowledge).
|
|
*/
|
|
#define M68K_INT_ACK_SPURIOUS 0xfffffffe
|
|
|
|
|
|
/* Registers used by m68k_get_reg() and m68k_set_reg() */
|
|
typedef enum
|
|
{
|
|
/* Real registers */
|
|
M68K_REG_D0, /* Data registers */
|
|
M68K_REG_D1,
|
|
M68K_REG_D2,
|
|
M68K_REG_D3,
|
|
M68K_REG_D4,
|
|
M68K_REG_D5,
|
|
M68K_REG_D6,
|
|
M68K_REG_D7,
|
|
M68K_REG_A0, /* Address registers */
|
|
M68K_REG_A1,
|
|
M68K_REG_A2,
|
|
M68K_REG_A3,
|
|
M68K_REG_A4,
|
|
M68K_REG_A5,
|
|
M68K_REG_A6,
|
|
M68K_REG_A7,
|
|
M68K_REG_PC, /* Program Counter */
|
|
M68K_REG_SR, /* Status Register */
|
|
M68K_REG_SP, /* The current Stack Pointer (located in A7) */
|
|
M68K_REG_USP, /* User Stack Pointer */
|
|
M68K_REG_ISP, /* Interrupt Stack Pointer */
|
|
|
|
#if M68K_EMULATE_PREFETCH
|
|
/* Assumed registers */
|
|
/* These are cheat registers which emulate the 1-longword prefetch
|
|
* present in the 68000 and 68010.
|
|
*/
|
|
M68K_REG_PREF_ADDR, /* Last prefetch address */
|
|
M68K_REG_PREF_DATA, /* Last prefetch data */
|
|
#endif
|
|
|
|
/* Convenience registers */
|
|
M68K_REG_IR /* Instruction register */
|
|
} m68k_register_t;
|
|
|
|
|
|
/* ======================================================================== */
|
|
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
|
|
/* ======================================================================== */
|
|
|
|
#include "macros.h"
|
|
|
|
/* 68k memory map structure */
|
|
typedef struct
|
|
{
|
|
unsigned char *base; /* direct memory access (ROM, RAM) */
|
|
unsigned int (*read8)(unsigned int address); /* I/O byte read access */
|
|
unsigned int (*read16)(unsigned int address); /* I/O word read access */
|
|
void (*write8)(unsigned int address, unsigned int data); /* I/O byte write access */
|
|
void (*write16)(unsigned int address, unsigned int data); /* I/O word write access */
|
|
} _m68k_memory_map;
|
|
|
|
/* 68k memory map */
|
|
_m68k_memory_map m68k_memory_map[256];
|
|
|
|
/* Read data immediately following the PC */
|
|
#define m68k_read_immediate_16(address) *(uint16 *)(m68k_memory_map[((address)>>16)&0xff].base + ((address) & 0xffff))
|
|
#define m68k_read_immediate_32(address) (m68k_read_immediate_16(address) << 16) | (m68k_read_immediate_16(address+2))
|
|
|
|
/* Read data relative to the PC */
|
|
#define m68k_read_pcrelative_8(address) READ_BYTE(m68k_memory_map[((address)>>16)&0xff].base, (address) & 0xffff)
|
|
#define m68k_read_pcrelative_16(address) m68k_read_immediate_16(address)
|
|
#define m68k_read_pcrelative_32(address) m68k_read_immediate_32(address)
|
|
|
|
|
|
/* ======================================================================== */
|
|
/* ============================== CALLBACKS =============================== */
|
|
/* ======================================================================== */
|
|
|
|
/* These functions allow you to set callbacks to the host when specific events
|
|
* occur. Note that you must enable the corresponding value in m68kconf.h
|
|
* in order for these to do anything useful.
|
|
* Note: I have defined default callbacks which are used if you have enabled
|
|
* the corresponding #define in m68kconf.h but either haven't assigned a
|
|
* callback or have assigned a callback of NULL.
|
|
*/
|
|
|
|
#if M68K_EMULATE_INT_ACK == OPT_ON
|
|
/* Set the callback for an interrupt acknowledge.
|
|
* You must enable M68K_EMULATE_INT_ACK in m68kconf.h.
|
|
* The CPU will call the callback with the interrupt level being acknowledged.
|
|
* The host program must return either a vector from 0x02-0xff, or one of the
|
|
* special interrupt acknowledge values specified earlier in this header.
|
|
* If this is not implemented, the CPU will always assume an autovectored
|
|
* interrupt, and will automatically clear the interrupt request when it
|
|
* services the interrupt.
|
|
* Default behavior: return M68K_INT_ACK_AUTOVECTOR.
|
|
*/
|
|
void m68k_set_int_ack_callback(int (*callback)(int int_level));
|
|
#endif
|
|
|
|
#if M68K_EMULATE_RESET == OPT_ON
|
|
/* Set the callback for the RESET instruction.
|
|
* You must enable M68K_EMULATE_RESET in m68kconf.h.
|
|
* The CPU calls this callback every time it encounters a RESET instruction.
|
|
* Default behavior: do nothing.
|
|
*/
|
|
void m68k_set_reset_instr_callback(void (*callback)(void));
|
|
#endif
|
|
|
|
#if M68K_TAS_HAS_CALLBACK == OPT_ON
|
|
/* Set the callback for the TAS instruction.
|
|
* You must enable M68K_TAS_HAS_CALLBACK in m68kconf.h.
|
|
* The CPU calls this callback every time it encounters a TAS instruction.
|
|
* Default behavior: return 1, allow writeback.
|
|
*/
|
|
void m68k_set_tas_instr_callback(int (*callback)(void));
|
|
#endif
|
|
|
|
#if M68K_EMULATE_FC == OPT_ON
|
|
/* Set the callback for CPU function code changes.
|
|
* You must enable M68K_EMULATE_FC in m68kconf.h.
|
|
* The CPU calls this callback with the function code before every memory
|
|
* access to set the CPU's function code according to what kind of memory
|
|
* access it is (supervisor/user, program/data and such).
|
|
* Default behavior: do nothing.
|
|
*/
|
|
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc));
|
|
#endif
|
|
|
|
|
|
/* ======================================================================== */
|
|
/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */
|
|
/* ======================================================================== */
|
|
|
|
/* Do whatever initialisations the core requires. Should be called
|
|
* at least once at init time.
|
|
*/
|
|
extern void m68k_init(void);
|
|
|
|
/* Pulse the RESET pin on the CPU.
|
|
* You *MUST* reset the CPU at least once to initialize the emulation
|
|
*/
|
|
extern void m68k_pulse_reset(void);
|
|
|
|
/* Run until given cycle count is reached */
|
|
extern void m68k_run(unsigned int cycles);
|
|
|
|
/* Set the IPL0-IPL2 pins on the CPU (IRQ).
|
|
* A transition from < 7 to 7 will cause a non-maskable interrupt (NMI).
|
|
* Setting IRQ to 0 will clear an interrupt request.
|
|
*/
|
|
extern void m68k_update_irq(unsigned int mask);
|
|
extern void m68k_set_irq(unsigned int int_level);
|
|
extern void m68k_set_irq_delay(unsigned int int_level);
|
|
|
|
/* Halt the CPU as if you pulsed the HALT pin. */
|
|
extern void m68k_pulse_halt(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.
|
|
*/
|
|
extern unsigned int m68k_get_reg(m68k_register_t reg);
|
|
|
|
/* Poke values into the internals of the currently running CPU context */
|
|
extern void m68k_set_reg(m68k_register_t reg, unsigned int value);
|
|
|
|
|
|
/* ======================================================================== */
|
|
/* ============================== END OF FILE ============================= */
|
|
/* ======================================================================== */
|
|
|
|
#endif /* M68K__HEADER */
|