summaryrefslogtreecommitdiff
path: root/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i')
-rw-r--r--plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i409
1 files changed, 409 insertions, 0 deletions
diff --git a/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i
new file mode 100644
index 00000000..bc573d3b
--- /dev/null
+++ b/plugins/sid/sidplay-libs/libsidplay/src/mos6510/cycle_based/sid6510c.i
@@ -0,0 +1,409 @@
+/***************************************************************************
+ sid6510c.i - Sidplay Specific 6510 emulation
+ -------------------
+ begin : Thu May 11 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: sid6510c.i,v $
+ * Revision 1.28 2002/12/03 23:24:52 s_a_white
+ * Let environment know when cpu sleeps in real c64 mode.
+ *
+ * Revision 1.27 2002/12/02 22:19:43 s_a_white
+ * sid_brk fix to prevent it running some of the real brk cycles in old emulation
+ * modes.
+ *
+ * Revision 1.26 2002/11/25 21:07:34 s_a_white
+ * Allow setting of program counter on reset.
+ *
+ * Revision 1.25 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.24 2002/11/19 22:56:25 s_a_white
+ * Sidplay1 modes modified to make them nolonger require the psid driver.
+ *
+ * Revision 1.23 2002/11/01 17:35:27 s_a_white
+ * Frame based support for old sidplay1 modes.
+ *
+ * Revision 1.22 2002/10/15 23:52:14 s_a_white
+ * Fix sidplay2 cpu sleep optimisation and NMIs.
+ *
+ * Revision 1.21 2002/09/23 22:50:55 s_a_white
+ * Reverted update 1.20 as was incorrect. Only need to
+ * change MOS6510 to SID6510 for compliancy.
+ *
+ * Revision 1.20 2002/09/23 19:42:14 s_a_white
+ * Newer compilers don't allow pointers to be taken directly
+ * from base class member functions.
+ *
+ * Revision 1.19 2002/03/12 18:47:13 s_a_white
+ * Made IRQ in sidplay1 compatibility modes behaves like JSR. This fixes tunes
+ * that have kernel switched out.
+ *
+ * Revision 1.18 2002/02/07 18:02:10 s_a_white
+ * Real C64 compatibility fixes. Debug of BRK works again. Fixed illegal
+ * instructions to work like sidplay1.
+ *
+ * Revision 1.17 2002/02/06 17:49:12 s_a_white
+ * Fixed sign comparison warning.
+ *
+ * Revision 1.16 2002/02/04 23:53:23 s_a_white
+ * Improved compatibilty of older sidplay1 modes. Fixed BRK to work like sidplay1
+ * only when stack is 0xff in real mode for better compatibility with C64.
+ *
+ * Revision 1.15 2002/01/28 19:32:16 s_a_white
+ * PSID sample improvements.
+ *
+ * Revision 1.14 2001/10/02 18:00:37 s_a_white
+ * Removed un-necessary cli.
+ *
+ * Revision 1.13 2001/09/18 07:51:39 jpaana
+ * Small fix to rti-processing.
+ *
+ * Revision 1.12 2001/09/03 22:23:06 s_a_white
+ * Fixed faked IRQ trigger on BRK for sidplay1 environment modes.
+ *
+ * Revision 1.11 2001/09/01 11:08:06 s_a_white
+ * Fixes for sidplay1 environment modes.
+ *
+ * Revision 1.10 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.9 2001/07/14 13:17:40 s_a_white
+ * Sidplay1 optimisations moved to here. Stack & PC invalid tests now only
+ * performed on a BRK.
+ *
+ * Revision 1.8 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.7 2001/03/22 22:40:07 s_a_white
+ * Replaced tabs characters.
+ *
+ * Revision 1.6 2001/03/21 22:26:24 s_a_white
+ * Fake interrupts now been moved into here from player.cpp. At anytime it's
+ * now possible to ditch this compatibility class and use the real thing.
+ *
+ * Revision 1.5 2001/03/09 22:28:03 s_a_white
+ * Speed optimisation update.
+ *
+ * Revision 1.4 2001/02/13 21:02:16 s_a_white
+ * Small tidy up and possibly a small performace increase.
+ *
+ * Revision 1.3 2000/12/11 19:04:32 s_a_white
+ * AC99 Update.
+ *
+ ***************************************************************************/
+
+#include "sid6510c.h"
+
+
+SID6510::SID6510 (EventContext *context)
+:MOS6510(context),
+ m_mode(sid2_envR),
+ m_framelock(false)
+{ // Ok start all the hacks for sidplay. This prevents
+ // execution of code in roms. For real c64 emulation
+ // create object from base class! Also stops code
+ // rom execution when bad code switches roms in over
+ // itself.
+ for (uint i = 0; i < OPCODE_MAX; i++)
+ {
+ procCycle = instrTable[i].cycle;
+ if (procCycle == NULL) continue;
+
+ for (uint n = 0; n < instrTable[i].cycles; n++)
+ {
+ if (procCycle[n] == &SID6510::illegal_instr)
+ { // Rev 1.2 (saw) - Changed nasty union to reinterpret_cast
+ procCycle[n] = reinterpret_cast <void (MOS6510::*)()>
+ (&SID6510::sid_illegal);
+ }
+ else if (procCycle[n] == &SID6510::jmp_instr)
+ { // Stop jumps into rom code
+ procCycle[n] = reinterpret_cast <void (MOS6510::*)()>
+ (&SID6510::sid_jmp);
+ }
+ else if (procCycle[n] == &SID6510::cli_instr)
+ { // No overlapping IRQs allowed
+ procCycle[n] = reinterpret_cast <void (MOS6510::*)()>
+ (&SID6510::sid_cli);
+ }
+ }
+ }
+
+ { // Since no real IRQs, all RTIs mapped to RTS
+ // Required for fix bad tunes in old modes
+ uint n;
+ procCycle = instrTable[RTIn].cycle;
+ for (n = 0; n < instrTable[RTIn].cycles; n++)
+ {
+ if (procCycle[n] == &SID6510::PopSR)
+ {
+ procCycle[n] = reinterpret_cast <void (MOS6510::*)()>
+ (&SID6510::sid_rti);
+ break;
+ }
+ }
+
+ procCycle = interruptTable[oIRQ].cycle;
+ for (n = 0; n < interruptTable[oIRQ].cycles; n++)
+ {
+ if (procCycle[n] == &SID6510::IRQRequest)
+ {
+ procCycle[n] = reinterpret_cast <void (MOS6510::*)()>
+ (&SID6510::sid_irq);
+ break;
+ }
+ }
+ }
+
+ { // Support of sidplays BRK functionality
+ procCycle = instrTable[BRKn].cycle;
+ for (uint n = 0; n < instrTable[BRKn].cycles; n++)
+ {
+ if (procCycle[n] == &SID6510::PushHighPC)
+ {
+ procCycle[n] = reinterpret_cast <void (MOS6510::*)()>
+ (&SID6510::sid_brk);
+ break;
+ }
+ }
+ }
+
+ // Used to insert busy delays into the CPU emulation
+ delayCycle[0] = reinterpret_cast <void (MOS6510::*)()>
+ (&SID6510::sid_delay);
+}
+
+void SID6510::reset (uint_least16_t pc, uint8_t a, uint8_t x, uint8_t y)
+{ // Reset the processor
+ reset ();
+
+ // Registers not touched by a reset
+ Register_Accumulator = a;
+ Register_X = x;
+ Register_Y = y;
+ Register_ProgramCounter = pc;
+}
+
+void SID6510::reset ()
+{
+ m_sleeping = false;
+ // Call inherited reset
+ MOS6510::reset ();
+}
+
+// Send CPU is about to sleep. Only a reset or
+// interrupt will wake up the processor
+void SID6510::sleep ()
+{ // Simulate a delay for JMPw
+ m_delayClk = eventContext.getTime ();
+ m_sleeping = true;
+ procCycle = delayCycle;
+ cycleCount = 0;
+ eventContext.cancel (this);
+ envSleep ();
+
+ // Check for outstanding interrupts
+ if (interrupts.irqs)
+ {
+ interrupts.irqs--;
+ triggerIRQ ();
+ }
+ else if (interrupts.pending)
+ {
+ m_sleeping = false;
+ eventContext.schedule (this, 1);
+ }
+}
+
+void SID6510::FetchOpcode (void)
+{
+ if (m_mode == sid2_envR)
+ {
+ MOS6510::FetchOpcode ();
+ return;
+ }
+
+ // Sid tunes end by wrapping the stack. For compatibilty it
+ // has to be handled.
+ m_sleeping |= (endian_16hi8 (Register_StackPointer) != SP_PAGE);
+ m_sleeping |= (endian_32hi16 (Register_ProgramCounter) != 0);
+ if (!m_sleeping)
+ MOS6510::FetchOpcode ();
+
+ if (m_framelock == false)
+ {
+ m_framelock = true;
+ // Simulate sidplay1 frame based execution
+ while (!m_sleeping)
+ MOS6510::clock ();
+ sleep ();
+ m_framelock = false;
+ }
+}
+
+
+//**************************************************************************************
+// For sidplay compatibility implement those instructions which don't behave properly.
+//**************************************************************************************
+void SID6510::sid_brk (void)
+{
+ if (m_mode == sid2_envR)
+ {
+ MOS6510::PushHighPC ();
+ return;
+ }
+
+ sei_instr ();
+#if !defined(NO_RTS_UPON_BRK)
+ sid_rts ();
+#endif
+ FetchOpcode ();
+}
+
+void SID6510::sid_jmp (void)
+{ // For sidplay compatibility, inherited from environment
+ if (m_mode == sid2_envR)
+ { // If a busy loop then just sleep
+ if (Cycle_EffectiveAddress != instrStartPC)
+ jmp_instr ();
+ else
+ {
+ Register_ProgramCounter = Cycle_EffectiveAddress;
+ sleep ();
+ }
+ return;
+ }
+
+ if (envCheckBankJump (Cycle_EffectiveAddress))
+ jmp_instr ();
+ else
+ sid_rts ();
+}
+
+// Will do a full rts in 1 cycle, to
+// destroy current function and quit
+void SID6510::sid_rts (void)
+{
+ PopLowPC();
+ PopHighPC();
+ rts_instr();
+}
+
+void SID6510::sid_cli (void)
+{
+ if (m_mode == sid2_envR)
+ cli_instr ();
+}
+
+void SID6510::sid_rti (void)
+{
+ if (m_mode == sid2_envR)
+ {
+ PopSR ();
+ return;
+ }
+
+ // Fake RTS
+ sid_rts ();
+ FetchOpcode ();
+}
+
+void SID6510::sid_irq (void)
+{
+ MOS6510::IRQRequest ();
+ if (m_mode != sid2_envR)
+ { // RTI behaves like RTI in sidplay1 modes
+ Register_StackPointer++;
+ }
+}
+
+// Sidplay Suppresses Illegal Instructions
+void SID6510::sid_illegal (void)
+{
+ if (m_mode == sid2_envR)
+ {
+ MOS6510::illegal_instr ();
+ return;
+ }
+#ifdef MOS6510_DEBUG
+ DumpState ();
+#endif
+}
+
+void SID6510::sid_delay (void)
+{
+ cycleCount = 0;
+ if (++m_delayCycles >= 3)
+ {
+ (void) interruptPending ();
+ m_delayCycles = 0;
+ }
+}
+
+
+//**************************************************************************************
+// Sidplay compatibility interrupts. Basically wakes CPU if it is m_sleeping
+//**************************************************************************************
+void SID6510::triggerRST (void)
+{ // All modes
+ MOS6510::triggerRST ();
+ if (m_sleeping)
+ {
+ m_sleeping = false;
+ eventContext.schedule (this, 1);
+ }
+}
+
+void SID6510::triggerNMI (void)
+{ // Only in Real C64 mode
+ if (m_mode == sid2_envR)
+ {
+ MOS6510::triggerNMI ();
+ if (m_sleeping)
+ {
+ m_delayCycles = eventContext.getTime (m_delayClk) % 3;
+ m_sleeping = false;
+ eventContext.schedule (this, 1);
+ }
+ }
+}
+
+void SID6510::triggerIRQ (void)
+{
+ switch (m_mode)
+ {
+ default:
+#ifdef MOS6510_DEBUG
+ if (dodump)
+ {
+ printf ("****************************************************\n");
+ printf (" Fake IRQ Routine\n");
+ printf ("****************************************************\n");
+ }
+#endif
+ return;
+ case sid2_envR:
+ MOS6510::triggerIRQ ();
+ if (m_sleeping)
+ { // Simulate busy loop
+ m_delayCycles = eventContext.getTime (m_delayClk) % 3;
+ m_sleeping = false;
+ eventContext.schedule (this, 1);
+ }
+ }
+}