- Added the Musashi 68K emulator by Karl Stenerud. Obtained Karl's explicit permission to relicense the code under GPL.

- Added a 68K interface, CPU/68K/M68K.*.
- Moved Turbo68K source files to CPU/68K/Turbo68K. It is no longer used but is being retained in the source tree for now. The LSR instruction has not been fixed in this update.
- Changed sound board code to use the new 68K interface (and hence, Musashi).
- Changed version string from 0.2-WIP to 0.2a-WIP. This is still an alpha version.
- Above changes have broken the 68K debugger.
This commit is contained in:
Bart Trzynadlowski 2011-07-12 04:57:12 +00:00
parent 95d61ce8bb
commit c73cb830dc
19 changed files with 19981 additions and 206 deletions

View file

@ -47,7 +47,7 @@ ENABLE_DEBUGGER = no
#
# Experimental sound code ('yes' on 32-bit builds only or 'no')
#
ENABLE_SOUND = no
ENABLE_SOUND = yes
###############################################################################
@ -118,7 +118,7 @@ OUTFILE = $(BIN_DIR)\Supermodel.exe
CC = "$(VC_BIN)\cl.exe"
LD = "$(VC_BIN)\link.exe"
COMPILER_FLAGS = /I "$(SDL_INCLUDEPATH)" /I "$(ZLIB_INCLUDEPATH)" /I "$(DIRECTX_INCLUDEPATH)" /I "Src\\" /I "Src\OSD\SDL\\" /Ox \
/D "SUPERMODEL_WIN32" /D "GLEW_STATIC" /D "_MBCS" /D "_CRT_SECURE_NO_WARNINGS" /MT /Gy /W3 /nologo /c /Zi /GL
/D "SUPERMODEL_WIN32" /D "GLEW_STATIC" /D "_MBCS" /D "_CRT_SECURE_NO_WARNINGS" /MT /Gy /W3 /nologo /c /Zi /GL /D "DEBUG" /DEBUG
CFLAGS = $(COMPILER_FLAGS) /TC
CPPFLAGS = $(COMPILER_FLAGS) /TP /EHsc
LFLAGS = /MACHINE:$(ARCH) $(ARCH_LIBS) /LIBPATH:"$(SDL_LIBPATH)" /LIBPATH:"$(ZLIB_LIBPATH)" /LIBPATH:"$(DIRECTX_LIBPATH)" /OUT:"$(OUTFILE)" \
@ -129,7 +129,7 @@ OBJ_LIBS = kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.
#
# Turbo68K options
#
MAKE68KFLAGS = -singleaddr
TURBO68K_FLAGS = -singleaddr
#
@ -145,7 +145,7 @@ endif
# Add compiler flags for various options
ifeq ($(strip $(ENABLE_DEBUGGER)),yes)
COMPILER_FLAGS += /D "SUPERMODEL_DEBUGGER"
MAKE68KFLAGS += -debug
TURBO68K_FLAGS += -debug
endif
ifeq ($(strip $(ENABLE_SOUND)),yes)
@ -164,16 +164,12 @@ HEADERS = Src/Supermodel.h Src/OSD/SDL/Types.h
OBJ = $(OBJ_DIR)/PPCDisasm.obj $(OBJ_DIR)/Games.obj $(OBJ_DIR)/INIFile.obj $(OBJ_DIR)/BlockFile.obj $(OBJ_DIR)/93C46.obj \
$(OBJ_DIR)/ROMLoad.obj $(OBJ_DIR)/unzip.obj $(OBJ_DIR)/ioapi.obj $(OBJ_DIR)/Error.obj $(OBJ_DIR)/glew.obj $(OBJ_DIR)/Shader.obj \
$(OBJ_DIR)/Real3D.obj $(OBJ_DIR)/Render3D.obj $(OBJ_DIR)/Models.obj $(OBJ_DIR)/Render2D.obj $(OBJ_DIR)/TileGen.obj \
$(OBJ_DIR)/Model3.obj $(OBJ_DIR)/ppc.obj $(OBJ_DIR)/Main.obj $(OBJ_DIR)/SoundBoard.obj \
$(OBJ_DIR)/Model3.obj $(OBJ_DIR)/ppc.obj $(OBJ_DIR)/Main.obj $(OBJ_DIR)/SoundBoard.obj $(OBJ_DIR)/SCSP.obj $(OBJ_DIR)/SCSPDSP.obj $(OBJ_DIR)/M68K.obj\
$(OBJ_DIR)/m68kcpu.obj $(OBJ_DIR)/m68kopnz.obj $(OBJ_DIR)/m68kopdm.obj $(OBJ_DIR)/m68kopac.obj $(OBJ_DIR)/m68kops.obj \
$(OBJ_DIR)/IRQ.obj $(OBJ_DIR)/53C810.obj $(OBJ_DIR)/PCI.obj $(OBJ_DIR)/RTC72421.obj $(OBJ_DIR)/MPC10x.obj \
$(OBJ_DIR)/Input.obj $(OBJ_DIR)/Inputs.obj $(OBJ_DIR)/InputSource.obj $(OBJ_DIR)/InputSystem.obj $(OBJ_DIR)/InputTypes.obj \
$(OBJ_DIR)/MultiInputSource.obj $(OBJ_DIR)/SDLInputSystem.obj $(OBJ_DIR)/DirectInputSystem.obj
# If sound enabled, include Turbo68K and SCSP code
ifeq ($(strip $(ENABLE_SOUND)),yes)
OBJ += $(OBJ_DIR)/Turbo68K.obj $(OBJ_DIR)/SCSP.obj $(OBJ_DIR)/SCSPDSP.obj
endif
# If built-in debugger enabled, include all debugging classes
ifeq ($(strip $(ENABLE_DEBUGGER)),yes)
OBJ += $(OBJ_DIR)/Debugger.obj $(OBJ_DIR)/ConsoleDebugger.obj $(OBJ_DIR)/SupermodelDebugger.obj $(OBJ_DIR)/CPUDebug.obj \
@ -208,17 +204,51 @@ $(OBJ_DIR):
clean:
del $(OUTFILE)
del $(OBJ_DIR)\*.obj
del $(OBJ_DIR)\*.c
del $(OBJ_DIR)\*.h
del $(OBJ_DIR)\*.exe
#
# Musashi 68K emulator
#
# All generated source files are emitted to the object directory. For MSVC,
# INLINE must be redefined as "static __inline", which is the syntax in C mode.
#
$(OBJ_DIR)/m68kmake.exe: Src/CPU/68K/Musashi/m68kmake.c
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/m68kmake.obj
$(LD) /OUT:$(OBJ_DIR)/m68kmake.exe /SUBSYSTEM:CONSOLE /NOLOGO /MANIFEST:NO /LTCG $(OBJ_DIR)/m68kmake.obj
$(OBJ_DIR)/m68kops.h: $(OBJ_DIR)/m68kmake.exe Src/CPU/68K/Musashi/m68k_in.c
$(OBJ_DIR)/m68kmake.exe $(OBJ_DIR) Src/CPU/68K/Musashi/m68k_in.c
$(OBJ_DIR)/m68kcpu.obj: Src/CPU/68K/Musashi/m68kcpu.c $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/m68kcpu.obj /I "$(OBJ_DIR)" /I "Src\CPU\68K\Musashi" /DINLINE="static __inline"
$(OBJ_DIR)/m68kops.obj: $(OBJ_DIR)/m68kops.c $(OBJ_DIR)/m68kmake.exe $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/m68kops.obj /I "Src\CPU\68K\Musashi" /DINLINE="static __inline"
$(OBJ_DIR)/m68kopac.obj: $(OBJ_DIR)/m68kopac.c $(OBJ_DIR)/m68kmake.exe $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/m68kopac.obj /I "Src\CPU\68K\Musashi" /DINLINE="static __inline"
$(OBJ_DIR)/m68kopdm.obj: $(OBJ_DIR)/m68kopdm.c $(OBJ_DIR)/m68kmake.exe $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/m68kopdm.obj /I "Src\CPU\68K\Musashi" /DINLINE="static __inline"
$(OBJ_DIR)/m68kopnz.obj: $(OBJ_DIR)/m68kopnz.c $(OBJ_DIR)/m68kmake.exe $(OBJ_DIR)/m68kops.h Src/CPU/68K/Musashi/m68k.h Src/CPU/68K/Musashi/m68kconf.h
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/m68kopnz.obj /I "Src\CPU\68K\Musashi" /DINLINE="static __inline"
#
# Turbo68K
#
$(OBJ_DIR)/Make68K.exe: Src/CPU/68K/Make68K.c
# 32-bit only.
#
$(OBJ_DIR)/Make68K.exe: Src/CPU/68K/Turbo68K/Make68K.c
$(CC) $< $(CFLAGS) /Fo$(OBJ_DIR)/Make68K.obj
$(LD) /OUT:$(OBJ_DIR)/Make68K.exe /SUBSYSTEM:CONSOLE /NOLOGO /MANIFEST:NO /LTCG $(OBJ_DIR)/Make68K.obj
$(OBJ_DIR)/Turbo68K.obj: $(OBJ_DIR)/Make68K.exe
$(OBJ_DIR)/Make68K.exe $(OBJ_DIR)/Turbo68K.asm $(MAKE68KFLAGS)
$(OBJ_DIR)/Make68K.exe $(OBJ_DIR)/Turbo68K.asm $(TURBO68K_FLAGS)
nasm $(OBJ_DIR)/Turbo68K.asm -o $(OBJ_DIR)/Turbo68K.obj -f win32
@ -255,6 +285,9 @@ $(OBJ_DIR)/%.obj: Src/Debugger/CPU/%.cpp Src/Debugger/CPU/%.h $(HEADERS)
$(OBJ_DIR)/%.obj: Src/CPU/PowerPC/%.cpp Src/CPU/PowerPC/%.h Src/CPU/PowerPC/ppc603.c Src/CPU/PowerPC/ppc_ops.c $(HEADERS)
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
$(OBJ_DIR)/%.obj: Src/CPU/68K/%.cpp Src/CPU/68K/%.h $(HEADERS)
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj
$(OBJ_DIR)/%.obj: Src/Inputs/%.cpp Src/Inputs/%.h $(HEADERS)
$(CC) $< $(CPPFLAGS) /Fo$(OBJ_DIR)/$(*F).obj

241
Src/CPU/68K/M68K.cpp Normal file
View file

@ -0,0 +1,241 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* M68K.cpp
*
* 68K CPU interface. This is presently just a wrapper for the Musashi 68K core
* and therefore, only a single CPU is supported. In the future, we may want to
* add in another 68K core (eg., Turbo68K, A68K, or a recompiler).
*/
#include "Supermodel.h"
#include "Musashi/m68k.h" // Musashi 68K core
/******************************************************************************
68K Interface
******************************************************************************/
// Interface function pointers
static int (*IRQAck)(int nIRQ) = NULL;
static UINT8 (*Fetch8)(UINT32 addr) = NULL;
static UINT16 (*Fetch16)(UINT32 addr) = NULL;
static UINT32 (*Fetch32)(UINT32 addr) = NULL;
static UINT8 (*Read8)(UINT32 addr) = NULL;
static UINT16 (*Read16)(UINT32 addr) = NULL;
static UINT32 (*Read32)(UINT32 addr) = NULL;
static void (*Write8)(UINT32 addr, UINT8 data) = NULL;
static void (*Write16)(UINT32 addr, UINT16 data) = NULL;
static void (*Write32)(UINT32 addr, UINT32 data) = NULL;
extern "C" {
// CPU state
UINT32 M68KGetARegister(int n)
{
m68k_register_t r;
switch (n)
{
case 0: r = M68K_REG_A0; break;
case 1: r = M68K_REG_A1; break;
case 2: r = M68K_REG_A2; break;
case 3: r = M68K_REG_A3; break;
case 4: r = M68K_REG_A4; break;
case 5: r = M68K_REG_A5; break;
case 6: r = M68K_REG_A6; break;
case 7: r = M68K_REG_A7; break;
default: r = M68K_REG_A7; break;
}
return m68k_get_reg(NULL, r);
}
UINT32 M68KGetDRegister(int n)
{
m68k_register_t r;
switch (n)
{
case 0: r = M68K_REG_D0; break;
case 1: r = M68K_REG_D1; break;
case 2: r = M68K_REG_D2; break;
case 3: r = M68K_REG_D3; break;
case 4: r = M68K_REG_D4; break;
case 5: r = M68K_REG_D5; break;
case 6: r = M68K_REG_D6; break;
case 7: r = M68K_REG_D7; break;
default: r = M68K_REG_D7; break;
}
return m68k_get_reg(NULL, r);
}
UINT32 M68KGetPC(void)
{
return m68k_get_reg(NULL, M68K_REG_PC);
}
// Emulation functions
void M68KSetIRQ(int irqLevel)
{
m68k_set_irq(irqLevel);
}
int M68KRun(int numCycles)
{
return m68k_execute(numCycles);
}
void M68KReset(void)
{
m68k_pulse_reset();
}
// Callback setup
void M68KSetIRQCallback(int (*F)(int nIRQ))
{
IRQAck = F;
}
void M68KSetFetch8Callback(UINT8 (*F)(UINT32))
{
Fetch8 = F;
}
void M68KSetFetch16Callback(UINT16 (*F)(UINT32))
{
Fetch16 = F;
}
void M68KSetFetch32Callback(UINT32 (*F)(UINT32))
{
Fetch32 = F;
}
void M68KSetRead8Callback(UINT8 (*F)(UINT32))
{
Read8 = F;
}
void M68KSetRead16Callback(UINT16 (*F)(UINT32))
{
Read16 = F;
}
void M68KSetRead32Callback(UINT32 (*F)(UINT32))
{
Read32 = F;
}
void M68KSetWrite8Callback(void (*F)(UINT32,UINT8))
{
Write8 = F;
}
void M68KSetWrite16Callback(void (*F)(UINT32,UINT16))
{
Write16 = F;
}
void M68KSetWrite32Callback(void (*F)(UINT32,UINT32))
{
Write32 = F;
}
// One-time initialization
BOOL M68KInit(void)
{
m68k_init();
m68k_set_cpu_type(M68K_CPU_TYPE_68000);
m68k_set_int_ack_callback(M68KIRQCallback);
return OKAY;
}
} // extern "C"
/******************************************************************************
Musashi 68K Handlers
Musashi/m68kconf.h has been configured to call these directly.
******************************************************************************/
extern "C" {
int M68KIRQCallback(int nIRQ)
{
if (NULL == IRQAck)
return M68K_IRQ_AUTOVECTOR;
else
return IRQAck(nIRQ);
}
unsigned int FASTCALL M68KFetch8(unsigned int a)
{
return Fetch8(a);
}
unsigned int FASTCALL M68KFetch16(unsigned int a)
{
return Fetch16(a);
}
unsigned int FASTCALL M68KFetch32(unsigned int a)
{
return Fetch32(a);
}
unsigned int FASTCALL M68KRead8(unsigned int a)
{
return Read8(a);
}
unsigned int FASTCALL M68KRead16(unsigned int a)
{
return Read16(a);
}
unsigned int FASTCALL M68KRead32(unsigned int a)
{
return Read32(a);
}
void FASTCALL M68KWrite8(unsigned int a, unsigned int d)
{
Write8(a, d);
}
void FASTCALL M68KWrite16(unsigned int a, unsigned int d)
{
Write16(a, d);
}
void FASTCALL M68KWrite32(unsigned int a, unsigned int d)
{
Write32(a, d);
}
} // extern "C"

252
Src/CPU/68K/M68K.h Normal file
View file

@ -0,0 +1,252 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* M68K.h
*
* Header file for 68K CPU interface. Caution: there is only a single 68K core
* available to Supermodel right now. Therefore, multiple 68K CPUs are not
* presently supported. See M68K.c for more details.
*
* TO-DO List:
* -----------
* - Optimize things, perhaps by using FASTCALL
*/
#ifndef INCLUDED_M68K_H
#define INCLUDED_M68K_H
#include "Types.h"
#include "Musashi/m68k.h"
#ifdef __cplusplus
extern "C" {
#endif
// This doesn't work for now (needs to be added to the prototypes in m68k.h for m68k_read_memory*)
//#ifndef FASTCALL
#undef FASTCALL
#define FASTCALL
//#endif
/******************************************************************************
Definitions
******************************************************************************/
// IRQ callback special return values
#define M68K_IRQ_AUTOVECTOR M68K_INT_ACK_AUTOVECTOR // signals an autovectored interrupt
#define M68K_IRQ_SPURIOUS M68K_INT_ACK_SPURIOUS // signals a spurious interrupt
/******************************************************************************
68K Interface
******************************************************************************/
/*
* M68KGetDRegister(int n):
*
* Parameters:
* n Register number (0-7).
*
* Returns:
* Register An.
*/
extern UINT32 M68KGetARegister(int n);
/*
* M68KGetDRegister(int n):
*
* Parameters:
* n Register number (0-7).
*
* Returns:
* Register Dn.
*/
extern UINT32 M68KGetDRegister(int reg);
/*
* M68KGetPC():
*
* Returns:
* Current program counter.
*/
extern UINT32 M68KGetPC(void);
/*
* M68KSetIRQ(irqLevel):
*
* Sets the interrupt level (IPL2-IPL0 pins).
*
* Parameters:
* irqLevel The interrupt level (1-7) or 0 to clear the interrupt.
*/
extern void M68KSetIRQ(int irqLevel);
/*
* M68KRun(numCycles):
*
* Runs the 68K.
*
* Parameters:
* numCycles Number of cycles to run.
*
* Returns:
* Number of cycles executed.
*/
extern int M68KRun(int numCycles);
/*
* M68KReset():
*
* Resets the 68K.
*/
extern void M68KReset(void);
/*
* M68KSetIRQCallback(F):
*
* Installs an interrupt acknowledge callback. The default behavior is to
* always assume autovectored interrupts.
*
* Parameters:
* F Callback function.
*/
extern void M68KSetIRQCallback(int (*F)(int));
/*
* M68KSetFetch8Callback(F):
* M68KSetFetch16Callback(F):
* M68KSetFetch32Callback(F):
* M68KSetRead8Callback(F):
* M68KSetRead16Callback(F):
* M68KSetRead32Callback(F):
* M68KSetWrite8Callback(F):
* M68KSetWrite16Callback(F):
* M68KSetWrite32Callback(F):
*
* Installs address space handler callbacks. There is no default behavior;
* these must all be set up before any 68K-related emulation functions are
* invoked.
*
* Parameters:
* F Callback function.
*/
extern void M68KSetFetch8Callback(UINT8 (*F)(UINT32));
extern void M68KSetFetch16Callback(UINT16 (*F)(UINT32));
extern void M68KSetFetch32Callback(UINT32 (*F)(UINT32));
extern void M68KSetRead8Callback(UINT8 (*F)(UINT32));
extern void M68KSetRead16Callback(UINT16 (*F)(UINT32));
extern void M68KSetRead32Callback(UINT32 (*F)(UINT32));
extern void M68KSetWrite8Callback(void (*F)(UINT32,UINT8));
extern void M68KSetWrite16Callback(void (*F)(UINT32,UINT16));
extern void M68KSetWrite32Callback(void (*F)(UINT32,UINT32));
/*
* M68KInit():
*
* Initializes the 68K emulator. Must be called once per program session prior
* to any other 68K interface calls.
*
* Returns:
* Always returns OKAY.
*/
extern BOOL M68KInit(void);
/******************************************************************************
68K Handlers
Intended for use directly by the 68K core.
******************************************************************************/
/*
* M68KIRQCallback(nIRQ):
*
* Interrupt acknowledge callback. Called when an interrupt is being serviced.
* Actually implemented by calling a user-supplied callback.
*
* Parameters:
* nIRQ IRQ level (1-7).
*
* Returns:
* The interrupt vector to use, M68K_IRQ_AUTOVECTOR, or
* M68K_IRQ_SPURIOUS. If no callback has been installed, the default
* callback is used and always returns M68K_IRQ_AUTOVECTOR.
*/
extern int M68KIRQCallback(int nIRQ);
/*
* M68KFetch8(a):
* M68KFetch16(a):
* M68KFetch32(a):
*
* Read data from the program address space.
*
* Parameters:
* a Address to read from.
*
* Returns:
* The 8, 16, or 32-bit value read.
*/
unsigned int FASTCALL M68KFetch8(unsigned int a);
unsigned int FASTCALL M68KFetch16(unsigned int a);
unsigned int FASTCALL M68KFetch32(unsigned int a);
/*
* M68KRead8(a):
* M68KRead16(a):
* M68KRead32(a):
*
* Read data from the data address space.
*
* Parameters:
* a Address to read from.
*
* Returns:
* The 8, 16, or 32-bit value read.
*/
unsigned int FASTCALL M68KRead8(unsigned int a);
unsigned int FASTCALL M68KRead16(unsigned int a);
unsigned int FASTCALL M68KRead32(unsigned int a);
/*
* M68KWrite8(a, d):
* M68KWrite16(a, d):
* M68KWrite32(a, d):
*
* Writes to the data address space.
*
* Parameters:
* a Address to write to.
* d Data to write.
*/
void FASTCALL M68KWrite8(unsigned int a, unsigned int d);
void FASTCALL M68KWrite16(unsigned int a, unsigned int d);
void FASTCALL M68KWrite32(unsigned int a, unsigned int d);
#ifdef __cplusplus
}
#endif
#endif // INCLUDED_M68K_H

395
Src/CPU/68K/Musashi/m68k.h Normal file
View file

@ -0,0 +1,395 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* m68k.h
*
* Header file for the Musashi 68K emulator.
*
* Permission was obtained from Karl Stenerud to apply the GPL license to this
* code.
*/
#ifndef M68K__HEADER
#define M68K__HEADER
#ifdef __cplusplus
extern "C" {
#endif
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
/*
* MUSASHI
* Version 3.3
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 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 lisencing terms must be negotiated with the author
* (Karl Stenerud).
*
* The latest version of this code can be obtained at:
* http://kstenerud.cjb.net
*/
/* ======================================================================== */
/* ============================ 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
/* CPU types for use in m68k_set_cpu_type() */
enum
{
M68K_CPU_TYPE_INVALID,
M68K_CPU_TYPE_68000,
M68K_CPU_TYPE_68008,
M68K_CPU_TYPE_68010,
M68K_CPU_TYPE_68EC020,
M68K_CPU_TYPE_68020,
M68K_CPU_TYPE_68030, /* Supported by disassembler ONLY */
M68K_CPU_TYPE_68040 /* Supported by disassembler ONLY */
};
/* 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 */
M68K_REG_MSP, /* Master Stack Pointer */
M68K_REG_SFC, /* Source Function Code */
M68K_REG_DFC, /* Destination Function Code */
M68K_REG_VBR, /* Vector Base Register */
M68K_REG_CACR, /* Cache Control Register */
M68K_REG_CAAR, /* Cache Address Register */
/* 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 */
/* Convenience registers */
M68K_REG_PPC, /* Previous value in the program counter */
M68K_REG_IR, /* Instruction register */
M68K_REG_CPU_TYPE /* Type of CPU being run */
} m68k_register_t;
/* ======================================================================== */
/* ====================== FUNCTIONS CALLED BY THE CPU ===================== */
/* ======================================================================== */
/* You will have to implement these functions */
/* read/write functions called by the CPU to access memory.
* while values used are 32 bits, only the appropriate number
* of bits are relevant (i.e. in write_memory_8, only the lower 8 bits
* of value should be written to memory).
*
* NOTE: I have separated the immediate and PC-relative memory fetches
* from the other memory fetches because some systems require
* differentiation between PROGRAM and DATA fetches (usually
* for security setups such as encryption).
* This separation can either be achieved by setting
* M68K_SEPARATE_READS in m68kconf.h and defining
* the read functions, or by setting M68K_EMULATE_FC and
* making a function code callback function.
* Using the callback offers better emulation coverage
* because you can also monitor whether the CPU is in SYSTEM or
* USER mode, but it is also slower.
*/
/* Read from anywhere */
unsigned int m68k_read_memory_8(unsigned int address);
unsigned int m68k_read_memory_16(unsigned int address);
unsigned int m68k_read_memory_32(unsigned int address);
/* Read data immediately following the PC */
unsigned int m68k_read_immediate_16(unsigned int address);
unsigned int m68k_read_immediate_32(unsigned int address);
/* Read data relative to the PC */
unsigned int m68k_read_pcrelative_8(unsigned int address);
unsigned int m68k_read_pcrelative_16(unsigned int address);
unsigned int m68k_read_pcrelative_32(unsigned int address);
/* Memory access for the disassembler */
unsigned int m68k_read_disassembler_8 (unsigned int address);
unsigned int m68k_read_disassembler_16 (unsigned int address);
unsigned int m68k_read_disassembler_32 (unsigned int address);
/* Write to anywhere */
void m68k_write_memory_8(unsigned int address, unsigned int value);
void m68k_write_memory_16(unsigned int address, unsigned int value);
void m68k_write_memory_32(unsigned int address, unsigned int value);
/* Special call to simulate undocumented 68k behavior when move.l with a
* predecrement destination mode is executed.
* To simulate real 68k behavior, first write the high word to
* [address+2], and then write the low word to [address].
*
* Enable this functionality with M68K_SIMULATE_PD_WRITES in m68kconf.h.
*/
void m68k_write_memory_32_pd(unsigned int address, unsigned int value);
/* ======================================================================== */
/* ============================== 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.
*/
/* 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));
/* Set the callback for a breakpoint acknowledge (68010+).
* You must enable M68K_EMULATE_BKPT_ACK in m68kconf.h.
* The CPU will call the callback with whatever was in the data field of the
* BKPT instruction for 68020+, or 0 for 68010.
* Default behavior: do nothing.
*/
void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data));
/* 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));
/* Set the callback for the CMPI.L #v, Dn instruction.
* You must enable M68K_CMPILD_HAS_CALLBACK in m68kconf.h.
* The CPU calls this callback every time it encounters a CMPI.L #v, Dn instruction.
* Default behavior: do nothing.
*/
void m68k_set_cmpild_instr_callback(void (*callback)(unsigned int val, int reg));
/* Set the callback for the RTE instruction.
* You must enable M68K_RTE_HAS_CALLBACK in m68kconf.h.
* The CPU calls this callback every time it encounters a RTE instruction.
* Default behavior: do nothing.
*/
void m68k_set_rte_instr_callback(void (*callback)(void));
/* Set the callback for informing of a large PC change.
* You must enable M68K_MONITOR_PC in m68kconf.h.
* The CPU calls this callback with the new PC value every time the PC changes
* by a large value (currently set for changes by longwords).
* Default behavior: do nothing.
*/
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc));
/* 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));
/* Set a callback for the instruction cycle of the CPU.
* You must enable M68K_INSTRUCTION_HOOK in m68kconf.h.
* The CPU calls this callback just before fetching the opcode in the
* instruction cycle.
* Default behavior: do nothing.
*/
void m68k_set_instr_hook_callback(void (*callback)(void));
/* ======================================================================== */
/* ====================== FUNCTIONS TO ACCESS THE CPU ===================== */
/* ======================================================================== */
/* Use this function to set the CPU type you want to emulate.
* Currently supported types are: M68K_CPU_TYPE_68000, M68K_CPU_TYPE_68008,
* M68K_CPU_TYPE_68010, M68K_CPU_TYPE_EC020, and M68K_CPU_TYPE_68020.
*/
void m68k_set_cpu_type(unsigned int cpu_type);
/* Do whatever initialisations the core requires. Should be called
* at least once at init time.
*/
void m68k_init(void);
/* Pulse the RESET pin on the CPU.
* You *MUST* reset the CPU at least once to initialize the emulation
* Note: If you didn't call m68k_set_cpu_type() before resetting
* the CPU for the first time, the CPU will be set to
* M68K_CPU_TYPE_68000.
*/
void m68k_pulse_reset(void);
/* execute num_cycles worth of instructions. returns number of cycles used */
int m68k_execute(int num_cycles);
/* 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 */
/* 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.
*/
void m68k_set_irq(unsigned int int_level);
/* Halt the CPU as if you pulsed the HALT pin. */
void m68k_pulse_halt(void);
/* Context switching to allow multiple CPUs */
/* Get the size of the cpu context in bytes */
unsigned int m68k_context_size(void);
/* Get a cpu context */
unsigned int m68k_get_context(void* dst);
/* set the current cpu context */
void m68k_set_context(void* dst);
/* Register the CPU state information */
void m68k_state_register(const char *type);
/* 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);
/* Poke values into the internals of the currently running CPU context */
void m68k_set_reg(m68k_register_t reg, unsigned int value);
/* 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);
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ======================================================================== */
/* Import the configuration for this build */
#include "m68kconf.h"
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#ifdef __cplusplus
}
#endif
#endif /* M68K__HEADER */

10489
Src/CPU/68K/Musashi/m68k_in.c Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,237 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* m68kconf.h
*
* Musashi configuration.
*
* Permission was obtained from Karl Stenerud to apply the GPL license to this
* code.
*/
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
/*
* MUSASHI
* Version 3.3
*
* A portable Motorola M680x0 processor emulation engine.
* Copyright 1998-2001 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 lisencing terms must be negotiated with the author
* (Karl Stenerud).
*
* The latest version of this code can be obtained at:
* http://kstenerud.cjb.net
*/
#ifndef M68KCONF__HEADER
#define M68KCONF__HEADER
#define M68K_COMPILE_FOR_MAME OPT_OFF
/* Configuration switches.
* Use OPT_SPECIFY_HANDLER for configuration options that allow callbacks.
* OPT_SPECIFY_HANDLER causes the core to link directly to the function
* or macro you specify, rather than using callback functions whose pointer
* must be passed in using m68k_set_xxx_callback().
*/
#define OPT_OFF 0
#define OPT_ON 1
#define OPT_SPECIFY_HANDLER 2
/* ======================================================================== */
/* ============================= CONFIGURATION ============================ */
/* ======================================================================== */
/* Turn ON if you want to use the following M68K variants */
#define M68K_EMULATE_008 OPT_OFF
#define M68K_EMULATE_010 OPT_OFF
#define M68K_EMULATE_EC020 OPT_OFF
#define M68K_EMULATE_020 OPT_OFF
/* If ON, the CPU will call m68k_read_immediate_xx() for immediate addressing
* and m68k_read_pcrelative_xx() for PC-relative addressing.
* If off, all read requests from the CPU will be redirected to m68k_read_xx()
*/
#define M68K_SEPARATE_READS OPT_OFF
/* If ON, the CPU will call m68k_write_32_pd() when it executes move.l with a
* predecrement destination EA mode instead of m68k_write_32().
* To simulate real 68k behavior, m68k_write_32_pd() must first write the high
* word to [address+2], and then write the low word to [address].
*/
#define M68K_SIMULATE_PD_WRITES OPT_OFF
/* If ON, CPU will call the interrupt acknowledge callback when it services an
* interrupt.
* If off, all interrupts will be autovectored and all interrupt requests will
* auto-clear when the interrupt is serviced.
*/
#define M68K_EMULATE_INT_ACK OPT_SPECIFY_HANDLER
#define M68K_INT_ACK_CALLBACK(A) M68KIRQCallback(A)
/* If ON, CPU will call the breakpoint acknowledge callback when it encounters
* a breakpoint instruction and it is running a 68010+.
*/
#define M68K_EMULATE_BKPT_ACK OPT_OFF
#define M68K_BKPT_ACK_CALLBACK() your_bkpt_ack_handler_function()
/* If ON, the CPU will monitor the trace flags and take trace exceptions
*/
#define M68K_EMULATE_TRACE OPT_OFF
/* If ON, CPU will call the output reset callback when it encounters a reset
* instruction.
*/
#define M68K_EMULATE_RESET OPT_OFF
#define M68K_RESET_CALLBACK() M68KResetCallback()
/* If ON, CPU will call the callback when it encounters a cmpi.l #v, dn
* instruction.
*/
#define M68K_CMPILD_HAS_CALLBACK OPT_OFF
#define M68K_CMPILD_CALLBACK(v,r) your_cmpild_handler_function(v,r)
/* If ON, CPU will call the callback when it encounters a rte
* instruction.
*/
#define M68K_RTE_HAS_CALLBACK OPT_OFF
#define M68K_RTE_CALLBACK() your_rte_handler_function()
/* If ON, CPU will call the set fc callback on every memory access to
* differentiate between user/supervisor, program/data access like a real
* 68000 would. This should be enabled and the callback should be set if you
* want to properly emulate the m68010 or higher. (moves uses function codes
* to read/write data from different address spaces)
*/
#define M68K_EMULATE_FC OPT_OFF
#define M68K_SET_FC_CALLBACK(A) your_set_fc_handler_function(A)
/* If ON, CPU will call the pc changed callback when it changes the PC by a
* large value. This allows host programs to be nicer when it comes to
* fetching immediate data and instructions on a banked memory system.
*/
#define M68K_MONITOR_PC OPT_OFF
#define M68K_SET_PC_CALLBACK(A) your_pc_changed_handler_function(A)
/* If ON, CPU will call the instruction hook callback before every
* instruction.
*/
#define M68K_INSTRUCTION_HOOK OPT_OFF
#define M68K_INSTRUCTION_CALLBACK() your_instruction_hook_function()
/* If ON, the CPU will emulate the 4-byte prefetch queue of a real 68000 */
#define M68K_EMULATE_PREFETCH OPT_OFF
/* If ON, the CPU will generate address error exceptions if it tries to
* access a word or longword at an odd address.
* NOTE: This is only emulated properly for 68000 mode.
*/
#define M68K_EMULATE_ADDRESS_ERROR OPT_OFF
/* Turn ON to enable logging of illegal instruction calls.
* M68K_LOG_FILEHANDLE must be #defined to a stdio file stream.
* Turn on M68K_LOG_1010_1111 to log all 1010 and 1111 calls.
*/
#define M68K_LOG_ENABLE OPT_OFF
#define M68K_LOG_1010_1111 OPT_OFF
#define M68K_LOG_FILEHANDLE some_file_handle
/* ----------------------------- COMPATIBILITY ---------------------------- */
/* The following options set optimizations that violate the current ANSI
* standard, but will be compliant under the forthcoming C9X standard.
*/
/* If ON, the enulation core will use 64-bit integers to speed up some
* operations.
*/
#define M68K_USE_64_BIT OPT_ON
/* Set to your compiler's static inline keyword to enable it, or
* set it to blank to disable it.
* If you define INLINE in the makefile, it will override this value.
* NOTE: not enabling inline functions will SEVERELY slow down emulation.
*/
#ifndef INLINE
#define INLINE static __inline__ // defined for GCC; if using MSVC, pass INLINE as "static __inline" from Makefile
#endif /* INLINE */
/******************************************************************************
Supermodel Interface
******************************************************************************/
#include "../M68K.h" // Supermodel's 68K interface
/* Read data relative to the PC */
#define m68k_read_pcrelative_8(address) M68KFetch8(address)
#define m68k_read_pcrelative_16(address) M68KFetch16(address)
#define m68k_read_pcrelative_32(address) M68KFetch32(address)
/* Read data immediately following the PC */
#define m68k_read_immediate_16(address) M68KFetch16(address)
#define m68k_read_immediate_32(address) M68KFetch32(address)
/* Memory access for the disassembler */
#define m68k_read_disassembler_8(address) M68KRead8(address)
#define m68k_read_disassembler_16(address) M68KRead16(address)
#define m68k_read_disassembler_32(address) M68KRead32(address)
/* Read from anywhere */
#define m68k_read_memory_8(address) M68KRead8(address)
#define m68k_read_memory_16(address) M68KRead16(address)
#define m68k_read_memory_32(address) M68KRead32(address)
/* Write to anywhere */
#define m68k_write_memory_8(address, value) M68KWrite8(address, value)
#define m68k_write_memory_16(address, value) M68KWrite16(address, value)
#define m68k_write_memory_32(address, value) M68KWrite32(address, value)
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */
#endif /* M68KCONF__HEADER */

View file

@ -0,0 +1,953 @@
/**
** Supermodel
** A Sega Model 3 Arcade Emulator.
** Copyright 2011 Bart Trzynadlowski
**
** This file is part of Supermodel.
**
** Supermodel is free software: you can redistribute it and/or modify it under
** the terms of the GNU General Public License as published by the Free
** Software Foundation, either version 3 of the License, or (at your option)
** any later version.
**
** Supermodel is distributed in the hope that it will be useful, but WITHOUT
** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
** FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
** more details.
**
** You should have received a copy of the GNU General Public License along
** with Supermodel. If not, see <http://www.gnu.org/licenses/>.
**/
/*
* m68kcpu.c
*
* Musashi core functions and interface.
*
* Permission was obtained from Karl Stenerud to apply the GPL license to this
* code.
*/
/* ======================================================================== */
/* ========================= LICENSING & COPYRIGHT ======================== */
/* ======================================================================== */
#if 1
static const char* copyright_notice =
"MUSASHI\n"
"Version 3.3 (2001-01-29)\n"
"A portable Motorola M680x0 processor emulation engine.\n"
"Copyright 1998-2001 Karl Stenerud. All rights reserved.\n"
"\n"
"This code may be freely used for non-commercial purpooses as long as this\n"
"copyright notice remains unaltered in the source code and any binary files\n"
"containing this code in compiled form.\n"
"\n"
"All other lisencing terms must be negotiated with the author\n"
"(Karl Stenerud).\n"
"\n"
"The latest version of this code can be obtained at:\n"
"http://kstenerud.cjb.net\n"
;
#endif
/* ======================================================================== */
/* ================================= NOTES ================================ */
/* ======================================================================== */
/* ======================================================================== */
/* ================================ INCLUDES ============================== */
/* ======================================================================== */
#include "m68kops.h"
#include "m68kcpu.h"
/* ======================================================================== */
/* ================================= DATA ================================= */
/* ======================================================================== */
int m68ki_initial_cycles;
int m68ki_remaining_cycles = 0; /* Number of clocks remaining */
uint m68ki_tracing = 0;
uint m68ki_address_space;
#ifdef M68K_LOG_ENABLE
const char* m68ki_cpu_names[] =
{
"Invalid CPU",
"M68000",
"M68008",
"Invalid CPU",
"M68010",
"Invalid CPU",
"Invalid CPU",
"Invalid CPU",
"M68EC020",
"Invalid CPU",
"Invalid CPU",
"Invalid CPU",
"Invalid CPU",
"Invalid CPU",
"Invalid CPU",
"Invalid CPU",
"M68020"
};
#endif /* M68K_LOG_ENABLE */
/* The CPU core */
m68ki_cpu_core m68ki_cpu = {0};
#if M68K_EMULATE_ADDRESS_ERROR
jmp_buf m68ki_aerr_trap;
#endif /* M68K_EMULATE_ADDRESS_ERROR */
uint m68ki_aerr_address;
uint m68ki_aerr_write_mode;
uint m68ki_aerr_fc;
/* Used by shift & rotate instructions */
uint8 m68ki_shift_8_table[65] =
{
0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff
};
uint16 m68ki_shift_16_table[65] =
{
0x0000, 0x8000, 0xc000, 0xe000, 0xf000, 0xf800, 0xfc00, 0xfe00, 0xff00,
0xff80, 0xffc0, 0xffe0, 0xfff0, 0xfff8, 0xfffc, 0xfffe, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
0xffff, 0xffff
};
uint m68ki_shift_32_table[65] =
{
0x00000000, 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, 0xf8000000,
0xfc000000, 0xfe000000, 0xff000000, 0xff800000, 0xffc00000, 0xffe00000,
0xfff00000, 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, 0xffff8000,
0xffffc000, 0xffffe000, 0xfffff000, 0xfffff800, 0xfffffc00, 0xfffffe00,
0xffffff00, 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, 0xfffffff8,
0xfffffffc, 0xfffffffe, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff
};
/* Number of clock cycles to use for exception processing.
* I used 4 for any vectors that are undocumented for processing times.
*/
uint8 m68ki_exception_cycle_table[3][256] =
{
{ /* 000 */
4, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
34, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero -- ASG: changed from 42 */
40, /* 6: CHK -- ASG: chanaged from 44 */
34, /* 7: TRAPV */
34, /* 8: Privilege Violation */
34, /* 9: Trace */
4, /* 10: 1010 */
4, /* 11: 1111 */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation (unemulated) */
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 */
44, /* 24: Spurious Interrupt */
44, /* 25: Level 1 Interrupt Autovector */
44, /* 26: Level 2 Interrupt Autovector */
44, /* 27: Level 3 Interrupt Autovector */
44, /* 28: Level 4 Interrupt Autovector */
44, /* 29: Level 5 Interrupt Autovector */
44, /* 30: Level 6 Interrupt Autovector */
44, /* 31: Level 7 Interrupt Autovector */
34, /* 32: TRAP #0 -- ASG: chanaged from 38 */
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 (unemulated) */
4, /* 49: FP Inexact Result (unemulated) */
4, /* 50: FP Divide by Zero (unemulated) */
4, /* 51: FP Underflow (unemulated) */
4, /* 52: FP Operand Error (unemulated) */
4, /* 53: FP Overflow (unemulated) */
4, /* 54: FP Signaling NAN (unemulated) */
4, /* 55: FP Unimplemented Data Type (unemulated) */
4, /* 56: MMU Configuration Error (unemulated) */
4, /* 57: MMU Illegal Operation Error (unemulated) */
4, /* 58: MMU Access Level Violation Error (unemulated) */
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
},
{ /* 010 */
4, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
126, /* 2: Bus Error (unemulated) */
126, /* 3: Address Error (unemulated) */
38, /* 4: Illegal Instruction */
44, /* 5: Divide by Zero */
44, /* 6: CHK */
34, /* 7: TRAPV */
38, /* 8: Privilege Violation */
38, /* 9: Trace */
4, /* 10: 1010 */
4, /* 11: 1111 */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation (unemulated) */
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 */
46, /* 24: Spurious Interrupt */
46, /* 25: Level 1 Interrupt Autovector */
46, /* 26: Level 2 Interrupt Autovector */
46, /* 27: Level 3 Interrupt Autovector */
46, /* 28: Level 4 Interrupt Autovector */
46, /* 29: Level 5 Interrupt Autovector */
46, /* 30: Level 6 Interrupt Autovector */
46, /* 31: Level 7 Interrupt Autovector */
38, /* 32: TRAP #0 */
38, /* 33: TRAP #1 */
38, /* 34: TRAP #2 */
38, /* 35: TRAP #3 */
38, /* 36: TRAP #4 */
38, /* 37: TRAP #5 */
38, /* 38: TRAP #6 */
38, /* 39: TRAP #7 */
38, /* 40: TRAP #8 */
38, /* 41: TRAP #9 */
38, /* 42: TRAP #10 */
38, /* 43: TRAP #11 */
38, /* 44: TRAP #12 */
38, /* 45: TRAP #13 */
38, /* 46: TRAP #14 */
38, /* 47: TRAP #15 */
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
4, /* 49: FP Inexact Result (unemulated) */
4, /* 50: FP Divide by Zero (unemulated) */
4, /* 51: FP Underflow (unemulated) */
4, /* 52: FP Operand Error (unemulated) */
4, /* 53: FP Overflow (unemulated) */
4, /* 54: FP Signaling NAN (unemulated) */
4, /* 55: FP Unimplemented Data Type (unemulated) */
4, /* 56: MMU Configuration Error (unemulated) */
4, /* 57: MMU Illegal Operation Error (unemulated) */
4, /* 58: MMU Access Level Violation Error (unemulated) */
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
},
{ /* 020 */
4, /* 0: Reset - Initial Stack Pointer */
4, /* 1: Reset - Initial Program Counter */
50, /* 2: Bus Error (unemulated) */
50, /* 3: Address Error (unemulated) */
20, /* 4: Illegal Instruction */
38, /* 5: Divide by Zero */
40, /* 6: CHK */
20, /* 7: TRAPV */
34, /* 8: Privilege Violation */
25, /* 9: Trace */
20, /* 10: 1010 */
20, /* 11: 1111 */
4, /* 12: RESERVED */
4, /* 13: Coprocessor Protocol Violation (unemulated) */
4, /* 14: Format Error */
30, /* 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 */
30, /* 24: Spurious Interrupt */
30, /* 25: Level 1 Interrupt Autovector */
30, /* 26: Level 2 Interrupt Autovector */
30, /* 27: Level 3 Interrupt Autovector */
30, /* 28: Level 4 Interrupt Autovector */
30, /* 29: Level 5 Interrupt Autovector */
30, /* 30: Level 6 Interrupt Autovector */
30, /* 31: Level 7 Interrupt Autovector */
20, /* 32: TRAP #0 */
20, /* 33: TRAP #1 */
20, /* 34: TRAP #2 */
20, /* 35: TRAP #3 */
20, /* 36: TRAP #4 */
20, /* 37: TRAP #5 */
20, /* 38: TRAP #6 */
20, /* 39: TRAP #7 */
20, /* 40: TRAP #8 */
20, /* 41: TRAP #9 */
20, /* 42: TRAP #10 */
20, /* 43: TRAP #11 */
20, /* 44: TRAP #12 */
20, /* 45: TRAP #13 */
20, /* 46: TRAP #14 */
20, /* 47: TRAP #15 */
4, /* 48: FP Branch or Set on Unknown Condition (unemulated) */
4, /* 49: FP Inexact Result (unemulated) */
4, /* 50: FP Divide by Zero (unemulated) */
4, /* 51: FP Underflow (unemulated) */
4, /* 52: FP Operand Error (unemulated) */
4, /* 53: FP Overflow (unemulated) */
4, /* 54: FP Signaling NAN (unemulated) */
4, /* 55: FP Unimplemented Data Type (unemulated) */
4, /* 56: MMU Configuration Error (unemulated) */
4, /* 57: MMU Illegal Operation Error (unemulated) */
4, /* 58: MMU Access Level Violation Error (unemulated) */
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
}
};
uint8 m68ki_ea_idx_cycle_table[64] =
{
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, /* ..01.000 no memory indirect, base NULL */
5, /* ..01..01 memory indirect, base NULL, outer NULL */
7, /* ..01..10 memory indirect, base NULL, outer 16 */
7, /* ..01..11 memory indirect, base NULL, outer 32 */
0, 5, 7, 7, 0, 5, 7, 7, 0, 5, 7, 7,
2, /* ..10.000 no memory indirect, base 16 */
7, /* ..10..01 memory indirect, base 16, outer NULL */
9, /* ..10..10 memory indirect, base 16, outer 16 */
9, /* ..10..11 memory indirect, base 16, outer 32 */
0, 7, 9, 9, 0, 7, 9, 9, 0, 7, 9, 9,
6, /* ..11.000 no memory indirect, base 32 */
11, /* ..11..01 memory indirect, base 32, outer NULL */
13, /* ..11..10 memory indirect, base 32, outer 16 */
13, /* ..11..11 memory indirect, base 32, outer 32 */
0, 11, 13, 13, 0, 11, 13, 13, 0, 11, 13, 13
};
/* ======================================================================== */
/* =============================== CALLBACKS ============================== */
/* ======================================================================== */
/* Default callbacks used if the callback hasn't been set yet, or if the
* callback is set to NULL
*/
/* Interrupt acknowledge */
static int default_int_ack_callback_data;
static int default_int_ack_callback(int int_level)
{
default_int_ack_callback_data = int_level;
CPU_INT_LEVEL = 0;
return M68K_INT_ACK_AUTOVECTOR;
}
/* Breakpoint acknowledge */
static unsigned int default_bkpt_ack_callback_data;
static void default_bkpt_ack_callback(unsigned int data)
{
default_bkpt_ack_callback_data = data;
}
/* Called when a reset instruction is executed */
static void default_reset_instr_callback(void)
{
}
/* Called when a cmpi.l #v, dn instruction is executed */
static void default_cmpild_instr_callback(unsigned int val, int reg)
{
}
/* Called when a rte instruction is executed */
static void default_rte_instr_callback(void)
{
}
/* Called when the program counter changed by a large value */
static unsigned int default_pc_changed_callback_data;
static void default_pc_changed_callback(unsigned int new_pc)
{
default_pc_changed_callback_data = new_pc;
}
/* Called every time there's bus activity (read/write to/from memory */
static unsigned int default_set_fc_callback_data;
static void default_set_fc_callback(unsigned int new_fc)
{
default_set_fc_callback_data = new_fc;
}
/* Called every instruction cycle prior to execution */
static void default_instr_hook_callback(void)
{
}
#if M68K_EMULATE_ADDRESS_ERROR
#include <setjmp.h>
jmp_buf m68ki_aerr_trap;
#endif /* M68K_EMULATE_ADDRESS_ERROR */
/* ======================================================================== */
/* ================================= API ================================== */
/* ======================================================================== */
/* Access the internals of the CPU */
unsigned int m68k_get_reg(void* context, m68k_register_t regnum)
{
m68ki_cpu_core* cpu = context != NULL ?(m68ki_cpu_core*)context : &m68ki_cpu;
switch(regnum)
{
case M68K_REG_D0: return cpu->dar[0];
case M68K_REG_D1: return cpu->dar[1];
case M68K_REG_D2: return cpu->dar[2];
case M68K_REG_D3: return cpu->dar[3];
case M68K_REG_D4: return cpu->dar[4];
case M68K_REG_D5: return cpu->dar[5];
case M68K_REG_D6: return cpu->dar[6];
case M68K_REG_D7: return cpu->dar[7];
case M68K_REG_A0: return cpu->dar[8];
case M68K_REG_A1: return cpu->dar[9];
case M68K_REG_A2: return cpu->dar[10];
case M68K_REG_A3: return cpu->dar[11];
case M68K_REG_A4: return cpu->dar[12];
case M68K_REG_A5: return cpu->dar[13];
case M68K_REG_A6: return cpu->dar[14];
case M68K_REG_A7: return cpu->dar[15];
case M68K_REG_PC: return MASK_OUT_ABOVE_32(cpu->pc);
case M68K_REG_SR: return cpu->t1_flag |
cpu->t0_flag |
(cpu->s_flag << 11) |
(cpu->m_flag << 11) |
cpu->int_mask |
((cpu->x_flag & XFLAG_SET) >> 4) |
((cpu->n_flag & NFLAG_SET) >> 4) |
((!cpu->not_z_flag) << 2) |
((cpu->v_flag & VFLAG_SET) >> 6) |
((cpu->c_flag & CFLAG_SET) >> 8);
case M68K_REG_SP: return cpu->dar[15];
case M68K_REG_USP: return cpu->s_flag ? cpu->sp[0] : cpu->dar[15];
case M68K_REG_ISP: return cpu->s_flag && !cpu->m_flag ? cpu->dar[15] : cpu->sp[4];
case M68K_REG_MSP: return cpu->s_flag && cpu->m_flag ? cpu->dar[15] : cpu->sp[6];
case M68K_REG_SFC: return cpu->sfc;
case M68K_REG_DFC: return cpu->dfc;
case M68K_REG_VBR: return cpu->vbr;
case M68K_REG_CACR: return cpu->cacr;
case M68K_REG_CAAR: return cpu->caar;
case M68K_REG_PREF_ADDR: return cpu->pref_addr;
case M68K_REG_PREF_DATA: return cpu->pref_data;
case M68K_REG_PPC: return MASK_OUT_ABOVE_32(cpu->ppc);
case M68K_REG_IR: return cpu->ir;
case M68K_REG_CPU_TYPE:
switch(cpu->cpu_type)
{
case CPU_TYPE_000: return (unsigned int)M68K_CPU_TYPE_68000;
case CPU_TYPE_008: return (unsigned int)M68K_CPU_TYPE_68008;
case CPU_TYPE_010: return (unsigned int)M68K_CPU_TYPE_68010;
case CPU_TYPE_EC020: return (unsigned int)M68K_CPU_TYPE_68EC020;
case CPU_TYPE_020: return (unsigned int)M68K_CPU_TYPE_68020;
}
return M68K_CPU_TYPE_INVALID;
default: return 0;
}
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 && !FLAG_M)
REG_SP = MASK_OUT_ABOVE_32(value);
else
REG_ISP = MASK_OUT_ABOVE_32(value);
return;
case M68K_REG_MSP: if(FLAG_S && FLAG_M)
REG_SP = MASK_OUT_ABOVE_32(value);
else
REG_MSP = MASK_OUT_ABOVE_32(value);
return;
case M68K_REG_VBR: REG_VBR = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_SFC: REG_SFC = value & 7; return;
case M68K_REG_DFC: REG_DFC = value & 7; return;
case M68K_REG_CACR: REG_CACR = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_CAAR: REG_CAAR = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_PPC: REG_PPC = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_IR: REG_IR = MASK_OUT_ABOVE_16(value); return;
case M68K_REG_PREF_ADDR: CPU_PREF_ADDR = MASK_OUT_ABOVE_32(value); return;
case M68K_REG_CPU_TYPE: m68k_set_cpu_type(value); return;
default: return;
}
}
/* Set the callbacks */
void m68k_set_int_ack_callback(int (*callback)(int int_level))
{
CALLBACK_INT_ACK = callback ? callback : default_int_ack_callback;
}
void m68k_set_bkpt_ack_callback(void (*callback)(unsigned int data))
{
CALLBACK_BKPT_ACK = callback ? callback : default_bkpt_ack_callback;
}
void m68k_set_reset_instr_callback(void (*callback)(void))
{
CALLBACK_RESET_INSTR = callback ? callback : default_reset_instr_callback;
}
void m68k_set_cmpild_instr_callback(void (*callback)(unsigned int, int))
{
CALLBACK_CMPILD_INSTR = callback ? callback : default_cmpild_instr_callback;
}
void m68k_set_rte_instr_callback(void (*callback)(void))
{
CALLBACK_RTE_INSTR = callback ? callback : default_rte_instr_callback;
}
void m68k_set_pc_changed_callback(void (*callback)(unsigned int new_pc))
{
CALLBACK_PC_CHANGED = callback ? callback : default_pc_changed_callback;
}
void m68k_set_fc_callback(void (*callback)(unsigned int new_fc))
{
CALLBACK_SET_FC = callback ? callback : default_set_fc_callback;
}
void m68k_set_instr_hook_callback(void (*callback)(void))
{
CALLBACK_INSTR_HOOK = callback ? callback : default_instr_hook_callback;
}
#include <stdio.h>
/* Set the CPU type. */
void m68k_set_cpu_type(unsigned int cpu_type)
{
switch(cpu_type)
{
case M68K_CPU_TYPE_68000:
CPU_TYPE = CPU_TYPE_000;
CPU_ADDRESS_MASK = 0x00ffffff;
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[0];
CYC_EXCEPTION = m68ki_exception_cycle_table[0];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 2;
CYC_DBCC_F_NOEXP = -2;
CYC_DBCC_F_EXP = 2;
CYC_SCC_R_TRUE = 2;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 3;
CYC_SHIFT = 1;
CYC_RESET = 132;
return;
case M68K_CPU_TYPE_68008:
CPU_TYPE = CPU_TYPE_008;
CPU_ADDRESS_MASK = 0x003fffff;
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[0];
CYC_EXCEPTION = m68ki_exception_cycle_table[0];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 2;
CYC_DBCC_F_NOEXP = -2;
CYC_DBCC_F_EXP = 2;
CYC_SCC_R_TRUE = 2;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 3;
CYC_SHIFT = 1;
CYC_RESET = 132;
return;
case M68K_CPU_TYPE_68010:
CPU_TYPE = CPU_TYPE_010;
CPU_ADDRESS_MASK = 0x00ffffff;
CPU_SR_MASK = 0xa71f; /* T1 -- S -- -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[1];
CYC_EXCEPTION = m68ki_exception_cycle_table[1];
CYC_BCC_NOTAKE_B = -4;
CYC_BCC_NOTAKE_W = 0;
CYC_DBCC_F_NOEXP = 0;
CYC_DBCC_F_EXP = 6;
CYC_SCC_R_TRUE = 0;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 3;
CYC_SHIFT = 1;
CYC_RESET = 130;
return;
case M68K_CPU_TYPE_68EC020:
CPU_TYPE = CPU_TYPE_EC020;
CPU_ADDRESS_MASK = 0x00ffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[2];
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
CYC_DBCC_F_NOEXP = 0;
CYC_DBCC_F_EXP = 4;
CYC_SCC_R_TRUE = 0;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
return;
case M68K_CPU_TYPE_68020:
CPU_TYPE = CPU_TYPE_020;
CPU_ADDRESS_MASK = 0xffffffff;
CPU_SR_MASK = 0xf71f; /* T1 T0 S M -- I2 I1 I0 -- -- -- X N Z V C */
CYC_INSTRUCTION = m68ki_cycles[2];
CYC_EXCEPTION = m68ki_exception_cycle_table[2];
CYC_BCC_NOTAKE_B = -2;
CYC_BCC_NOTAKE_W = 0;
CYC_DBCC_F_NOEXP = 0;
CYC_DBCC_F_EXP = 4;
CYC_SCC_R_TRUE = 0;
CYC_MOVEM_W = 2;
CYC_MOVEM_L = 2;
CYC_SHIFT = 0;
CYC_RESET = 518;
return;
}
}
/* Execute some instructions until we use up num_cycles clock cycles */
/* ASG: removed per-instruction interrupt checks */
int m68k_execute(int num_cycles)
{
/* Make sure we're not stopped */
if(!CPU_STOPPED)
{
/* 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) */
/* Main loop. Keep going until we run out of clock cycles */
do
{
/* 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) */
} while(GET_CYCLES() > 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();
}
/* We get here if the CPU is stopped or halted */
SET_CYCLES(0);
CPU_INT_CYCLES = 0;
return num_cycles;
}
int m68k_cycles_run(void)
{
return m68ki_initial_cycles - GET_CYCLES();
}
int m68k_cycles_remaining(void)
{
return GET_CYCLES();
}
/* Change the timeslice */
void m68k_modify_timeslice(int cycles)
{
m68ki_initial_cycles += cycles;
ADD_CYCLES(cycles);
}
void m68k_end_timeslice(void)
{
m68ki_initial_cycles -= GET_CYCLES();
SET_CYCLES(0);
}
/* ASG: rewrote so that the int_level is a mask of the IPL0/IPL1/IPL2 bits */
/* KS: Modified so that IPL* bits match with mask positions in the SR
* and cleaned out remenants of the interrupt controller.
*/
void m68k_set_irq(unsigned int int_level)
{
uint old_level = CPU_INT_LEVEL;
CPU_INT_LEVEL = int_level << 8;
/* A transition from < 7 to 7 always interrupts (NMI) */
/* Note: Level 7 can also level trigger like a normal IRQ */
if(old_level != 0x0700 && CPU_INT_LEVEL == 0x0700)
m68ki_exception_interrupt(7); /* Edge triggered level 7 (NMI) */
else
m68ki_check_interrupts(); /* Level triggered (IRQ) */
}
void m68k_init(void)
{
static uint emulation_initialized = 0;
/* The first call to this function initializes the opcode handler jump table */
if(!emulation_initialized)
{
m68ki_build_opcode_table();
emulation_initialized = 1;
}
m68k_set_int_ack_callback(NULL);
m68k_set_bkpt_ack_callback(NULL);
m68k_set_reset_instr_callback(NULL);
m68k_set_cmpild_instr_callback(NULL);
m68k_set_rte_instr_callback(NULL);
m68k_set_pc_changed_callback(NULL);
m68k_set_fc_callback(NULL);
m68k_set_instr_hook_callback(NULL);
}
/* Pulse the RESET line on the CPU */
void m68k_pulse_reset(void)
{
/* Clear all stop levels and eat up all remaining cycles */
CPU_STOPPED = 0;
SET_CYCLES(0);
CPU_RUN_MODE = RUN_MODE_BERR_AERR_RESET;
/* 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);
CPU_RUN_MODE = RUN_MODE_NORMAL;
}
/* Pulse the HALT line on the CPU */
void m68k_pulse_halt(void)
{
CPU_STOPPED |= STOP_LEVEL_HALT;
}
/* Get and set the current CPU context */
/* This is to allow for multiple CPUs */
unsigned int m68k_context_size()
{
return sizeof(m68ki_cpu_core);
}
unsigned int m68k_get_context(void* dst)
{
if(dst) *(m68ki_cpu_core*)dst = m68ki_cpu;
return sizeof(m68ki_cpu_core);
}
void m68k_set_context(void* src)
{
if(src) m68ki_cpu = *(m68ki_cpu_core*)src;
}
/* ======================================================================== */
/* ============================== MAME STUFF ============================== */
/* ======================================================================== */
#if M68K_COMPILE_FOR_MAME == OPT_ON
#include "state.h"
static struct {
UINT16 sr;
int stopped;
int halted;
} m68k_substate;
static void m68k_prepare_substate(void)
{
m68k_substate.sr = m68ki_get_sr();
m68k_substate.stopped = (CPU_STOPPED & STOP_LEVEL_STOP) != 0;
m68k_substate.halted = (CPU_STOPPED & STOP_LEVEL_HALT) != 0;
}
static void m68k_post_load(void)
{
m68ki_set_sr_noint_nosp(m68k_substate.sr);
CPU_STOPPED = m68k_substate.stopped ? STOP_LEVEL_STOP : 0
| m68k_substate.halted ? STOP_LEVEL_HALT : 0;
m68ki_jump(REG_PC);
}
void m68k_state_register(const char *type)
{
int cpu = cpu_getactivecpu();
state_save_register_UINT32(type, cpu, "D" , REG_D, 8);
state_save_register_UINT32(type, cpu, "A" , REG_A, 8);
state_save_register_UINT32(type, cpu, "PPC" , &REG_PPC, 1);
state_save_register_UINT32(type, cpu, "PC" , &REG_PC, 1);
state_save_register_UINT32(type, cpu, "USP" , &REG_USP, 1);
state_save_register_UINT32(type, cpu, "ISP" , &REG_ISP, 1);
state_save_register_UINT32(type, cpu, "MSP" , &REG_MSP, 1);
state_save_register_UINT32(type, cpu, "VBR" , &REG_VBR, 1);
state_save_register_UINT32(type, cpu, "SFC" , &REG_SFC, 1);
state_save_register_UINT32(type, cpu, "DFC" , &REG_DFC, 1);
state_save_register_UINT32(type, cpu, "CACR" , &REG_CACR, 1);
state_save_register_UINT32(type, cpu, "CAAR" , &REG_CAAR, 1);
state_save_register_UINT16(type, cpu, "SR" , &m68k_substate.sr, 1);
state_save_register_UINT32(type, cpu, "INT_LEVEL" , &CPU_INT_LEVEL, 1);
state_save_register_UINT32(type, cpu, "INT_CYCLES", &CPU_INT_CYCLES, 1);
state_save_register_int (type, cpu, "STOPPED" , &m68k_substate.stopped);
state_save_register_int (type, cpu, "HALTED" , &m68k_substate.halted);
state_save_register_UINT32(type, cpu, "PREF_ADDR" , &CPU_PREF_ADDR, 1);
state_save_register_UINT32(type, cpu, "PREF_DATA" , &CPU_PREF_DATA, 1);
state_save_register_func_presave(m68k_prepare_substate);
state_save_register_func_postload(m68k_post_load);
}
#endif /* M68K_COMPILE_FOR_MAME */
/* ======================================================================== */
/* ============================== END OF FILE ============================= */
/* ======================================================================== */

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

View file

@ -1900,14 +1900,14 @@ void CModel3::RunFrame(void)
//printf("---*\n");
}
SoundBoard.RunFrame();
IRQ.Deassert(0x40);
// Print out sound command buffer in Scud Race RAM
printf("cmdbuf=%08X %08X %08X %08X %08X %08X %08X %08X\n", Read32(0x100180), Read32(0x100184), Read32(0x100188), Read32(0x10018C), Read32(0x100190), Read32(0x100194), Read32(0x100198), Read32(0x10019C));
#endif
SoundBoard.RunFrame();
IRQ.Deassert(0x40);
// End frame
GPU.EndFrame();
TileGen.EndFrame();

View file

@ -34,178 +34,264 @@ static INT16 leftBuffer[44100/60],rightBuffer[44100/60];
static FILE *soundFP;
/******************************************************************************
Global 68K Access Handlers
The 68K must interface with globally-accessible memory maps and access
handlers. Turbo68K uses the __cdecl calling convention. Note that this is not
explicitly defined for the Turbo68K functions themselves but in case Turbo68K
crashes, this may be the culprit.
68K Access Handlers
******************************************************************************/
// Prototypes for access handlers
#ifdef SUPERMODEL_SOUND
static UINT8 __cdecl UnknownRead8(UINT32);
static UINT16 __cdecl UnknownRead16(UINT32);
static UINT32 __cdecl UnknownRead32(UINT32);
static void __cdecl UnknownWrite8(UINT32, UINT8);
static void __cdecl UnknownWrite16(UINT32, UINT16);
static void __cdecl UnknownWrite32(UINT32, UINT32);
// Memory regions passed out of CSoundBoard object for global access handlers
static UINT8 *sbRAM1, *sbRAM2;
static const UINT8 *sbSoundROM, *sbSampleROM;
// Memory maps for 68K
struct TURBO68K_FETCHREGION mapFetch[] =
{
{ 0x000000, 0x0FFFFF, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL }, // program ROM
{ -1, -1, NULL }
};
struct TURBO68K_DATAREGION mapRead8[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL, NULL }, // program ROM
{ 0x800000, 0x9FFFFF, NULL, NULL }, // sample ROM (low 2 MB)
{ 0xA00000, 0xDFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0xE00000, 0xFFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_r8 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_r8 },
{ 0x000000, 0xFFFFFF, NULL, UnknownRead8 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapRead16[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL, NULL }, // program ROM
{ 0x800000, 0x9FFFFF, NULL, NULL }, // sample ROM (low 2 MB)
{ 0xA00000, 0xDFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0xE00000, 0xFFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_r16 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_r16 },
{ 0x000000, 0xFFFFFF, NULL, UnknownRead16 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapRead32[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x600000, 0x67FFFF, NULL, NULL }, // program ROM
{ 0x800000, 0x9FFFFF, NULL, NULL }, // sample ROM (low 2 MB)
{ 0xA00000, 0xDFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0xE00000, 0xFFFFFF, NULL, NULL }, // sample ROM (bank)
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_r32 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_r32 },
{ 0x000000, 0xFFFFFF, NULL, UnknownRead32 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapWrite8[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_w8 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_w8 },
{ 0x000000, 0xFFFFFF, NULL, UnknownWrite8 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapWrite16[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_w16 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_w16 },
{ 0x000000, 0xFFFFFF, NULL, UnknownWrite16 },
{ -1, -1, NULL, NULL }
};
struct TURBO68K_DATAREGION mapWrite32[] =
{
{ 0x000000, 0x0FFFFF, NULL, NULL }, // SCSP1 RAM
{ 0x200000, 0x2FFFFF, NULL, NULL }, // SCSP2 RAM
{ 0x100000, 0x10FFFF, NULL, SCSP_Master_w32 },
{ 0x300000, 0x30FFFF, NULL, SCSP_Slave_w32 },
{ 0x000000, 0xFFFFFF, NULL, UnknownWrite32 },
{ -1, -1, NULL, NULL }
};
static UINT8 __cdecl UnknownRead8(UINT32 addr)
{
printf("68K read from %06X (byte)\n", addr);
return 0;
static UINT8 Read8(UINT32 a)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
return sbRAM1[a^1];
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
return sbRAM2[(a-0x200000)^1];
// Program ROM
else if ((a >= 0x600000) && (a <= 0x67FFFF))
return sbSoundROM[(a-0x600000)^1];
// Sample ROM (low 2MB, fixed)
else if ((a >= 0x800000) && (a <= 0x9FFFFF))
return sbSampleROM[(a-0x800000)^1];
// Sample ROM (bank)
else if ((a >= 0xA00000) && (a <= 0xDFFFFF))
return sbSampleROM[(a-0x800000)^1];
// Sample ROM (bank)
else if ((a >= 0xE00000) && (a <= 0xFFFFFF))
return sbSampleROM[(a-0x800000)^1];
// SCSP (Master)
else if ((a >= 0x100000) && (a <= 0x10FFFF))
return SCSP_Master_r8(a);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
return SCSP_Slave_r8(a);
// Unknown
else
{
printf("68K: Unknown read8 %06X\n", a);
return 0;
}
}
static UINT16 __cdecl UnknownRead16(UINT32 addr)
{
printf("68K read from %06X (word)\n", addr);
return 0;
static UINT16 Read16(UINT32 a)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
return *(UINT16 *) &sbRAM1[a];
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
return *(UINT16 *) &sbRAM2[(a-0x200000)];
// Program ROM
else if ((a >= 0x600000) && (a <= 0x67FFFF))
return *(UINT16 *) &sbSoundROM[(a-0x600000)];
// Sample ROM (low 2MB, fixed)
else if ((a >= 0x800000) && (a <= 0x9FFFFF))
return *(UINT16 *) &sbSampleROM[(a-0x800000)];
// Sample ROM (bank)
else if ((a >= 0xA00000) && (a <= 0xDFFFFF))
return *(UINT16 *) &sbSampleROM[(a-0x800000)];
// Sample ROM (bank)
else if ((a >= 0xE00000) && (a <= 0xFFFFFF))
return *(UINT16 *) &sbSampleROM[(a-0x800000)];
// SCSP (Master)
else if ((a >= 0x100000) && (a <= 0x10FFFF))
return SCSP_Master_r16(a);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
return SCSP_Slave_r16(a);
// Unknown
else
{
printf("68K: Unknown read16 %06X\n", a);
return 0;
}
}
static UINT32 __cdecl UnknownRead32(UINT32 addr)
{
printf("68K read from %06X (longword)\n", addr);
return 0;
static UINT32 Read32(UINT32 a)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
return (Read16(a)<<16)|Read16(a+2);
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
return (Read16(a)<<16)|Read16(a+2);
// Program ROM
else if ((a >= 0x600000) && (a <= 0x67FFFF))
return (Read16(a)<<16)|Read16(a+2);
// Sample ROM (low 2MB, fixed)
else if ((a >= 0x800000) && (a <= 0x9FFFFF))
return (Read16(a)<<16)|Read16(a+2);
// Sample ROM (bank)
else if ((a >= 0xA00000) && (a <= 0xDFFFFF))
return (Read16(a)<<16)|Read16(a+2);
// Sample ROM (bank)
else if ((a >= 0xE00000) && (a <= 0xFFFFFF))
return (Read16(a)<<16)|Read16(a+2);
// SCSP (Master)
else if ((a >= 0x100000) && (a <= 0x10FFFF))
return SCSP_Master_r32(a);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
return SCSP_Slave_r32(a);
// Unknown
else
{
printf("68K: Unknown read32 %06X\n", a);
return 0;
}
}
static void __cdecl UnknownWrite8(UINT32 addr, UINT8 data)
{
printf("68K wrote %06X=%02X\n", addr, data);
static void Write8 (unsigned int a,unsigned char d)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
sbRAM1[a^1] = d;
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
sbRAM2[(a-0x200000)^1] = d;
// SCSP (Master)
else if ((a >= 0x100000) && (a <= 0x10FFFF))
SCSP_Master_w8(a,d);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
SCSP_Slave_w8(a,d);
// Unknown
else
printf("68K: Unknown write8 %06X=%02X\n", a, d);
}
static void __cdecl UnknownWrite16(UINT32 addr, UINT16 data)
{
printf("68K wrote %06X=%04X\n", addr, data);
static void Write16(unsigned int a,unsigned short d)
{
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
*(UINT16 *) &sbRAM1[a] = d;
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
*(UINT16 *) &sbRAM2[(a-0x200000)] = d;
// SCSP (Master)
else if ((a >= 0x100000) && (a <= 0x10FFFF))
SCSP_Master_w16(a,d);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
SCSP_Slave_w16(a,d);
// Unknown
else
printf("68K: Unknown write16 %06X=%04X\n", a, d);
}
static void __cdecl UnknownWrite32(UINT32 addr, UINT32 data)
static void Write32(unsigned int a,unsigned int d)
{
printf("68K wrote %06X=%08X\n", addr, data);
// SCSP RAM 1
if ((a >= 0x000000) && (a <= 0x0FFFFF))
{
Write16(a,d>>16);
Write16(a+2,d&0xFFFF);
}
// SCSP RAM 2
else if ((a >= 0x200000) && (a <= 0x2FFFFF))
{
Write16(a,d>>16);
Write16(a+2,d&0xFFFF);
}
// SCSP (Master)
else if ((a >= 0x100000) && (a <= 0x10FFFF))
SCSP_Master_w32(a,d);
// SCSP (Slave)
else if ((a >= 0x300000) && (a <= 0x30FFFF))
SCSP_Slave_w32(a,d);
// Unknown
else
printf("68K: Unknown write32 %06X=%08X\n", a, d);
}
#endif
/******************************************************************************
Emulation Functions
SCSP 68K Callbacks
The SCSP emulator drives the 68K via callbacks.
******************************************************************************/
int irqLine = 0;
// Status of IRQ pins (IPL2-0) on 68K
static int irqLine = 0;
// Interrupt acknowledge callback (TODO: don't need this, default behavior in M68K.cpp is fine)
int IRQAck(int irqLevel)
{
M68KSetIRQ(0);
irqLine = 0;
return M68K_IRQ_AUTOVECTOR;
}
// SCSP callback for generating IRQs
void SCSP68KIRQCallback(int irqNum)
void SCSP68KIRQCallback(int irqLevel)
{
#ifdef SUPERMODEL_SOUND
//printf("IRQ: %d\n", irqNum);
irqLine = irqNum;
//Turbo68KInterrupt(irqNum, TURBO68K_AUTOVECTOR);
#endif
/*
* IRQ arbitration logic: only allow higher priority IRQs to be asserted or
* 0 to clear pending IRQ.
*/
if ((irqLevel>irqLine) || (0==irqLevel))
{
irqLine = irqLevel;
}
M68KSetIRQ(irqLine);
}
// SCSP callback for running the 68K
int SCSP68KRunCallback(int numCycles)
{
#ifdef SUPERMODEL_SOUND
for (int i = 0; i < numCycles; i++)
{
if (irqLine)
Turbo68KInterrupt(irqLine,TURBO68K_AUTOVECTOR);
Turbo68KRun(1);
}
return numCycles;
//Turbo68KRun(numCycles);
//return Turbo68KGetElapsedCycles();
#else
return numCycles;
#endif
return M68KRun(numCycles);
}
/******************************************************************************
Sound Board Emulation
******************************************************************************/
void CSoundBoard::WriteMIDIPort(UINT8 data)
{
#ifdef SUPERMODEL_SOUND
SCSP_MidiIn(data);
#endif
}
void CSoundBoard::RunFrame(void)
@ -227,18 +313,8 @@ void CSoundBoard::RunFrame(void)
void CSoundBoard::Reset(void)
{
#ifdef SUPERMODEL_SOUND
memcpy(ram1, soundROM, 16); // copy 68K vector table
Turbo68KReset();
/*
printf("68K PC=%06X\n", Turbo68KReadPC());
for (int i = 0; i < 1000000; i++)
{
//printf("%06X\n", Turbo68KReadPC());
Turbo68KRun(1);
}
*/
#endif
M68KReset();
DebugLog("Sound Board Reset\n");
}
@ -248,13 +324,12 @@ void CSoundBoard::Reset(void)
******************************************************************************/
// Offsets of memory regions within sound board's pool
#define OFFSET_RAM1 0 // 1 MB SCSP1 RAM
#define OFFSET_RAM2 0x100000 // 1 MB SCSP2 RAM
#define OFFSETsbRAM1 0 // 1 MB SCSP1 RAM
#define OFFSETsbRAM2 0x100000 // 1 MB SCSP2 RAM
#define MEMORY_POOL_SIZE (0x100000+0x100000)
BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ *ppcIRQObjectPtr, unsigned soundIRQBit)
{
#ifdef SUPERMODEL_SOUND
float memSizeMB = (float)MEMORY_POOL_SIZE/(float)0x100000;
// Attach IRQ controller
@ -272,33 +347,28 @@ BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ
memset(memoryPool, 0, MEMORY_POOL_SIZE);
// Set up memory pointers
ram1 = &memoryPool[OFFSET_RAM1];
ram2 = &memoryPool[OFFSET_RAM2];
ram1 = &memoryPool[OFFSETsbRAM1];
ram2 = &memoryPool[OFFSETsbRAM2];
// Make global copies of memory pointers for 68K access handlers
sbRAM1 = ram1;
sbRAM2 = ram2;
sbSoundROM = soundROM;
sbSampleROM = sampleROM;
// Initialize 68K core
mapFetch[0].ptr = mapRead8[0].ptr = mapRead16[0].ptr = mapRead32[0].ptr =
mapWrite8[0].ptr = mapWrite16[0].ptr = mapWrite32[0].ptr = (UINT32)ram1 - mapFetch[0].base;;
mapFetch[1].ptr = mapRead8[1].ptr = mapRead16[1].ptr = mapRead32[1].ptr =
mapWrite8[1].ptr = mapWrite16[1].ptr = mapWrite32[1].ptr = (UINT32)ram2 - mapFetch[1].base;
mapFetch[2].ptr = mapRead8[2].ptr = mapRead16[2].ptr = mapRead32[2].ptr = (UINT32)soundROM - mapFetch[2].base;
mapRead8[3].ptr = mapRead16[3].ptr = mapRead32[3].ptr = (UINT32)&sampleROM[0x000000] - mapRead8[3].base;
mapRead8[4].ptr = mapRead16[4].ptr = mapRead32[4].ptr = (UINT32)&sampleROM[0x200000] - mapRead8[4].base;
mapRead8[5].ptr = mapRead16[5].ptr = mapRead32[5].ptr = (UINT32)&sampleROM[0x600000] - mapRead8[5].base;
Turbo68KInit();
Turbo68KSetFetch(mapFetch, NULL);
Turbo68KSetReadByte(mapRead8, NULL);
Turbo68KSetReadWord(mapRead16, NULL);
Turbo68KSetReadLong(mapRead32, NULL);
Turbo68KSetWriteByte(mapWrite8, NULL);
Turbo68KSetWriteWord(mapWrite16, NULL);
Turbo68KSetWriteLong(mapWrite32, NULL);
M68KInit();
M68KSetIRQCallback(IRQAck);
M68KSetFetch8Callback(Read8);
M68KSetFetch16Callback(Read16);
M68KSetFetch32Callback(Read32);
M68KSetRead8Callback(Read8);
M68KSetRead16Callback(Read16);
M68KSetRead32Callback(Read32);
M68KSetWrite8Callback(Write8);
M68KSetWrite16Callback(Write16);
M68KSetWrite32Callback(Write32);
// Initialize SCSPs
SCSP_SetBuffers(leftBuffer, rightBuffer, 44100/60);
SCSP_SetCB(SCSP68KRunCallback, SCSP68KIRQCallback, ppcIRQ, ppcSoundIRQBit);
@ -307,6 +377,7 @@ BOOL CSoundBoard::Init(const UINT8 *soundROMPtr, const UINT8 *sampleROMPtr, CIRQ
SCSP_SetRAM(1, ram2);
// Binary logging
#ifdef SUPERMODEL_SOUND
soundFP = fopen("sound.bin","wb"); // delete existing file
fclose(soundFP);
soundFP = fopen("sound.bin","ab"); // append mode
@ -364,6 +435,7 @@ CSoundBoard::~CSoundBoard(void)
}
//#endif
#endif
SCSP_Deinit();
@ -374,7 +446,5 @@ CSoundBoard::~CSoundBoard(void)
}
ram1 = NULL;
ram2 = NULL;
#endif
DebugLog("Destroyed Sound Board\n");
}

View file

@ -545,6 +545,9 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsi
SCSP_MidiIn(0xAF);SCSP_MidiIn(0x10);SCSP_MidiIn(0x01);
*/
SCSP_MidiIn(0xAF);SCSP_MidiIn(0x10);SCSP_MidiIn(0x00);
//static int snd=0xF;
//SCSP_MidiIn(0xA0);SCSP_MidiIn(0x11);SCSP_MidiIn(snd++);
//Sound codes:
// A0 11 xx (0F=time extend, 11=jumbo left right)
// AF 10 xx (music -- 01 seems to work)
@ -635,9 +638,6 @@ int Supermodel(const char *zipFile, CInputs *Inputs, unsigned ppcFrequency, unsi
printf("SR%d=%08X\n", i, ppc_read_sr(i));
printf("SDR1=%08X\n", ppc_read_spr(SPR603E_SDR1));
*/
#ifdef SUPERMODEL_SOUND
printf("68K PC =%08X\n", Turbo68KReadPC());
#endif
#endif
return 0;

View file

@ -22,7 +22,9 @@
/*
* Types.h
*
* Fundamental data types.
* Fundamental data types. This file is used by both C++ and C modules, so it
* must NOT include any C++-specific constructs. Some modules may elect to
* include it directly rather than through Supermodel.h.
*/
#ifndef INCLUDED_TYPES_H

View file

@ -738,6 +738,7 @@ void SCSP_UpdateSlotReg(int s,int r)
if(KEYONB(s2) && (!s2->active || (s2->active && s2->EG.state==RELEASE)))
{
DebugLog("KEYON %d",sl);
printf("KEYON %d\n",sl);
SCSP_StartSlot(s2);
}
if(!KEYONB(s2) && s2->active)
@ -880,7 +881,7 @@ void SCSP_UpdateRegR(int reg)
unsigned short v=SCSP->data[0x5/2];
v&=0xff00;
v|=MidiStack[MidiR];
printf("read MIDI\n");
//printf("read MIDI\n");
if(MidiR!=MidiW)
{
++MidiR;
@ -914,6 +915,7 @@ void SCSP_w8(unsigned int addr,unsigned char val)
int slot=addr/0x20;
addr&=0x1f;
DebugLog("Slot %02X Reg %02X write byte %04X",slot,addr^1,val);
printf("Slot %02X Reg %02X write byte %04X\n",slot,addr^1,val);
*((unsigned char *) (SCSP->Slots[slot].datab+(addr^1))) = val;
SCSP_UpdateSlotReg(slot,(addr^1)&0x1f);
}
@ -953,6 +955,7 @@ void SCSP_w16(unsigned int addr,unsigned short val)
int slot=addr/0x20;
addr&=0x1f;
DebugLog("Slot %02X Reg %02X write word %04X",slot,addr,val);
printf("Slot %02X Reg %02X write word %04X\n",slot,addr,val);
*((unsigned short *) (SCSP->Slots[slot].datab+(addr))) = val;
SCSP_UpdateSlotReg(slot,addr&0x1f);
}
@ -992,6 +995,7 @@ void SCSP_w32(unsigned int addr,unsigned int val)
int slot=addr/0x20;
addr&=0x1f;
DebugLog("Slot %02X Reg %02X write dword %08X",slot,addr,val);
printf("Slot %02X Reg %02X write dword %08X\n",slot,addr,val);
_asm rol val,16
*((unsigned int *) (SCSP->Slots[slot].datab+(addr))) = val;
SCSP_UpdateSlotReg(slot,addr&0x1f);

View file

@ -32,7 +32,7 @@
Program-Wide Definitions
******************************************************************************/
#define SUPERMODEL_VERSION "0.2-WIP" // version string
#define SUPERMODEL_VERSION "0.2a-WIP" // version string
/******************************************************************************
@ -63,6 +63,10 @@
* INT8 Signed 8-bit integer.
* FLOAT32 Single-precision, 32-bit floating point number.
* FLOAT64 Double-precision, 64-bit floating point number.
*
* Types.h is used within C++ and C modules, so it must NOT include any C++-
* specific stuff. Some modules may choose to include it directly rather than
* use Supermodel.h, so it must exist.
*/
#include "Types.h"
@ -141,9 +145,7 @@ extern void InfoLog(const char *fmt, ...);
#endif // SUPERMODEL_DEBUGGER
#include "CPU/PowerPC/PPCDisasm.h"
#include "CPU/PowerPC/ppc.h"
#ifdef SUPERMODEL_SOUND
#include "CPU/68K/Turbo68K.h"
#endif // SUPERMODEL_SOUND
#include "CPU/68K/M68K.h"
#include "Inputs/Input.h"
#include "Inputs/Inputs.h"
#include "Inputs/InputSource.h"