#include "burnint.h" #include "m6800_intf.h" #include #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; }