diff options
Diffstat (limited to 'libsidplay2/sidplay-libs-2.1.0/libsidplay/src/mos6510/cycle_based/mos6510c.i')
-rw-r--r-- | libsidplay2/sidplay-libs-2.1.0/libsidplay/src/mos6510/cycle_based/mos6510c.i | 2562 |
1 files changed, 0 insertions, 2562 deletions
diff --git a/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/mos6510/cycle_based/mos6510c.i b/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/mos6510/cycle_based/mos6510c.i deleted file mode 100644 index 78d57ba6..00000000 --- a/libsidplay2/sidplay-libs-2.1.0/libsidplay/src/mos6510/cycle_based/mos6510c.i +++ /dev/null @@ -1,2562 +0,0 @@ -/*************************************************************************** - mos6510.i - Cycle Accurate 6510 emulation - ------------------- - begin : Thu May 11 06:22:40 BST 2000 - copyright : (C) 2000 by Simon White - email : s_a_white@email.com - ***************************************************************************/ - -/*************************************************************************** - * * - * This program 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 2 of the License, or * - * (at your option) any later version. * - * * - ***************************************************************************/ -/*************************************************************************** - * $Log: mos6510c.i,v $ - * Revision 1.30 2002/12/16 08:42:58 s_a_white - * Fixed use of nothrow to be namespaced with std::. - * - * Revision 1.29 2002/11/28 20:35:06 s_a_white - * Reduced number of thrown exceptions when dma occurs. - * - * Revision 1.28 2002/11/25 20:10:55 s_a_white - * A bus access failure should stop the CPU dead like the cycle never started. - * This is currently simulated using throw (execption handling) for now. - * - * Revision 1.27 2002/11/21 19:52:48 s_a_white - * CPU upgraded to be like other components. Theres nolonger a clock call, - * instead events are registered to occur at a specific time. - * - * Revision 1.26 2002/11/19 22:57:33 s_a_white - * Initial support for external DMA to steal cycles away from the CPU. - * - * Revision 1.25 2002/11/01 19:22:36 s_a_white - * Removed debug printf. - * - * Revision 1.24 2002/11/01 17:35:27 s_a_white - * Frame based support for old sidplay1 modes. - * - * Revision 1.23 2002/03/12 18:48:03 s_a_white - * Tidied illegal instruction debug print out. - * - * Revision 1.22 2001/12/11 19:24:15 s_a_white - * More GCC3 Fixes. - * - * Revision 1.21 2001/11/16 19:21:03 s_a_white - * Sign fixes. - * - * Revision 1.20 2001/10/28 21:31:26 s_a_white - * Removed kernel debuging code. - * - * Revision 1.19 2001/09/03 22:21:52 s_a_white - * When initialising the status register and therefore unmasking the irqs, - * check the irq line to see if any are pending. - * - * Revision 1.18 2001/08/10 20:05:50 s_a_white - * Fixed RMW instructions which broke due to the optimisation. - * - * Revision 1.17 2001/08/05 15:46:02 s_a_white - * No longer need to check on which cycle an instruction ends or when to print - * debug information. - * - * Revision 1.16 2001/07/14 13:15:30 s_a_white - * Accumulator is now unsigned, which improves code readability. Emulation - * tested with testsuite 2.15. Various instructions required modification. - * - * Revision 1.15 2001/04/20 22:23:11 s_a_white - * Handling of page boundary crossing now correct for branch instructions. - * - * Revision 1.14 2001/03/28 22:59:59 s_a_white - * Converted some bad envReadMemByte's to - * envReadMemDataByte - * - * Revision 1.13 2001/03/28 21:17:34 s_a_white - * Added support for proper RMW instructions. - * - * Revision 1.12 2001/03/24 18:09:17 s_a_white - * On entry to interrupt routine the first instruction in the handler is now always - * executed before pending interrupts are re-checked. - * - * Revision 1.11 2001/03/22 22:40:43 s_a_white - * Added new header for definition of nothrow. - * - * Revision 1.10 2001/03/21 22:27:18 s_a_white - * Change to IRQ error message. - * - * Revision 1.9 2001/03/19 23:46:35 s_a_white - * NMI no longer sets I flag. RTI and store instructions are no longer - * overlapped. - * - * Revision 1.8 2001/03/09 22:28:51 s_a_white - * Speed optimisation update and fix for interrupt flag in PushSR call. - * - * Revision 1.7 2001/02/22 08:28:57 s_a_white - * Interrupt masking fixed. - * - * Revision 1.6 2001/02/13 23:01:44 s_a_white - * envReadMemDataByte now used for some memory accesses. - * - * Revision 1.5 2000/12/24 00:45:38 s_a_white - * HAVE_EXCEPTIONS update - * - * Revision 1.4 2000/12/14 23:55:07 s_a_white - * PushSR optimisation and PopSR code cleanup. - * - ***************************************************************************/ -/* -const char _sidtune_CHRtab[256] = // CHR$ conversion table (0x01 = no output) -{ - 0x0, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0xd, 0x1, 0x1, - 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, - 0x20,0x21, 0x1,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, - 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, - 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, - 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x24,0x5d,0x20,0x20, - // alternative: CHR$(92=0x5c) => ISO Latin-1(0xa3) - 0x2d,0x23,0x7c,0x2d,0x2d,0x2d,0x2d,0x7c,0x7c,0x5c,0x5c,0x2f,0x5c,0x5c,0x2f,0x2f, - 0x5c,0x23,0x5f,0x23,0x7c,0x2f,0x58,0x4f,0x23,0x7c,0x23,0x2b,0x7c,0x7c,0x26,0x5c, - // 0x80-0xFF - 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, - 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, 0x1, - 0x20,0x7c,0x23,0x2d,0x2d,0x7c,0x23,0x7c,0x23,0x2f,0x7c,0x7c,0x2f,0x5c,0x5c,0x2d, - 0x2f,0x2d,0x2d,0x7c,0x7c,0x7c,0x7c,0x2d,0x2d,0x2d,0x2f,0x5c,0x5c,0x2f,0x2f,0x23, - 0x2d,0x23,0x7c,0x2d,0x2d,0x2d,0x2d,0x7c,0x7c,0x5c,0x5c,0x2f,0x5c,0x5c,0x2f,0x2f, - 0x5c,0x23,0x5f,0x23,0x7c,0x2f,0x58,0x4f,0x23,0x7c,0x23,0x2b,0x7c,0x7c,0x26,0x5c, - 0x20,0x7c,0x23,0x2d,0x2d,0x7c,0x23,0x7c,0x23,0x2f,0x7c,0x7c,0x2f,0x5c,0x5c,0x2d, - 0x2f,0x2d,0x2d,0x7c,0x7c,0x7c,0x7c,0x2d,0x2d,0x2d,0x2f,0x5c,0x5c,0x2f,0x2f,0x23 -}; -*/ - -#include "config.h" - -#ifdef HAVE_EXCEPTIONS -# include <new> -#endif - -// Microsoft Visual C++ Version Number to work around compiler bug -// Currently both Visual C++ Versions 5, 6 are broken. -#define _MSC_VER_BAD_NEW 1200 /* Defines VC6 and below */ -//char filetmp[0x100]; -//int filepos = 0; - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Status Register Routines // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Use macros to access flags. Allows compatiblity with other versions -// of this emulation -// Set N and Z flags according to byte -#define setFlagsNZ(x) (Register_z_Flag = (Register_n_Flag = (uint_least8_t) (x))) -#define setFlagN(x) (Register_n_Flag = (uint_least8_t) (x)) -#define setFlagV(x) (Register_v_Flag = (uint_least8_t) (x)) -#define setFlagD(x) (Register_Status = (Register_Status & ~(1 << SR_DECIMAL)) \ - | (((x) != 0) << SR_DECIMAL)) -#define setFlagI(x) (Register_Status = (Register_Status & ~(1 << SR_INTERRUPT)) \ - | (((x) != 0) << SR_INTERRUPT)) -#define setFlagZ(x) (Register_z_Flag = (uint_least8_t) (x)) -#define setFlagC(x) (Register_c_Flag = (uint_least8_t) (x)) - - -#define getFlagN() ((Register_n_Flag & (1 << SR_NEGATIVE)) != 0) -#define getFlagV() (Register_v_Flag != 0) -#define getFlagD() ((Register_Status & (1 << SR_DECIMAL)) != 0) -#define getFlagI() ((Register_Status & (1 << SR_INTERRUPT)) != 0) -#define getFlagZ() (Register_z_Flag == 0) -#define getFlagC() (Register_c_Flag != 0) - -#define stealCycle() \ - interrupts.delay++; \ - throw((int_least8_t) -1); - - -// Handle bus access signals -void MOS6510::aecSignal (bool state) -{ // If the cpu blocked waiting for the bus - // the schedule a retry. - aec = state; - if (state && m_blocked) - { - m_blocked = false; - eventContext.schedule (this, 1); - } -} - -void MOS6510::rdySignal (bool state) -{ // If the cpu blocked waiting for the bus - // the schedule a retry. - rdy = state; - if (state && m_blocked) - { - m_blocked = false; - eventContext.schedule (this, 1); - } -} - -// Push P on stack, decrement S -void MOS6510::PushSR (bool b_flag) -{ - if (aec) - { - uint_least16_t addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - /* Rev 1.04 - Corrected flag mask */ - Register_Status &= ((1 << SR_NOTUSED) | (1 << SR_INTERRUPT) | - (1 << SR_DECIMAL) | (1 << SR_BREAK)); - Register_Status |= (getFlagN () << SR_NEGATIVE); - Register_Status |= (getFlagV () << SR_OVERFLOW); - Register_Status |= (getFlagZ () << SR_ZERO); - Register_Status |= (getFlagC () << SR_CARRY); - envWriteMemByte (addr, Register_Status & ~((!b_flag) << SR_BREAK)); - Register_StackPointer--; - } - else - { // Address bus not ready - stealCycle(); - } -} - -void MOS6510::PushSR (void) -{ - PushSR (true); -} - -// increment S, Pop P off stack -void MOS6510::PopSR (void) -{ - if (rdy && aec) - { - bool newFlagI, oldFlagI; - oldFlagI = getFlagI (); - - // Get status register off stack - Register_StackPointer++; - { - uint_least16_t addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - Register_Status = envReadMemByte (addr); - } - Register_Status |= ((1 << SR_NOTUSED) | (1 << SR_BREAK)); - setFlagN (Register_Status); - setFlagV (Register_Status & (1 << SR_OVERFLOW)); - setFlagZ (!(Register_Status & (1 << SR_ZERO))); - setFlagC (Register_Status & (1 << SR_CARRY)); - - // I flag change is delayed by 1 instruction - newFlagI = getFlagI (); - interrupts.irqLatch = oldFlagI ^ newFlagI; - // Check to see if interrupts got re-enabled - if (!newFlagI && interrupts.irqs) - interrupts.irqRequest = true; - } - else - { // Address bus not ready - stealCycle(); - } -} - - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Interrupt Routines // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -#define iIRQSMAX 3 -enum -{ - oNONE = -1, - oRST, - oNMI, - oIRQ -}; - -enum -{ - iNONE = 0, - iRST = 1 << oRST, - iNMI = 1 << oNMI, - iIRQ = 1 << oIRQ -}; - -void MOS6510::triggerRST (void) -{ - interrupts.pending |= iRST; -} - -void MOS6510::triggerNMI (void) -{ - interrupts.pending |= iNMI; - interrupts.nmiClock = eventContext.getTime (); -} - -// Level triggered interrupt -void MOS6510::triggerIRQ (void) -{ // IRQ Suppressed - if (!getFlagI ()) - interrupts.irqRequest = true; - if (!interrupts.irqs++) - interrupts.irqClock = eventContext.getTime (); - - if (interrupts.irqs > iIRQSMAX) - { - printf ("\nMOS6510 ERROR: An external component is not clearing down it's IRQs.\n\n"); - exit (-1); - } -} - -void MOS6510::clearIRQ (void) -{ - if (interrupts.irqs > 0) - { - if (!(--interrupts.irqs)) - { // Clear off the interrupts - interrupts.irqRequest = false; - } - } -} - -bool MOS6510::interruptPending (void) -{ - int_least8_t offset, pending; - static const int_least8_t offTable[] = {oNONE, oRST, oNMI, oRST, - oIRQ, oRST, oNMI, oRST}; - // Update IRQ pending - if (!interrupts.irqLatch) - { - interrupts.pending &= ~iIRQ; - if (interrupts.irqRequest) - interrupts.pending |= iIRQ; - } - - pending = interrupts.pending; -MOS6510_interruptPending_check: - // Service the highest priority interrupt - offset = offTable[pending]; - switch (offset) - { - case oNONE: - return false; - - case oNMI: - { - // Try to determine if we should be processing the NMI yet - event_clock_t cycles = eventContext.getTime (interrupts.nmiClock); - if (cycles >= interrupts.delay) - { - interrupts.pending &= ~iNMI; - break; - } - - // NMI delayed so check for other interrupts - pending &= ~iNMI; - goto MOS6510_interruptPending_check; - } - - case oIRQ: - { - // Try to determine if we should be processing the IRQ yet - event_clock_t cycles = eventContext.getTime (interrupts.irqClock); - if (cycles >= interrupts.delay) - break; - - // NMI delayed so check for other interrupts - pending &= ~iIRQ; - goto MOS6510_interruptPending_check; - } - - case oRST: - break; - } - -#ifdef MOS6510_DEBUG - if (dodump) - { - printf ("****************************************************\n"); - switch (offset) - { - case oIRQ: - printf (" IRQ Routine\n"); - break; - case oNMI: - printf (" NMI Routine\n"); - break; - case oRST: - printf (" RST Routine\n"); - break; - } - printf ("****************************************************\n"); - } -#endif - - // Start the interrupt - instrCurrent = &interruptTable[offset]; - procCycle = instrCurrent->cycle; - cycleCount = 0; - return true; -} - -void MOS6510::RSTRequest (void) -{ - envReset (); -} - -void MOS6510::NMIRequest (void) -{ - if (rdy && aec) - endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFA)); - else - { // Address bus not ready - stealCycle(); - } -} - -void MOS6510::NMI1Request (void) -{ - if (rdy && aec) - { - endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFB)); - endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); - } - else - { // Address bus not ready - stealCycle(); - } -} - -void MOS6510::IRQRequest (void) -{ - PushSR (false); - setFlagI (true); - interrupts.irqRequest = false; -} - -void MOS6510::IRQ1Request (void) -{ - if (rdy && aec) - endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFE)); - else - { // Address bus not ready - stealCycle(); - } -} - -void MOS6510::IRQ2Request (void) -{ - if (rdy && aec) - { - endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFF)); - endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); - } - else - { // Address bus not ready - stealCycle(); - } -} - -void MOS6510::NextInstr (void) -{ - if (!interruptPending ()) - FetchOpcode (); -} - - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Common Instruction Addressing Routines // -// Addressing operations as described in 64doc by John West and // -// Marko Makela // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// - -// Fetch opcode, increment PC -// Addressing Modes: All -void MOS6510::FetchOpcode (void) -{ - if (rdy && aec) - { // On new instruction all interrupt delays are reset - interrupts.delay = MOS6510_INTERRUPT_DELAY; - interrupts.irqLatch = false; - - instrStartPC = endian_32lo16 (Register_ProgramCounter++); - instrOpcode = envReadMemByte (instrStartPC); - // Convert opcode to pointer in instruction table - instrCurrent = &instrTable[instrOpcode]; - Instr_Operand = 0; - procCycle = instrCurrent->cycle; - cycleCount = 0; - clock (); - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Fetch value, increment PC -/* Addressing Modes: Immediate - Relative -*/ -void MOS6510::FetchDataByte (void) -{ // Get data byte from memory - Cycle_Data = envReadMemByte (endian_32lo16 (Register_ProgramCounter)); - Register_ProgramCounter++; - - // Nextline used for Debug - Instr_Operand = (uint_least16_t) Cycle_Data; -} - -// Fetch low address byte, increment PC -/* Addressing Modes: Stack Manipulation - Absolute - Zero Page - Zerp Page Indexed - Absolute Indexed - Absolute Indirect -*/ -void MOS6510::FetchLowAddr (void) -{ - if (rdy && aec) - { - Cycle_EffectiveAddress = envReadMemByte (endian_32lo16 (Register_ProgramCounter)); - Register_ProgramCounter++; - - // Nextline used for Debug - Instr_Operand = Cycle_EffectiveAddress; - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Read from address, add index register X to it -// Addressing Modes: Zero Page Indexed -void MOS6510::FetchLowAddrX (void) -{ - FetchLowAddr (); - Cycle_EffectiveAddress = (Cycle_EffectiveAddress + Register_X) & 0xFF; -} - -// Read from address, add index register Y to it -// Addressing Modes: Zero Page Indexed -void MOS6510::FetchLowAddrY (void) -{ - FetchLowAddr (); - Cycle_EffectiveAddress = (Cycle_EffectiveAddress + Register_Y) & 0xFF; -} - -// Fetch high address byte, increment PC (Absoulte Addressing) -// Low byte must have been obtained first! -// Addressing Modes: Absolute -void MOS6510::FetchHighAddr (void) -{ - if (rdy && aec) - { // Get the high byte of an address from memory - endian_16hi8 (Cycle_EffectiveAddress, envReadMemByte (endian_32lo16 (Register_ProgramCounter))); - Register_ProgramCounter++; - - // Nextline used for Debug - endian_16hi8 (Instr_Operand, endian_16hi8 (Cycle_EffectiveAddress)); - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Fetch high byte of address, add index register X to low address byte, -// increment PC -// Addressing Modes: Absolute Indexed -void MOS6510::FetchHighAddrX (void) -{ - uint8_t page; - // Rev 1.05 (saw) - Call base Function - FetchHighAddr (); - page = endian_16hi8 (Cycle_EffectiveAddress); - Cycle_EffectiveAddress += Register_X; - -#ifdef MOS6510_ACCURATE_CYCLES - // Handle page boundary crossing - if (endian_16hi8 (Cycle_EffectiveAddress) == page) - cycleCount++; -#endif -} - -// Same as above except dosen't worry about page crossing -void MOS6510::FetchHighAddrX2 (void) -{ - FetchHighAddr (); - Cycle_EffectiveAddress += Register_X; -} - -// Fetch high byte of address, add index register Y to low address byte, -// increment PC -// Addressing Modes: Absolute Indexed -void MOS6510::FetchHighAddrY (void) -{ - uint8_t page; - // Rev 1.05 (saw) - Call base Function - FetchHighAddr (); - page = endian_16hi8 (Cycle_EffectiveAddress); - Cycle_EffectiveAddress += Register_Y; - -#ifdef MOS6510_ACCURATE_CYCLES - // Handle page boundary crossing - if (endian_16hi8 (Cycle_EffectiveAddress) == page) - cycleCount++; -#endif -} - -// Same as above except dosen't worry about page crossing -void MOS6510::FetchHighAddrY2 (void) -{ - FetchHighAddr (); - Cycle_EffectiveAddress += Register_Y; -} - -// Fetch pointer address low, increment PC -/* Addressing Modes: Absolute Indirect - Indirect indexed (post Y) -*/ -void MOS6510::FetchLowPointer (void) -{ - if (rdy && aec) - { - Cycle_Pointer = envReadMemByte (endian_32lo16 (Register_ProgramCounter)); - Register_ProgramCounter++; - // Nextline used for Debug - Instr_Operand = Cycle_Pointer; - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Read pointer from the address and add X to it -// Addressing Modes: Indexed Indirect (pre X) -void MOS6510::FetchLowPointerX (void) -{ - if (rdy && aec) - { - endian_16hi8 (Cycle_Pointer, envReadMemDataByte (Cycle_Pointer)); - // Page boundary crossing is not handled - Cycle_Pointer = (Cycle_Pointer + Register_X) & 0xFF; - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Fetch pointer address high, increment PC -// Addressing Modes: Absolute Indirect -void MOS6510::FetchHighPointer (void) -{ - if (rdy && aec) - { - endian_16hi8 (Cycle_Pointer, envReadMemByte (endian_32lo16 (Register_ProgramCounter))); - Register_ProgramCounter++; - - // Nextline used for Debug - endian_16hi8 (Instr_Operand, endian_16hi8 (Cycle_Pointer)); - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Fetch effective address low -/* Addressing Modes: Indirect - Indexed Indirect (pre X) - Indirect indexed (post Y) -*/ -void MOS6510::FetchLowEffAddr (void) -{ - if (rdy && aec) - Cycle_EffectiveAddress = envReadMemDataByte (Cycle_Pointer); - else - { // Address bus not ready - stealCycle(); - } -} - -// Fetch effective address high -/* Addressing Modes: Indirect - Indexed Indirect (pre X) -*/ -void MOS6510::FetchHighEffAddr (void) -{ - if (rdy && aec) - { // Rev 1.03 (Mike) - Extra +1 removed - endian_16lo8 (Cycle_Pointer, (Cycle_Pointer + 1) & 0xff); - endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (Cycle_Pointer)); - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Fetch effective address high, add Y to low byte of effective address -// Addressing Modes: Indirect indexed (post Y) -void MOS6510::FetchHighEffAddrY (void) -{ - uint8_t page; - // Rev 1.05 (saw) - Call base Function - FetchHighEffAddr (); - page = endian_16hi8 (Cycle_EffectiveAddress); - Cycle_EffectiveAddress += Register_Y; - -#ifdef MOS6510_ACCURATE_CYCLES - // Handle page boundary crossing - if (endian_16hi8 (Cycle_EffectiveAddress) == page) - cycleCount++; -#endif -} - -// Same as above except dosen't worry about page crossing -void MOS6510::FetchHighEffAddrY2 (void) -{ - FetchHighEffAddr (); - Cycle_EffectiveAddress += Register_Y; -} - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Common Data Accessing Routines // -// Data Accessing operations as described in 64doc by John West and // -// Marko Makela // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// - -void MOS6510::FetchEffAddrDataByte (void) -{ - if (rdy && aec) - Cycle_Data = envReadMemDataByte (Cycle_EffectiveAddress); - else - { // Address bus not ready - stealCycle(); - } -} - -void MOS6510::PutEffAddrDataByte (void) -{ - if (aec) - envWriteMemByte (Cycle_EffectiveAddress, Cycle_Data); - else - { // Address bus not ready - stealCycle(); - } -} - -// Used for Read Modify Write (RMW) instructions -void MOS6510::FetchPutEffAddrDataByte (void) -{ - FetchEffAddrDataByte (); - PutEffAddrDataByte (); -} - -// Push Program Counter Low Byte on stack, decrement S -void MOS6510::PushLowPC (void) -{ - if (aec) - { - uint_least16_t addr; - addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - envWriteMemByte (addr, endian_32lo8 (Register_ProgramCounter)); - Register_StackPointer--; - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Push Program Counter High Byte on stack, decrement S -void MOS6510::PushHighPC (void) -{ - if (aec) - { - uint_least16_t addr; - addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - envWriteMemByte (addr, endian_32hi8 (Register_ProgramCounter)); - Register_StackPointer--; - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Increment stack and pull program counter low byte from stack, -void MOS6510::PopLowPC (void) -{ - if (rdy && aec) - { - uint_least16_t addr; - Register_StackPointer++; - addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (addr)); - } - else - { // Address bus not ready - stealCycle(); - } -} - -// Increment stack and pull program counter high byte from stack, -void MOS6510::PopHighPC (void) -{ - if (rdy && aec) - { - uint_least16_t addr; - Register_StackPointer++; - addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (addr)); - } - else - { // Address bus not ready - stealCycle(); - } -} - -void MOS6510::WasteCycle (void) -{ -} - -void MOS6510::DebugCycle (void) -{ - if (dodump) - DumpState (); - clock (); -} - - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Common Instruction Opcodes // -// See and 6510 Assembly Book for more information on these instructions // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// - -void MOS6510::brk_instr (void) -{ - PushSR (); - setFlagI (true); - interrupts.irqRequest = false; - - // Check for an NMI, and switch over if pending - if (interrupts.pending & iNMI) - { - event_clock_t cycles = eventContext.getTime (interrupts.nmiClock); - if (cycles >= interrupts.delay) - { - interrupts.pending &= ~iNMI; - instrCurrent = &interruptTable[oNMI]; - procCycle = &instrCurrent->cycle[cycleCount]; - } - } -} - -void MOS6510::cld_instr (void) -{ - setFlagD (false); -} - -void MOS6510::cli_instr (void) -{ - bool oldFlagI = getFlagI (); - setFlagI (false); - // I flag change is delayed by 1 instruction - interrupts.irqLatch = oldFlagI ^ getFlagI (); - // Check to see if interrupts got re-enabled - if (interrupts.irqs) - interrupts.irqRequest = true; -} - -void MOS6510::jmp_instr (void) -{ - endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); -} - -void MOS6510::jsr_instr (void) -{ // JSR uses absolute addressing in this emulation, - // hence the -1. The real SID does not use this addressing - // mode. - Register_ProgramCounter--; - PushHighPC (); -} - -void MOS6510::pha_instr (void) -{ - if (aec) - { - uint_least16_t addr; - addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - envWriteMemByte (addr, Register_Accumulator); - Register_StackPointer--; - } - else - { // Address bus not ready - cycleCount--; - return; - } -} - -/* RTI does not delay the IRQ I flag change as it is set 3 cycles before - * the end of the opcode, and thus the 6510 has enough time to call the - * interrupt routine as soon as the opcode ends, if necessary. */ -void MOS6510::rti_instr (void) -{ -#ifdef MOS6510_DEBUG - if (dodump) - printf ("****************************************************\n\n"); -#endif - - endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); - interrupts.irqLatch = false; -} - -void MOS6510::rts_instr (void) -{ -/* - // Hack - Output character to screen - if (Register_ProgramCounter == 0xffd3) - { - char ch = _sidtune_CHRtab[Register_Accumulator]; - switch (ch) - { - case 0: - break; - case 1: - printf (" "); - fprintf (stderr, " "); - case 0xd: - printf ("\n"); - fprintf (stderr, "\n"); - filepos = 0; - break; - default: - filetmp[filepos++] = ch; - printf ("%c", ch); - fprintf (stderr, "%c", ch); - } - } - - if (Register_ProgramCounter == 0xe170) - { - filetmp[filepos] = '\0'; - envLoadFile (filetmp); - } -*/ - endian_32lo16 (Register_ProgramCounter, Cycle_EffectiveAddress); - Register_ProgramCounter++; -} - -void MOS6510::sed_instr (void) -{ - setFlagD (true); -} - -void MOS6510::sei_instr (void) -{ - bool oldFlagI = getFlagI (); - setFlagI (true); - // I flag change is delayed by 1 instruction - interrupts.irqLatch = oldFlagI ^ getFlagI (); - interrupts.irqRequest = false; -} - -void MOS6510::sta_instr (void) -{ - Cycle_Data = Register_Accumulator; - PutEffAddrDataByte (); -} - -void MOS6510::stx_instr (void) -{ - Cycle_Data = Register_X; - PutEffAddrDataByte (); -} - -void MOS6510::sty_instr (void) -{ - Cycle_Data = Register_Y; - PutEffAddrDataByte (); -} - - - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Common Instruction Undocumented Opcodes // -// See documented 6502-nmo.opc by Adam Vardy for more details // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// - -// Undocumented - This opcode stores the result of A AND X AND the high -// byte of the target address of the operand +1 in memory. -void MOS6510::axa_instr (void) -{ - Cycle_Data = Register_X & Register_Accumulator & (endian_16hi8 (Cycle_EffectiveAddress) + 1); - PutEffAddrDataByte (); -} - -// Undocumented - AXS ANDs the contents of the A and X registers (without changing the -// contents of either register) and stores the result in memory. -// AXS does not affect any flags in the processor status register. -void MOS6510::axs_instr (void) -{ - Cycle_Data = Register_Accumulator & Register_X; -} - -/* Not required - Operation performed By another method -// Undocumented - HLT crashes the microprocessor. When this opcode is executed, program -// execution ceases. No hardware interrupts will execute either. The author -// has characterized this instruction as a halt instruction since this is the -// most straightforward explanation for this opcode's behaviour. Only a reset -// will restart execution. This opcode leaves no trace of any operation -// performed! No registers affected. -void MOS6510::hlt_instr (void) -{ -} -*/ - -/* Not required - Operation performed By another method -void MOS6510::nop_instr (void) -{ -} -*/ - -/* Not required - Operation performed By another method -void MOS6510::php_instr (void) -{ -} -*/ - -// Undocumented - This opcode ANDs the contents of the Y register with <ab+1> and stores the -// result in memory. -void MOS6510::say_instr (void) -{ - Cycle_Data = Register_Y & (endian_16hi8 (Cycle_EffectiveAddress) + 1); -} - -/* Not required - Operation performed By another method -// Undocumented - skip next byte. -void MOS6510::skb_instr (void) -{ - Register_ProgramCounter++; -} -*/ - -/* Not required - Operation performed By another method -// Undocumented - skip next word. -void MOS6510::skw_instr (void) -{ - Register_ProgramCounter += 2; -} -*/ - -// Undocumented - This opcode ANDs the contents of the X register with <ab+1> and stores the -// result in memory. -void MOS6510::xas_instr (void) -{ - Cycle_Data = Register_X & (endian_16hi8 (Cycle_EffectiveAddress) + 1); -} - - -#ifdef X86 -#include "MOS6510\CYCLE_~1\X86.CPP" -//#include "MOS6510\CYCLE_BASED\X86.CPP" -#else - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Generic Binary Coded Decimal Correction // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// - -void MOS6510::Perform_ADC (void) -{ - uint C = getFlagC (); - uint A = Register_Accumulator; - uint s = Cycle_Data; - uint regAC2 = A + s + C; - - if (getFlagD ()) - { // BCD mode - uint lo = (A & 0x0f) + (s & 0x0f) + C; - uint hi = (A & 0xf0) + (s & 0xf0); - if (lo > 0x09) lo += 0x06; - if (lo > 0x0f) hi += 0x10; - - setFlagZ (regAC2); - setFlagN (hi); - setFlagV (((hi ^ A) & 0x80) && !((A ^ s) & 0x80)); - if (hi > 0x90) hi += 0x60; - - setFlagC (hi > 0xff); - Register_Accumulator = (hi | (lo & 0x0f)); - } - else - { // Binary mode - setFlagC (regAC2 > 0xff); - setFlagV (((regAC2 ^ A) & 0x80) && !((A ^ s) & 0x80)); - setFlagsNZ (Register_Accumulator = regAC2 & 0xff); - } -} - -void MOS6510::Perform_SBC (void) -{ - uint C = !getFlagC (); - uint A = Register_Accumulator; - uint s = Cycle_Data; - uint regAC2 = A - s - C; - - setFlagC (regAC2 < 0x100); - setFlagV (((regAC2 ^ A) & 0x80) && ((A ^ s) & 0x80)); - setFlagsNZ (regAC2); - - if (getFlagD ()) - { // BCD mode - uint lo = (A & 0x0f) - (s & 0x0f) - C; - uint hi = (A & 0xf0) - (s & 0xf0); - if (lo & 0x10) - { - lo -= 0x06; - hi -= 0x10; - } - if (hi & 0x100) hi -= 0x60; - Register_Accumulator = (hi | (lo & 0x0f)); - } - else - { // Binary mode - Register_Accumulator = regAC2 & 0xff; - } -} - - - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Generic Instruction Addressing Routines // -//-------------------------------------------------------------------------/ - - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Generic Instruction Opcodes // -// See and 6510 Assembly Book for more information on these instructions // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// - -void MOS6510::adc_instr (void) -{ - Perform_ADC (); -} - -void MOS6510::and_instr (void) -{ - setFlagsNZ (Register_Accumulator &= Cycle_Data); -} - -void MOS6510::ane_instr (void) -{ - setFlagsNZ (Register_Accumulator = (Register_Accumulator | 0xee) & Register_X & Cycle_Data); -} - -void MOS6510::asl_instr (void) -{ - setFlagC (Cycle_Data & 0x80); - setFlagsNZ (Cycle_Data <<= 1); -} - -void MOS6510::asla_instr (void) -{ - setFlagC (Register_Accumulator & 0x80); - setFlagsNZ (Register_Accumulator <<= 1); -} - -void MOS6510::branch_instr (bool condition) -{ - if (condition) -#ifdef MOS6510_ACCURATE_CYCLES - { - uint8_t page; - page = endian_32hi8 (Register_ProgramCounter); - Register_ProgramCounter += (int8_t) Cycle_Data; - - // Handle page boundary crossing - if (endian_32hi8 (Register_ProgramCounter) == page) - { - cycleCount++; - interrupts.delay++; - } - } - else - { - cycleCount += 2; - } -#else - Register_ProgramCounter += (int8_t) Cycle_Data; -#endif -} - -void MOS6510::bcc_instr (void) -{ - branch_instr (!getFlagC ()); -} - -void MOS6510::bcs_instr (void) -{ - branch_instr (getFlagC ()); -} - -void MOS6510::beq_instr (void) -{ - branch_instr (getFlagZ ()); -} - -void MOS6510::bit_instr (void) -{ - setFlagZ (Register_Accumulator & Cycle_Data); - setFlagN (Cycle_Data); - setFlagV (Cycle_Data & 0x40); -} - -void MOS6510::bmi_instr (void) -{ - branch_instr (getFlagN ()); -} - -void MOS6510::bne_instr (void) -{ - branch_instr (!getFlagZ ()); -} - -void MOS6510::bpl_instr(void) -{ - branch_instr (!getFlagN ()); -} - -void MOS6510::bvc_instr (void) -{ - branch_instr (!getFlagV ()); -} - -void MOS6510::bvs_instr (void) -{ - branch_instr (getFlagV ()); -} - -void MOS6510::clc_instr (void) -{ - setFlagC (false); -} - -void MOS6510::clv_instr (void) -{ - setFlagV (false); -} - -void MOS6510::cmp_instr (void) -{ - uint_least16_t tmp = (uint_least16_t) Register_Accumulator - Cycle_Data; - setFlagsNZ (tmp); - setFlagC (tmp < 0x100); -} - -void MOS6510::cpx_instr (void) -{ - uint_least16_t tmp = (uint_least16_t) Register_X - Cycle_Data; - setFlagsNZ (tmp); - setFlagC (tmp < 0x100); -} - -void MOS6510::cpy_instr (void) -{ - uint_least16_t tmp = (uint_least16_t) Register_Y - Cycle_Data; - setFlagsNZ (tmp); - setFlagC (tmp < 0x100); -} - -void MOS6510::dec_instr (void) -{ - setFlagsNZ (--Cycle_Data); -} - -void MOS6510::dex_instr (void) -{ - setFlagsNZ (--Register_X); -} - -void MOS6510::dey_instr (void) -{ - setFlagsNZ (--Register_Y); -} - -void MOS6510::eor_instr (void) -{ - setFlagsNZ (Register_Accumulator^= Cycle_Data); -} - -void MOS6510::inc_instr (void) -{ - setFlagsNZ (++Cycle_Data); -} - -void MOS6510::inx_instr (void) -{ - setFlagsNZ (++Register_X); -} - -void MOS6510::iny_instr (void) -{ - setFlagsNZ (++Register_Y); -} - -void MOS6510::lda_instr (void) -{ - setFlagsNZ (Register_Accumulator = Cycle_Data); -} - -void MOS6510::ldx_instr (void) -{ - setFlagsNZ (Register_X = Cycle_Data); -} - -void MOS6510::ldy_instr (void) -{ - setFlagsNZ (Register_Y = Cycle_Data); -} - -void MOS6510::lsr_instr (void) -{ - setFlagC (Cycle_Data & 0x01); - setFlagsNZ (Cycle_Data >>= 1); -} - -void MOS6510::lsra_instr (void) -{ - setFlagC (Register_Accumulator & 0x01); - setFlagsNZ (Register_Accumulator >>= 1); -} - -void MOS6510::ora_instr (void) -{ - setFlagsNZ (Register_Accumulator |= Cycle_Data); -} - -void MOS6510::pla_instr (void) -{ - if (rdy && aec) - { - uint_least16_t addr; - Register_StackPointer++; - addr = Register_StackPointer; - endian_16hi8 (addr, SP_PAGE); - setFlagsNZ (Register_Accumulator = envReadMemByte (addr)); - } - else - { // Address bus not ready - cycleCount--; - return; - } -} - -void MOS6510::rol_instr (void) -{ - uint8_t tmp = Cycle_Data & 0x80; - Cycle_Data <<= 1; - if (getFlagC ()) Cycle_Data |= 0x01; - setFlagsNZ (Cycle_Data); - setFlagC (tmp); -} - -void MOS6510::rola_instr (void) -{ - uint8_t tmp = Register_Accumulator & 0x80; - Register_Accumulator <<= 1; - if (getFlagC ()) Register_Accumulator |= 0x01; - setFlagsNZ (Register_Accumulator); - setFlagC (tmp); -} - -void MOS6510::ror_instr (void) -{ - uint8_t tmp = Cycle_Data & 0x01; - Cycle_Data >>= 1; - if (getFlagC ()) Cycle_Data |= 0x80; - setFlagsNZ (Cycle_Data); - setFlagC (tmp); -} - -void MOS6510::rora_instr (void) -{ - uint8_t tmp = Register_Accumulator & 0x01; - Register_Accumulator >>= 1; - if (getFlagC ()) Register_Accumulator |= 0x80; - setFlagsNZ (Register_Accumulator); - setFlagC (tmp); -} - -void MOS6510::sbx_instr (void) -{ - uint tmp = (Register_X & Register_Accumulator) - Cycle_Data; - setFlagsNZ (Register_X = tmp & 0xff); - setFlagC (tmp < 0x100); -} - -void MOS6510::sbc_instr (void) -{ - Perform_SBC (); -} - -void MOS6510::sec_instr (void) -{ - setFlagC (true); -} - -void MOS6510::shs_instr (void) -{ - endian_16lo8 (Register_StackPointer, (Register_Accumulator & Register_X)); - Cycle_Data = (endian_16hi8 (Cycle_EffectiveAddress) + 1) & Register_StackPointer; -} - -void MOS6510::tax_instr (void) -{ - setFlagsNZ (Register_X = Register_Accumulator); -} - -void MOS6510::tay_instr (void) -{ - setFlagsNZ (Register_Y = Register_Accumulator); -} - -void MOS6510::tsx_instr (void) -{ // Rev 1.03 (saw) - Got these tsx and txs reversed - setFlagsNZ (Register_X = endian_16lo8 (Register_StackPointer)); -} - -void MOS6510::txa_instr (void) -{ - setFlagsNZ (Register_Accumulator = Register_X); -} - -void MOS6510::txs_instr (void) -{ // Rev 1.03 (saw) - Got these tsx and txs reversed - endian_16lo8 (Register_StackPointer, Register_X); -} - -void MOS6510::tya_instr (void) -{ - setFlagsNZ (Register_Accumulator = Register_Y); -} - -void MOS6510::illegal_instr (void) -{ - printf ("\n\nILLEGAL INSTRUCTION, resetting emulation. **************\n"); - DumpState (); - printf ("********************************************************\n"); - // Perform Environment Reset - envReset (); -} - - -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// -// Generic Instruction Undocuemented Opcodes // -// See documented 6502-nmo.opc by Adam Vardy for more details // -//-------------------------------------------------------------------------// -//-------------------------------------------------------------------------// - -// Undocumented - This opcode ANDs the contents of the A register with an immediate value and -// then LSRs the result. -void MOS6510::alr_instr (void) -{ - Register_Accumulator &= Cycle_Data; - setFlagC (Register_Accumulator & 0x01); - setFlagsNZ (Register_Accumulator >>= 1); -} - -// Undcouemented - ANC ANDs the contents of the A register with an immediate value and then -// moves bit 7 of A into the Carry flag. This opcode works basically -// identically to AND #immed. except that the Carry flag is set to the same -// state that the Negative flag is set to. -void MOS6510::anc_instr (void) -{ - setFlagsNZ (Register_Accumulator &= Cycle_Data); - setFlagC (getFlagN ()); -} - -// Undocumented - This opcode ANDs the contents of the A register with an immediate value and -// then RORs the result (Implementation based on that of Frodo C64 Emulator) -void MOS6510::arr_instr (void) -{ - uint8_t data = Cycle_Data & Register_Accumulator; - Register_Accumulator = data >> 1; - if (getFlagC ()) Register_Accumulator |= 0x80; - - if (getFlagD ()) - { - setFlagN (0); - if (getFlagC ()) setFlagN (1 << SR_NEGATIVE); - setFlagZ (Register_Accumulator); - setFlagV ((data ^ Register_Accumulator) & 0x40); - - if ((data & 0x0f) + (data & 0x01) > 5) - Register_Accumulator = Register_Accumulator & 0xf0 | (Register_Accumulator + 6) & 0x0f; - setFlagC (((data + (data & 0x10)) & 0x1f0) > 0x50); - if (getFlagC ()) - Register_Accumulator += 0x60; - } - else - { - setFlagsNZ (Register_Accumulator); - setFlagC (Register_Accumulator & 0x40); - setFlagV ((Register_Accumulator & 0x40) ^ ((Register_Accumulator & 0x20) << 1)); - } -} - -// Undocumented - This opcode ASLs the contents of a memory location and then ORs the result -// with the accumulator. -void MOS6510::aso_instr (void) -{ - setFlagC (Cycle_Data & 0x80); - Cycle_Data <<= 1; - setFlagsNZ (Register_Accumulator |= Cycle_Data); -} - -// Undocumented - This opcode DECs the contents of a memory location and then CMPs the result -// with the A register. -void MOS6510::dcm_instr (void) -{ - uint_least16_t tmp; - Cycle_Data--; - tmp = (uint_least16_t) Register_Accumulator - Cycle_Data; - setFlagsNZ (tmp); - setFlagC (tmp < 0x100); -} - -// Undocumented - This opcode INCs the contents of a memory location and then SBCs the result -// from the A register. -void MOS6510::ins_instr (void) -{ - Cycle_Data++; - Perform_SBC (); -} - -// Undocumented - This opcode ANDs the contents of a memory location with the contents of the -// stack pointer register and stores the result in the accumulator, the X -// register, and the stack pointer. Affected flags: N Z. -void MOS6510::las_instr (void) -{ - setFlagsNZ (Cycle_Data &= endian_16lo8 (Register_StackPointer)); - Register_Accumulator = Cycle_Data; - Register_X = Cycle_Data; - Register_StackPointer = Cycle_Data; -} - -// Undocumented - This opcode loads both the accumulator and the X register with the contents -// of a memory location. -void MOS6510::lax_instr (void) -{ - setFlagsNZ (Register_Accumulator = Register_X = Cycle_Data); -} - -// Undocumented - LSE LSRs the contents of a memory location and then EORs the result with -// the accumulator. -void MOS6510::lse_instr (void) -{ - setFlagC (Cycle_Data & 0x01); - Cycle_Data >>= 1; - setFlagsNZ (Register_Accumulator ^= Cycle_Data); -} - -// Undocumented - This opcode ORs the A register with #xx, ANDs the result with an immediate -// value, and then stores the result in both A and X. -// xx may be EE,EF,FE, OR FF, but most emulators seem to use EE -void MOS6510::oal_instr (void) -{ - setFlagsNZ (Register_X = (Register_Accumulator = (Cycle_Data & (Register_Accumulator | 0xee)))); -} - -// Undocumented - RLA ROLs the contents of a memory location and then ANDs the result with -// the accumulator. -void MOS6510::rla_instr (void) -{ - uint8_t tmp = Cycle_Data & 0x80; - Cycle_Data = Cycle_Data << 1; - if (getFlagC ()) Cycle_Data |= 0x01; - setFlagC (tmp); - setFlagsNZ (Register_Accumulator &= Cycle_Data); -} - -// Undocumented - RRA RORs the contents of a memory location and then ADCs the result with -// the accumulator. -void MOS6510::rra_instr (void) -{ - uint8_t tmp = Cycle_Data & 0x01; - Cycle_Data >>= 1; - if (getFlagC ()) Cycle_Data |= 0x80; - setFlagC (tmp); - Perform_ADC (); -} - -// Undocumented - This opcode ANDs the contents of the A and X registers (without changing -// the contents of either register) and transfers the result to the stack -// pointer. It then ANDs that result with the contents of the high byte of -// the target address of the operand +1 and stores that final result in -// memory. -void MOS6510::tas_instr (void) -{ - endian_16lo8 (Register_StackPointer, Register_Accumulator & Register_X); - uint_least16_t tmp = Register_StackPointer & (Cycle_EffectiveAddress + 1); - Cycle_Data = (signed) endian_16lo8 (tmp); -} - -#endif // X86 - - -//-------------------------------------------------------------------------// -// Initialise and create CPU Chip // - -//MOS6510::MOS6510 (model_t _model, const char *id) -MOS6510::MOS6510 (EventContext *context) -:eventContext(*context), - Event("CPU") -{ - struct ProcessorOperations *instr; - uint8_t legalMode = true; - uint8_t legalInstr = true; - uint i, pass; - - //---------------------------------------------------------------------- - // Build up the processor instruction table - for (i = 0; i < 0x100; i++) - { -#if MOS6510_DEBUG > 1 - printf ("Building Command %d[%02x]..", i, i); -#endif - - // Pass 1 allocates the memory, Pass 2 builds the instruction - instr = &instrTable[i]; - instr->cycle = NULL; - - for (pass = 0; pass < 2; pass++) - { - enum {WRITE = 0, RMW = 1, READ = 2}; - int access = WRITE; - cycleCount = -1; - legalMode = true; - legalInstr = true; - if (pass) procCycle = instr->cycle; - - switch (i) - { - // Accumulator or Implied addressing - case ASLn: case CLCn: case CLDn: case CLIn: case CLVn: case DEXn: - case DEYn: case INXn: case INYn: case LSRn: case NOPn_: case PHAn: - case PHPn: case PLAn: case PLPn: case ROLn: case RORn: case RTIn: - case RTSn: case SECn: case SEDn: case SEIn: case TAXn: case TAYn: - case TSXn: case TXAn: case TXSn: case TYAn: -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - // Immediate and Relative Addressing Mode Handler - case ADCb: case ANDb: case ANCb_: case ANEb: case ASRb: case ARRb: - case BCCr: case BCSr: case BEQr: case BMIr: case BNEr: case BPLr: - case BRKn: case BVCr: case BVSr: case CMPb: case CPXb: case CPYb: - case EORb: case LDAb: case LDXb: case LDYb: case LXAb: case NOPb_: - case ORAb: case SBCb_: case SBXb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchDataByte; - break; - - // Zero Page Addressing Mode Handler - Read & RMW - case ADCz: case ANDz: case BITz: case CMPz: case CPXz: case CPYz: - case EORz: case LAXz: case LDAz: case LDXz: case LDYz: case ORAz: - case NOPz_: case SBCz: - access++; - case ASLz: case DCPz: case DECz: case INCz: case ISBz: case LSRz: - case ROLz: case RORz: case SREz: case SLOz: case RLAz: case RRAz: - access++; - case SAXz: case STAz: case STXz: case STYz: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; - if (access == READ) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - } else if (access == RMW) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; - } - break; - - // Zero Page with X Offset Addressing Mode Handler - case ADCzx: case ANDzx: case CMPzx: case EORzx: case LDAzx: case LDYzx: - case NOPzx_: case ORAzx: case SBCzx: - access++; - case ASLzx: case DCPzx: case DECzx: case INCzx: case ISBzx: case LSRzx: - case RLAzx: case ROLzx: case RORzx: case RRAzx: case SLOzx: case SREzx: - access++; - case STAzx: case STYzx: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddrX; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - if (access == READ) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - } else if (access == RMW) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; - } - break; - - // Zero Page with Y Offset Addressing Mode Handler - case LDXzy: case LAXzy: - access = READ; - case STXzy: case SAXzy: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddrY; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - if (access == READ) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - } - break; - - // Absolute Addressing Mode Handler - case ADCa: case ANDa: case BITa: case CMPa: case CPXa: case CPYa: - case EORa: case LAXa: case LDAa: case LDXa: case LDYa: case NOPa: - case ORAa: case SBCa: - access++; - case ASLa: case DCPa: case DECa: case INCa: case ISBa: case LSRa: - case ROLa: case RORa: case SLOa: case SREa: case RLAa: case RRAa: - access++; - case JMPw: case JSRw: case SAXa: case STAa: case STXa: case STYa: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddr; - if (access == READ) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - } else if (access == RMW) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; - } - break; - - // Absolute With X Offset Addressing Mode Handler (Read) - case ADCax: case ANDax: case CMPax: case EORax: case LDAax: - case LDYax: case NOPax_: case ORAax: case SBCax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrX; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - break; - - // Absolute X (No page crossing handled) - case ASLax: case DCPax: case DECax: case INCax: case ISBax: - case LSRax: case RLAax: case ROLax: case RORax: case RRAax: - case SLOax: case SREax: - access = RMW; - case SHYax: case STAax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrX2; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - if (access == RMW) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; - } - break; - - // Absolute With Y Offset Addresing Mode Handler (Read) - case ADCay: case ANDay: case CMPay: case EORay: case LASay: - case LAXay: case LDAay: case LDXay: case ORAay: case SBCay: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrY; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - break; - - // Absolute Y (No page crossing handled) - case DCPay: case ISBay: case RLAay: case RRAay: case SLOay: - case SREay: - access = RMW; - case SHAay: case SHSay: case SHXay: case STAay: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighAddrY2; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - if (access == RMW) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; - } - break; - - // Absolute Indirect Addressing Mode Handler - case JMPi: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighPointer; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddr; - break; - - // Indexed with X Preinc Addressing Mode Handler - case ADCix: case ANDix: case CMPix: case EORix: case LAXix: case LDAix: - case ORAix: case SBCix: - access++; - case DCPix: case ISBix: case SLOix: case SREix: case RLAix: case RRAix: - access++; - case SAXix: case STAix: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointerX; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddr; - if (access == READ) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - } else if (access == RMW) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; - } - break; - - // Indexed with Y Postinc Addressing Mode Handler (Read) - case ADCiy: case ANDiy: case CMPiy: case EORiy: case LAXiy: - case LDAiy: case ORAiy: case SBCiy: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddrY; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchEffAddrDataByte; - break; - - // Indexed Y (No page crossing handled) - case DCPiy: case ISBiy: case RLAiy: case RRAiy: case SLOiy: - case SREiy: - access = RMW; - case SHAiy: case STAiy: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowPointer; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchLowEffAddr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchHighEffAddrY2; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - if (access == RMW) { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchPutEffAddrDataByte; - } - break; - - default: - legalMode = false; - break; - } - -#ifdef MOS6510_DEBUG - if (legalMode) - { - cycleCount++; - if (pass) procCycle[cycleCount] = &MOS6510::DebugCycle; - } -#endif // MOS6510_DEBUG - - //--------------------------------------------------------------------------------------- - // Addressing Modes Finished, other cycles are instruction dependent - switch(i) - { - case ADCz: case ADCzx: case ADCa: case ADCax: case ADCay: case ADCix: - case ADCiy: case ADCb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::adc_instr; - break; - - case ANCb_: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::anc_instr; - break; - - case ANDz: case ANDzx: case ANDa: case ANDax: case ANDay: case ANDix: - case ANDiy: case ANDb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::and_instr; - break; - - case ANEb: // Also known as XAA - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ane_instr; - break; - - case ARRb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::arr_instr; - break; - - case ASLn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::asla_instr; - break; - - case ASLz: case ASLzx: case ASLa: case ASLax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::asl_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case ASRb: // Also known as ALR - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::alr_instr; - break; - - case BCCr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bcc_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case BCSr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bcs_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case BEQr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::beq_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case BITz: case BITa: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bit_instr; - break; - - case BMIr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bmi_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case BNEr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bne_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case BPLr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bpl_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case BRKn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushHighPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::brk_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ1Request; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ2Request; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; - break; - - case BVCr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bvc_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case BVSr: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::bvs_instr; -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - break; - - case CLCn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::clc_instr; - break; - - case CLDn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cld_instr; - break; - - case CLIn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cli_instr; - break; - - case CLVn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::clv_instr; - break; - - case CMPz: case CMPzx: case CMPa: case CMPax: case CMPay: case CMPix: - case CMPiy: case CMPb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cmp_instr; - break; - - case CPXz: case CPXa: case CPXb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cpx_instr; - break; - - case CPYz: case CPYa: case CPYb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::cpy_instr; - break; - - case DCPz: case DCPzx: case DCPa: case DCPax: case DCPay: case DCPix: - case DCPiy: // Also known as DCM - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dcm_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case DECz: case DECzx: case DECa: case DECax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dec_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case DEXn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dex_instr; - break; - - case DEYn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::dey_instr; - break; - - case EORz: case EORzx: case EORa: case EORax: case EORay: case EORix: - case EORiy: case EORb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::eor_instr; - break; - -/* HLT // Also known as JAM - case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: - case 0x62: case 0x72: case 0x92: case 0xb2: case 0xd2: case 0xf2: - case 0x02: case 0x12: case 0x22: case 0x32: case 0x42: case 0x52: - case 0x62: case 0x72: case 0x92: case 0xb2: case 0xd2: case 0xf2: - cycleCount++; if (pass) procCycle[cycleCount] = hlt_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; -*/ - - case INCz: case INCzx: case INCa: case INCax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::inc_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case INXn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::inx_instr; - break; - - case INYn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::iny_instr; - break; - - case ISBz: case ISBzx: case ISBa: case ISBax: case ISBay: case ISBix: - case ISBiy: // Also known as INS - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ins_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case JMPw: case JMPi: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::jmp_instr; - break; - - case JSRw: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::jsr_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::jmp_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case LASay: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::las_instr; - break; - - case LAXz: case LAXzy: case LAXa: case LAXay: case LAXix: case LAXiy: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lax_instr; - break; - - case LDAz: case LDAzx: case LDAa: case LDAax: case LDAay: case LDAix: - case LDAiy: case LDAb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lda_instr; - break; - - case LDXz: case LDXzy: case LDXa: case LDXay: case LDXb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ldx_instr; - break; - - case LDYz: case LDYzx: case LDYa: case LDYax: case LDYb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ldy_instr; - break; - - case LSRn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lsra_instr; - break; - - case LSRz: case LSRzx: case LSRa: case LSRax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lsr_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case NOPn_: case NOPb_: - // Should not be required! - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case NOPz_: case NOPzx_: case NOPa: case NOPax_: - // NOPb NOPz NOPzx - Also known as SKBn - // NOPa NOPax - Also known as SKWn - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case LXAb: // Also known as OAL - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::oal_instr; - break; - - case ORAz: case ORAzx: case ORAa: case ORAax: case ORAay: case ORAix: - case ORAiy: case ORAb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ora_instr; - break; - - case PHAn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::pha_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case PHPn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushSR; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case PLAn: -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::pla_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case PLPn: -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopSR; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case RLAz: case RLAzx: case RLAix: case RLAa: case RLAax: case RLAay: - case RLAiy: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rla_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case ROLn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rola_instr; - break; - - case ROLz: case ROLzx: case ROLa: case ROLax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rol_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case RORn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rora_instr; - break; - - case RORz: case RORzx: case RORa: case RORax: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::ror_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case RRAa: case RRAax: case RRAay: case RRAz: case RRAzx: case RRAix: - case RRAiy: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rra_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case RTIn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopSR; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopLowPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopHighPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rti_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case RTSn: -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopLowPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PopHighPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::rts_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case SAXz: case SAXzy: case SAXa: case SAXix: // Also known as AXS - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::axs_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - break; - - case SBCz: case SBCzx: case SBCa: case SBCax: case SBCay: case SBCix: - case SBCiy: case SBCb_: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sbc_instr; - break; - - case SBXb: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sbx_instr; - break; - - case SECn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sec_instr; - break; - - case SEDn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sed_instr; - break; - - case SEIn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sei_instr; - break; - - case SHAay: case SHAiy: // Also known as AXA - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::axa_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case SHSay: // Also known as TAS - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::shs_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - break; - - case SHXay: // Also known as XAS - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::xas_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - break; - - case SHYax: // Also known as SAY - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::say_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - break; - - case SLOz: case SLOzx: case SLOa: case SLOax: case SLOay: case SLOix: - case SLOiy: // Also known as ASO - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::aso_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case SREz: case SREzx: case SREa: case SREax: case SREay: case SREix: - case SREiy: // Also known as LSE - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::lse_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PutEffAddrDataByte; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case STAz: case STAzx: case STAa: case STAax: case STAay: case STAix: - case STAiy: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sta_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case STXz: case STXzy: case STXa: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::stx_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case STYz: case STYzx: case STYa: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::sty_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - break; - - case TAXn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tax_instr; - break; - - case TAYn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tay_instr; - break; - - case TSXn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tsx_instr; - break; - - case TXAn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::txa_instr; - break; - - case TXSn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::txs_instr; - break; - - case TYAn: - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::tya_instr; - break; - - default: - legalInstr = false; - break; - } - - if (!(legalMode || legalInstr)) - { - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::illegal_instr; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - } - else if (!(legalMode && legalInstr)) - { - printf ("\nInstruction 0x%x: Not built correctly.\n\n", i); - exit(1); - } - - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::NextInstr; - cycleCount++; - if (!pass) - { // Pass 1 - Allocate Memory - if (cycleCount) - { -#if defined(_MSC_VER) && (_MSC_VER <= _MSC_VER_BAD_NEW) - typedef void (MOS6510::*ptr2cycle) (void); - instr->cycle = (ptr2cycle*) new char[sizeof (ptr2cycle) *cycleCount]; -#else -# ifdef HAVE_EXCEPTIONS - instr->cycle = new(std::nothrow) (void (MOS6510::*[cycleCount]) (void)); -# else - instr->cycle = new (void (MOS6510::*[cycleCount]) (void)); -# endif -#endif // _MSC_VER - if (!instr->cycle) - goto MOS6510_MemAllocFailed; - } - } - else - instr->opcode = i; - -#if MOS6510_DEBUG > 1 - printf ("."); -#endif - } - - instr->cycles = cycleCount; -#if MOS6510_DEBUG > 1 - printf ("Done [%d Cycles]\n", cycleCount); -#endif - } - - //---------------------------------------------------------------------- - // Build interrupts - for (i = 0; i < 3; i++) - { -#if MOS6510_DEBUG > 1 - printf ("Building Interrupt %d[%02x]..", i, i); -#endif - - // Pass 1 allocates the memory, Pass 2 builds the interrupt - instr = &interruptTable[i]; - instr->cycle = NULL; - instr->opcode = 0; - - for (int pass = 0; pass < 2; pass++) - { - cycleCount = -1; - if (pass) procCycle = instr->cycle; - - switch (i) - { - case oRST: -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::RSTRequest; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; - break; - - case oNMI: -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushHighPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQRequest; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::NMIRequest; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::NMI1Request; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; - break; - - case oIRQ: -#ifdef MOS6510_ACCURATE_CYCLES - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::WasteCycle; -#endif - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushHighPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::PushLowPC; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQRequest; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ1Request; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::IRQ2Request; - cycleCount++; if (pass) procCycle[cycleCount] = &MOS6510::FetchOpcode; - break; - } - - cycleCount++; - if (!pass) - { // Pass 1 - Allocate Memory - if (cycleCount) - { -#if defined(_MSC_VER) && (_MSC_VER <= _MSC_VER_BAD_NEW) - typedef void (MOS6510::*ptr2cycle) (void); - instr->cycle = (ptr2cycle*) new char[sizeof (ptr2cycle) *cycleCount]; -#else -# ifdef HAVE_EXCEPTIONS - instr->cycle = new(std::nothrow) (void (MOS6510::*[cycleCount]) (void)); -# else - instr->cycle = new (void (MOS6510::*[cycleCount]) (void)); -# endif -#endif // _MSC_VER - if (!instr->cycle) - goto MOS6510_MemAllocFailed; - } - } - -#if MOS6510_DEBUG > 1 - printf ("."); -#endif - } - - instr->cycles = cycleCount; -#if MOS6510_DEBUG > 1 - printf ("Done [%d Cycles]\n", cycleCount); -#endif - } - - // Intialise Processor Registers - Register_Accumulator = 0; - Register_X = 0; - Register_Y = 0; - - Cycle_EffectiveAddress = 0; - Cycle_Data = 0; - fetchCycle[0] = &MOS6510::NextInstr; - - dodump = false; - Initialise (); -return; - -MOS6510_MemAllocFailed: - printf ("Unable to allocate enough memory.\n\n"); -exit (-1); -} - -MOS6510::~MOS6510 () -{ - struct ProcessorOperations *instr; - uint i; - - // Remove Opcodes - for (i = 0; i < 0x100; i++) - { - instr = &instrTable[i]; - if (instr->cycle != NULL) delete [] instr->cycle; - } - - // Remove Interrupts - for (i = 0; i < 3; i++) - { - instr = &interruptTable[i]; - if (instr->cycle != NULL) delete [] instr->cycle; - } -} - - -//-------------------------------------------------------------------------// -// Initialise CPU Emulation (Registers) // -void MOS6510::Initialise (void) -{ - // Reset stack - Register_StackPointer = endian_16 (SP_PAGE, 0xFF); - - // Reset Cycle Count - cycleCount = 0; - procCycle = fetchCycle; - - // Reset Status Register - Register_Status = (1 << SR_NOTUSED) | (1 << SR_BREAK); - // FLAGS are set from data directly and do not require - // being calculated first before setting. E.g. if you used - // SetFlags (0), N flag would = 0, and Z flag would = 1. - setFlagsNZ (1); - setFlagC (false); - setFlagV (false); - - // Set PC to some value - Register_ProgramCounter = 0; - // IRQs pending check - interrupts.irqLatch = false; - interrupts.irqRequest = false; - if (interrupts.irqs) - interrupts.irqRequest = true; - - // Signals - aec = true; - rdy = true; - - m_blocked = false; - eventContext.schedule (this, 1); -} - -//-------------------------------------------------------------------------// -// Reset CPU Emulation // -void MOS6510::reset (void) -{ - // Reset Interrupts - interrupts.pending = false; - interrupts.irqs = 0; - interrupts.delay = MOS6510_INTERRUPT_DELAY; - - // Internal Stuff - Initialise (); - - // Requires External Bits - // Read from reset vector for program entry point - endian_16lo8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFC)); - endian_16hi8 (Cycle_EffectiveAddress, envReadMemDataByte (0xFFFD)); - Register_ProgramCounter = Cycle_EffectiveAddress; -// filepos = 0; -} - -//-------------------------------------------------------------------------// -// Module Credits // -void MOS6510::credits (char *sbuffer) -{ // Copy credits to buffer - sprintf (sbuffer, "%sModule : MOS6510 Cycle Exact Emulation\n", sbuffer); - sprintf (sbuffer, "%sWritten By : %s\n", sbuffer, MOS6510_AUTHOR); - sprintf (sbuffer, "%sVersion : %s\n", sbuffer, MOS6510_VERSION); - sprintf (sbuffer, "%sReleased : %s\n", sbuffer, MOS6510_DATE); - sprintf (sbuffer, "%sEmail : %s\n", sbuffer, MOS6510_EMAIL); -} |