void Reset (bool fPress_) { // Set CPU operating mode g_fReset = fPress_; if (g_fReset) { // Certain registers are initialised on every reset I = R = R7 = IFF1 = IFF2 = 0; PC = 0x0000; regs.halted = 0; bOpcode = 0x00; // not after EI // Index prefix not active pHlIxIy = pNewHlIxIy = &HL; // Clear the CPU events queue InitCpuEvents(); // Schedule the first end of line event, and an update check 3/4 through the frame AddCpuEvent(evtEndOfFrame, TSTATES_PER_FRAME); AddCpuEvent(evtInputUpdate, TSTATES_PER_FRAME*3/4); // Re-initialise memory (for configuration changes) and reset I/O IO::Init(); Memory::Init(); // Refresh the debugger and re-test breakpoints Debug::Refresh(); } // Set up the fast reset for first power-on else if (GetOption(fastreset)) g_nTurbo |= TURBO_BOOT; }
void Tape::NextEdge (DWORD dwTime_) { libspectrum_error error; if (fEar) keyboard |= BORD_EAR_MASK; else keyboard &= ~BORD_EAR_MASK; if (!g_nTurbo) pDAC->Output(fEar ? 0xa0 : 0x80); libspectrum_dword tstates; int nFlags; // Fetch details of the next edge, and the time until it's due error = libspectrum_tape_get_next_edge(&tstates, &nFlags, pTape); if (error) { Stop(); return; } if (nFlags & LIBSPECTRUM_TAPE_FLAGS_LEVEL_LOW) fEar = false; else if (nFlags & LIBSPECTRUM_TAPE_FLAGS_LEVEL_HIGH) fEar = true; else if (!(nFlags & LIBSPECTRUM_TAPE_FLAGS_NO_EDGE)) fEar = !fEar; // End of tape block? if ((nFlags & LIBSPECTRUM_TAPE_FLAGS_BLOCK)) { // Stop the tape as it'll restart when required Stop(); } else { // Timings are in 3.5MHz t-states, so convert to SAM t-states tstates = tstates*(REAL_TSTATES_PER_SECOND/1000) + tremain; libspectrum_dword tadd = tstates/(SPECTRUM_TSTATES_PER_SECOND/1000); tremain = tstates % (SPECTRUM_TSTATES_PER_SECOND/1000); // Schedule an event to activate the edge AddCpuEvent(evtTapeEdge, dwTime_+tadd); } }
// Execute the CPU event specified void ExecuteEvent (CPU_EVENT sThisEvent) { switch (sThisEvent.nEvent) { case evtStdIntEnd: // Reset the interrupt as we're done status_reg |= (STATUS_INT_FRAME | STATUS_INT_LINE); break; case evtMidiOutIntStart: // Begin the MIDI_OUT interrupt and add an event to end it status_reg &= ~STATUS_INT_MIDIOUT; AddCpuEvent(evtMidiOutIntEnd, sThisEvent.dwTime + MIDI_INT_ACTIVE_TIME); break; case evtMidiOutIntEnd: // Reset the interrupt and clear the 'transmitting' bit in LPEN as we're done status_reg |= STATUS_INT_MIDIOUT; lpen &= ~LPEN_TXFMST; break; case evtLineIntStart: { // Begin the line interrupt and add an event to end it status_reg &= ~STATUS_INT_LINE; AddCpuEvent(evtStdIntEnd, sThisEvent.dwTime + INT_ACTIVE_TIME); AddCpuEvent(evtLineIntStart, sThisEvent.dwTime + TSTATES_PER_FRAME); break; } case evtEndOfFrame: { // Signal a FRAME interrupt, and start the interrupt counter status_reg &= ~STATUS_INT_FRAME; AddCpuEvent(evtStdIntEnd, sThisEvent.dwTime + INT_ACTIVE_TIME); AddCpuEvent(evtEndOfFrame, sThisEvent.dwTime + TSTATES_PER_FRAME); // Signal end of the frame g_fBreak = true; break; } case evtInputUpdate: // Update the input in the centre of the screen (well away from the frame boundary) to avoid the ROM // keyboard scanner discarding key presses when it thinks keys have bounced. In old versions this was // the cause of the first key press on the boot screen only clearing it (took AGES to track down!) IO::UpdateInput(); // Schedule the next input check at the same position in the next frame AddCpuEvent(evtInputUpdate, sThisEvent.dwTime + TSTATES_PER_FRAME); break; case evtMouseReset: pMouse->Reset(); break; case evtBlueAlphaClock: // Clock the sampler, scheduling the next event if it's still running if (pBlueAlpha->Clock()) AddCpuEvent(evtBlueAlphaClock, sThisEvent.dwTime + BLUE_ALPHA_CLOCK_TIME); break; case evtAsicStartup: // ASIC is now responsive IO::WakeAsic(); break; case evtTapeEdge: Tape::NextEdge(sThisEvent.dwTime); break; } }