Esempio n. 1
0
        /// <summary>
        /// Actually executes the instruction that was determine by the Step phase.
        /// In most cases, the whole of the instrucftion is run, but for some opcodes,
        /// some additional code has to be run.
        /// It is possible for those cases (and conditional jumps) that some extra clock
        /// ticks have to run after execution.
        /// </summary>
        /// <returns>How many clock ticks have to run after the opcode execution</returns>
        internal byte ExecuteInstruction()
        {
            // Prepare for program counter movement, but wait for instruction execution.
            // Overwrite _state.NextPC in the instruction lambdas if you want to implement jumps.
            // NOTE(Cristian): If we don't differentiate this case, the CALL instruction of the
            //                 interrupt will be added to _state.NextPC, which will in turn be written
            //                 into the stack. This means that when we RET, we would have jumped
            //                 into the address we *should* have jumped plus some meaningless offset!
            if (!_state.InterruptInProgress)
            {
                this._state.NextPC = (ushort)(_state.Registers.PC + _state.CurrentInstruction.Length);
            }

            if (!_state.CurrentInstruction.CB)
            {
                CPUInstructions.RunInstruction(this,
                                               (byte)_state.CurrentInstruction.OpCode,
                                               _state.CurrentInstruction.Literal);
            }
            else
            {
                CPUCBInstructions.RunCBInstruction(this,
                                                   (byte)_state.CurrentInstruction.OpCode,
                                                   _state.CurrentInstruction.Literal);
            }

            // Push the next program counter value into the real program counter!
            _state.Registers.PC = this._state.NextPC;

            // We calculate how many more ticks have to run
            byte remainingSteps = GetPostTicks();

            return(remainingSteps);
        }
Esempio n. 2
0
        public void Cycle()
        {
            mtx.WaitOne();
            // Normal Cycle
            reg.CycleCount++;
            var totalClockM = 0;
            var totalClockT = 0;

            if (_halt)
            {
                totalClockM += 1;
                totalClockT += 4;
            }
            else
            {
                var op = memory.ReadByte(reg.PC);
                reg.PC++;
                CPUInstructions.opcodes[op](this);
                totalClockM += reg.lastClockM;
                totalClockT += reg.lastClockT;
            }

            // Check Interrupts
            if (reg.InterruptEnable && reg.EnabledInterrupts != 0 && reg.TriggerInterrupts != 0)
            {
                _halt = false;
                reg.InterruptEnable = false;
                var interruptsFired = reg.EnabledInterrupts & reg.TriggerInterrupts;
                if ((interruptsFired & Flags.INT_VBLANK) > 0)
                {
                    reg.TriggerInterrupts &= (byte)~Flags.INT_VBLANK;
                    CPUInstructions.RSTXX(this, Addresses.INT_VBLANK);  // V-Blank
                    totalClockM += reg.lastClockM;
                    totalClockT += reg.lastClockT;
                }
                else if ((interruptsFired & Flags.INT_LCDSTAT) > 0)
                {
                    Console.WriteLine("Handling LCDSTAT Int");
                    reg.TriggerInterrupts &= (byte)~Flags.INT_LCDSTAT;
                    CPUInstructions.RSTXX(this, Addresses.INT_LCDSTAT); // LCD Stat
                    totalClockM += reg.lastClockM;
                    totalClockT += reg.lastClockT;
                }
                else if ((interruptsFired & Flags.INT_TIMER) > 0)
                {
                    Console.WriteLine("Handling Timer Int");
                    reg.TriggerInterrupts &= (byte)~Flags.INT_TIMER;
                    CPUInstructions.RSTXX(this, Addresses.INT_TIMER);  // Timer
                    totalClockM += reg.lastClockM;
                    totalClockT += reg.lastClockT;
                }
                else if ((interruptsFired & Flags.INT_SERIAL) > 0)
                {
                    Console.WriteLine("Handling Serial Int");
                    reg.TriggerInterrupts &= (byte)~Flags.INT_SERIAL;
                    CPUInstructions.RSTXX(this, Addresses.INT_SERIAL); // Serial
                    totalClockM += reg.lastClockM;
                    totalClockT += reg.lastClockT;
                }
                else if ((interruptsFired & Flags.INT_JOYPAD) > 0)
                {
                    reg.TriggerInterrupts &= (byte)~Flags.INT_JOYPAD;
                    CPUInstructions.RSTXX(this, Addresses.INT_JOYPAD); // Joypad Interrupt
                    totalClockM += reg.lastClockM;
                    totalClockT += reg.lastClockT;
                }
                else
                {
                    reg.InterruptEnable = true;
                }
            }

            clockM += totalClockM;
            clockT += totalClockT;

            if (!stopped)
            {
                // GPU
                gpu.Cycle();

                // Timers
                timer.Increment();
            }

            mtx.ReleaseMutex();
        }