fbneo/src/cpu/m6800_intf.cpp

781 lines
16 KiB
C++

#include "burnint.h"
#include "m6800_intf.h"
#include <stddef.h>
#define MAX_CPU 8
INT32 nM6800Count = 0; // note: is 0 when 1 cpu is in use. also, 0 when no cpus are in use.
static INT32 nActiveCPU = -1;
static M6800Ext *M6800CPUContext = NULL;
static INT32 nM6800CyclesDone[MAX_CPU];
static INT32 (*cpu_execute[MAX_CPU])(INT32);
INT32 nM6800CyclesTotal;
cpu_core_config M6800Config = // M6802, M6808
{
"M6800",
M6800CPUPush, //M6800Open,
M6800CPUPop, //M6800Close,
M6800CheatRead,
M6800WriteRom,
M6800GetActive,
M6800TotalCycles,
M6800NewFrame,
M6800Idle,
M6800SetIRQLine,
M6800Run, // different
M6800RunEnd,
M6800Reset,
M6800Scan,
M6800Exit,
0x10000,
0
};
cpu_core_config HD63701Config =
{
"HD63701",
M6800CPUPush, //M6800Open,
M6800CPUPop, //M6800Close,
M6800CheatRead,
M6800WriteRom,
M6800GetActive,
M6800TotalCycles,
M6800NewFrame,
M6800Idle,
M6800SetIRQLine,
HD63701Run, // different
M6800RunEnd,
M6800Reset,
M6800Scan,
M6800Exit,
0x10000,
0
};
cpu_core_config M6803Config = // M6801, M6803
{
"M6803",
M6800CPUPush, //M6800Open,
M6800CPUPop, //M6800Close,
M6800CheatRead,
M6800WriteRom,
M6800GetActive,
M6800TotalCycles,
M6800NewFrame,
M6800Idle,
M6800SetIRQLine,
M6803Run, // different
M6800RunEnd,
M6800Reset,
M6800Scan,
M6800Exit,
0x10000,
0
};
cpu_core_config M6801Config =
{
"M6801",
M6800CPUPush, //M6800Open,
M6800CPUPop, //M6800Close,
M6800CheatRead,
M6800WriteRom,
M6800GetActive,
M6800TotalCycles,
M6800NewFrame,
M6800Idle,
M6800SetIRQLine,
M6803Run, // different
M6800RunEnd,
M6800Reset,
M6800Scan,
M6800Exit,
0x10000,
0
};
cpu_core_config NSC8105Config =
{
"NSC8015",
M6800CPUPush, //M6800Open,
M6800CPUPop, //M6800Close,
M6800CheatRead,
M6800WriteRom,
M6800GetActive,
M6800TotalCycles,
M6800NewFrame,
M6800Idle,
M6800SetIRQLine,
NSC8105Run, // different
M6800RunEnd,
M6800Reset,
M6800Scan,
M6800Exit,
0x10000,
0
};
static UINT8 M6800ReadByteDummyHandler(UINT16)
{
return 0;
}
static void M6800WriteByteDummyHandler(UINT16, UINT8)
{
}
static UINT8 M6800ReadOpDummyHandler(UINT16)
{
return 0;
}
static UINT8 M6800ReadOpArgDummyHandler(UINT16)
{
return 0;
}
static UINT8 M6800ReadPortDummyHandler(UINT16)
{
return 0;
}
static void M6800WritePortDummyHandler(UINT16, UINT8)
{
}
// ## M6800CPUPush() / M6800CPUPop() ## internal helpers for sending signals to other m6800's
struct m6800pstack {
INT32 nHostCPU;
INT32 nPushedCPU;
};
#define MAX_PSTACK 10
static m6800pstack pstack[MAX_PSTACK];
static INT32 pstacknum = 0;
void M6800CPUPush(INT32 nCPU)
{
m6800pstack *p = &pstack[pstacknum++];
if (pstacknum + 1 >= MAX_PSTACK) {
bprintf(0, _T("M6800CPUPush(): out of stack! Possible infinite recursion? Crash pending..\n"));
}
p->nPushedCPU = nCPU;
p->nHostCPU = M6800GetActive();
if (p->nHostCPU != p->nPushedCPU) {
if (p->nHostCPU != -1) M6800Close();
M6800Open(p->nPushedCPU);
}
}
void M6800CPUPop()
{
m6800pstack *p = &pstack[--pstacknum];
if (p->nHostCPU != p->nPushedCPU) {
M6800Close();
if (p->nHostCPU != -1) M6800Open(p->nHostCPU);
}
}
void M6800Reset()
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Reset called without init\n"));
#endif
m6800_reset();
}
void M6800Reset(INT32 nCPU)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Reset called without init\n"));
#endif
M6800CPUPush(nCPU);
M6800Reset();
M6800CPUPop();
}
void M6800SetRESETLine(INT32 nStatus)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetRESETLine called without init\n"));
if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6800SetRESETLine called when no CPU open\n"));
#endif
if (nActiveCPU < 0) return;
if (M6800CPUContext[nActiveCPU].bResetLine && nStatus == 0) {
M6800Reset();
}
M6800CPUContext[nActiveCPU].bResetLine = nStatus;
}
void M6800SetRESETLine(INT32 nCPU, INT32 nStatus)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetRESETLine called without init\n"));
#endif
M6800CPUPush(nCPU);
M6800SetRESETLine(nStatus);
M6800CPUPop();
}
INT32 M6800GetRESETLine()
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800GetRESETLine called without init\n"));
if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6800GetRESETLine called when no CPU open\n"));
#endif
return M6800CPUContext[nActiveCPU].bResetLine;
}
INT32 M6800GetRESETLine(INT32 nCPU)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800GetRESETLine called without init\n"));
#endif
M6800CPUPush(nCPU);
INT32 nRet = M6800GetRESETLine();
M6800CPUPop();
return nRet;
}
void M6800ResetSoft()
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800ResetSoft called without init\n"));
#endif
m6800_reset_soft();
}
void M6800NewFrame()
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800NewFrame called without init\n"));
#endif
for (INT32 i = 0; i <= nM6800Count; i++) {
nM6800CyclesDone[i] = 0;
}
nM6800CyclesTotal = 0;
}
INT32 M6800TotalCycles(INT32 nCPU)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800TotalCycles called without init\n"));
#endif
M6800CPUPush(nCPU);
INT32 nRet = M6800TotalCycles();
M6800CPUPop();
return nRet;
}
INT32 M6800Idle(INT32 nCPU, INT32 nCycles)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Idle called without init\n"));
#endif
M6800CPUPush(nCPU);
INT32 nRet = M6800Idle(nCycles);
M6800CPUPop();
return nRet;
}
UINT8 M6800CheatRead(UINT32 a)
{
return M6800ReadByte(a);
}
void M6800Open(INT32 num)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Open called without init\n"));
if (num > nM6800Count) bprintf(PRINT_ERROR, _T("M6800Open called with invalid index %x\n"), num);
if (nActiveCPU != -1) bprintf(PRINT_ERROR, _T("M6800Open called when CPU already open with index %x\n"), num);
#endif
nActiveCPU = num;
m6800_set_context(&M6800CPUContext[nActiveCPU].reg);
nM6800CyclesTotal = nM6800CyclesDone[nActiveCPU];
}
void M6800Close()
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Close called without init\n"));
if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6800Close called when no CPU open\n"));
#endif
m6800_get_context(&M6800CPUContext[nActiveCPU].reg);
nM6800CyclesDone[nActiveCPU] = nM6800CyclesTotal;
nActiveCPU = -1;
}
INT32 M6800GetActive()
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800GetActive called without init\n"));
//if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6800GetActive called when no CPU open\n"));
#endif
return nActiveCPU;
}
INT32 M6800CoreInit(INT32 num, INT32 type)
{
DebugCPU_M6800Initted = 1;
nActiveCPU = -1;
nM6800Count = num;
if (M6800CPUContext == NULL) {
M6800CPUContext = (M6800Ext*)malloc(MAX_CPU * sizeof(M6800Ext));
if (M6800CPUContext == NULL) {
return 1;
}
memset(M6800CPUContext, 0, MAX_CPU * sizeof(M6800Ext));
for (INT32 i = 0; i < MAX_CPU; i++) {
M6800CPUContext[i].ReadByte = M6800ReadByteDummyHandler;
M6800CPUContext[i].WriteByte = M6800WriteByteDummyHandler;
M6800CPUContext[i].ReadOp = M6800ReadOpDummyHandler;
M6800CPUContext[i].ReadOpArg = M6800ReadOpArgDummyHandler;
M6800CPUContext[i].ReadPort = M6800ReadPortDummyHandler;
M6800CPUContext[i].WritePort = M6800WritePortDummyHandler;
M6800CPUContext[i].bResetLine = 0;
nM6800CyclesDone[i] = 0;
for (INT32 j = 0; j < (0x0100 * 3); j++) {
M6800CPUContext[i].pMemMap[j] = NULL;
}
cpu_execute[i] = NULL;
}
}
nM6800CyclesTotal = 0;
M6800CPUContext[num].nCpuType = type;
M6800Open(num);
if (type == CPU_TYPE_M6800) {
m6800_init();
cpu_execute[num] = m6800_execute;
CpuCheatRegister(num, &M6800Config);
}
if (type == CPU_TYPE_HD63701) {
hd63701_init();
cpu_execute[num] = hd63701_execute;
CpuCheatRegister(num, &HD63701Config);
}
if (type == CPU_TYPE_M6803) {
m6803_init();
cpu_execute[num] = m6803_execute;
CpuCheatRegister(num, &M6803Config);
}
if (type == CPU_TYPE_M6801) {
m6801_init();
cpu_execute[num] = m6803_execute; // really
CpuCheatRegister(num, &M6801Config);
}
if (type == CPU_TYPE_NSC8105) {
nsc8105_init();
cpu_execute[num] = nsc8105_execute;
CpuCheatRegister(num, &NSC8105Config);
}
M6800Close();
return 0;
}
INT32 M6800Init(INT32 num)
{
return M6800CoreInit(num, CPU_TYPE_M6800);
}
INT32 HD63701Init(INT32 num)
{
return M6800CoreInit(num, CPU_TYPE_HD63701);
}
INT32 M6803Init(INT32 num)
{
return M6800CoreInit(num, CPU_TYPE_M6803);
}
INT32 M6801Init(INT32 num)
{
return M6800CoreInit(num, CPU_TYPE_M6801);
}
INT32 NSC8105Init(INT32 num)
{
return M6800CoreInit(num, CPU_TYPE_NSC8105);
}
void M6800Exit()
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Exit called without init\n"));
#endif
nM6800Count = 0;
nActiveCPU = -1;
if (M6800CPUContext) {
free(M6800CPUContext);
M6800CPUContext = NULL;
}
DebugCPU_M6800Initted = 0;
}
void M6800SetIRQLine(INT32 vector, INT32 status)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetIRQLine called without init\n"));
if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6800SetIRQLine called when no CPU open\n"));
#endif
if (status == CPU_IRQSTATUS_NONE) {
m6800_set_irq_line(vector, 0);
}
if (status == CPU_IRQSTATUS_ACK) {
m6800_set_irq_line(vector, 1);
}
if (status == CPU_IRQSTATUS_HOLD) {
m6800_set_irq_line(vector, 2);
}
if (status == CPU_IRQSTATUS_AUTO) {
m6800_set_irq_line(vector, 1);
cpu_execute[nActiveCPU](0);
m6800_set_irq_line(vector, 0);
cpu_execute[nActiveCPU](0);
}
}
void M6800SetIRQLine(INT32 nCPU, const INT32 line, const INT32 status)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetIRQLine called without init\n"));
#endif
M6800CPUPush(nCPU);
M6800SetIRQLine(line, status);
M6800CPUPop();
}
INT32 M6800Run(INT32 cycles)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Run called without init\n"));
if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6800Run called when no CPU open\n"));
#endif
if (!M6800CPUContext[nActiveCPU].bResetLine) {
cycles = cpu_execute[nActiveCPU](cycles);
}
nM6800CyclesTotal += cycles;
return cycles;
}
INT32 M6800Run(INT32 nCPU, INT32 nCycles)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Run called without init\n"));
#endif
M6800CPUPush(nCPU);
INT32 nRet = M6800Run(nCycles);
M6800CPUPop();
return nRet;
}
UINT32 M6800GetPC(INT32)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800GetPC called without init\n"));
#endif
return m6800_get_pc();
}
INT32 M6800MapMemory(UINT8* pMemory, UINT16 nStart, UINT16 nEnd, INT32 nType)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800MapMemory called without init\n"));
if (nActiveCPU == -1) bprintf(PRINT_ERROR, _T("M6800MapMemory called when no CPU open\n"));
#endif
UINT8 cStart = (nStart >> 8);
UINT8 **pMemMap = M6800CPUContext[nActiveCPU].pMemMap;
for (UINT16 i = cStart; i <= (nEnd >> 8); i++) {
if (nType & MAP_READ) {
pMemMap[0 + i] = pMemory + ((i - cStart) << 8);
}
if (nType & MAP_WRITE) {
pMemMap[0x100 + i] = pMemory + ((i - cStart) << 8);
}
if (nType & MAP_FETCH) {
pMemMap[0x200 + i] = pMemory + ((i - cStart) << 8);
}
}
return 0;
}
void M6800SetReadHandler(UINT8 (*pHandler)(UINT16))
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetReadHandler called without init\n"));
#endif
M6800CPUContext[nActiveCPU].ReadByte = pHandler;
}
void M6800SetWriteHandler(void (*pHandler)(UINT16, UINT8))
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetWriteHandler called without init\n"));
#endif
M6800CPUContext[nActiveCPU].WriteByte = pHandler;
}
void M6800SetReadOpHandler(UINT8 (*pHandler)(UINT16))
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetReadOpHandler called without init\n"));
#endif
M6800CPUContext[nActiveCPU].ReadOp = pHandler;
}
void M6800SetReadOpArgHandler(UINT8 (*pHandler)(UINT16))
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetReadOpArgHandler called without init\n"));
#endif
M6800CPUContext[nActiveCPU].ReadOpArg = pHandler;
}
void M6800SetReadPortHandler(UINT8 (*pHandler)(UINT16))
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetReadPortHandler called without init\n"));
#endif
M6800CPUContext[nActiveCPU].ReadPort = pHandler;
}
void M6800SetWritePortHandler(void (*pHandler)(UINT16, UINT8))
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800SetWritePortHandler called without init\n"));
#endif
M6800CPUContext[nActiveCPU].WritePort = pHandler;
}
UINT8 M6800ReadByte(UINT16 Address)
{
// check mem map
UINT8 * pr = M6800CPUContext[nActiveCPU].pMemMap[0x000 | (Address >> 8)];
if (pr != NULL) {
return pr[Address & 0xff];
}
// check handler
if (M6800CPUContext[nActiveCPU].ReadByte != NULL) {
return M6800CPUContext[nActiveCPU].ReadByte(Address);
}
return 0;
}
void M6800WriteByte(UINT16 Address, UINT8 Data)
{
// check mem map
UINT8 * pr = M6800CPUContext[nActiveCPU].pMemMap[0x100 | (Address >> 8)];
if (pr != NULL) {
pr[Address & 0xff] = Data;
return;
}
// check handler
if (M6800CPUContext[nActiveCPU].WriteByte != NULL) {
M6800CPUContext[nActiveCPU].WriteByte(Address, Data);
return;
}
}
UINT8 M6800ReadOp(UINT16 Address)
{
// check mem map
UINT8 * pr = M6800CPUContext[nActiveCPU].pMemMap[0x200 | (Address >> 8)];
if (pr != NULL) {
return pr[Address & 0xff];
}
// check handler
if (M6800CPUContext[nActiveCPU].ReadOp != NULL) {
return M6800CPUContext[nActiveCPU].ReadOp(Address);
}
return 0;
}
UINT8 M6800ReadOpArg(UINT16 Address)
{
// check mem map
UINT8 * pr = M6800CPUContext[nActiveCPU].pMemMap[0x200 | (Address >> 8)];
if (pr != NULL) {
return pr[Address & 0xff];
}
// check handler
if (M6800CPUContext[nActiveCPU].ReadOpArg != NULL) {
return M6800CPUContext[nActiveCPU].ReadOpArg(Address);
}
return 0;
}
UINT8 M6800ReadPort(UINT16 Address)
{
// check handler
if (M6800CPUContext[nActiveCPU].ReadPort != NULL) {
return M6800CPUContext[nActiveCPU].ReadPort(Address);
}
return 0;
}
void M6800WritePort(UINT16 Address, UINT8 Data)
{
// check handler
if (M6800CPUContext[nActiveCPU].WritePort != NULL) {
M6800CPUContext[nActiveCPU].WritePort(Address, Data);
return;
}
}
void M6800WriteRom(UINT32 Address, UINT8 Data)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800WriteRom called without init\n"));
#endif
Address &= 0xffff;
// check mem map
UINT8 * pr = M6800CPUContext[nActiveCPU].pMemMap[0x000 | (Address >> 8)];
UINT8 * pw = M6800CPUContext[nActiveCPU].pMemMap[0x100 | (Address >> 8)];
UINT8 * pf = M6800CPUContext[nActiveCPU].pMemMap[0x200 | (Address >> 8)];
if (pr != NULL) {
pr[Address & 0xff] = Data;
}
if (pw != NULL) {
pw[Address & 0xff] = Data;
}
if (pf != NULL) {
pf[Address & 0xff] = Data;
}
// check handler
if (M6800CPUContext[nActiveCPU].WriteByte != NULL) {
M6800CPUContext[nActiveCPU].WriteByte(Address, Data);
return;
}
}
INT32 M6800Scan(INT32 nAction)
{
#if defined FBNEO_DEBUG
if (!DebugCPU_M6800Initted) bprintf(PRINT_ERROR, _T("M6800Scan called without init\n"));
#endif
if (nAction & ACB_DRIVER_DATA) {
for (INT32 i = 0; i < nM6800Count+1; i++) {
struct BurnArea ba;
memset(&ba, 0, sizeof(ba));
ba.Data = &M6800CPUContext[i].reg;
ba.nLen = STRUCT_SIZE_HELPER(m6800_Regs, timer_over);
ba.szName = "M6800 Registers";
BurnAcb(&ba);
SCAN_VAR(M6800CPUContext[i].nCyclesTotal);
SCAN_VAR(M6800CPUContext[i].nCyclesSegment);
SCAN_VAR(M6800CPUContext[i].nCyclesLeft);
SCAN_VAR(nM6800CyclesDone[i]);
SCAN_VAR(M6800CPUContext[i].bResetLine);
}
SCAN_VAR(nM6800CyclesTotal);
}
return 0;
}