Exemple #1
0
        private IEnumerable <Action> RunAndYieldAssertions(IInstructionBlock block, DecodedBlock decodedBlock, ExecutionContext context)
        {
            yield return(() => block.Address.ShouldBe(decodedBlock.Address, nameof(block.Address)));

            yield return(() => block.Length.ShouldBe(decodedBlock.Length, nameof(block.Length)));

            yield return(() => block.DebugInfo.ShouldNotBeNullOrEmpty(nameof(block.DebugInfo)));

            yield return(() => block.HaltCpu.ShouldBe(block.HaltCpu, nameof(block.HaltCpu)));

            yield return(() => block.HaltPeripherals.ShouldBe(block.HaltPeripherals, nameof(block.HaltPeripherals)));

            var timings         = block.ExecuteInstructionBlock(context.MockRegisters.Object, context.Mmu.Object, context.Alu.Object, context.Io.Object);
            var expectedTimings = decodedBlock.Timings + _runtimeTimings;

            yield return(() => timings.ShouldBe(expectedTimings));

            // TODO: also assert I & R on Z80
            if (_halt)
            {
                yield return(() => context.MockRegisters.VerifySet(x => x.ProgramCounter = context.SyncedProgramCounter));
            }

            foreach (var assertion in _assertions)
            {
                yield return(() => assertion(context));
            }
        }
Exemple #2
0
        /// <summary>
        /// Executes the specified instruction block.
        /// </summary>
        /// <param name="instructionBlock">The instruction block.</param>
        /// <returns></returns>
        protected async Task ExecuteInstructionBlockAsync(IInstructionBlock instructionBlock)
        {
            if (_paused != null)
            {
                await _paused.Task.ConfigureAwait(false);
            }

            var timings = instructionBlock.ExecuteInstructionBlock(_registers, _mmu, _alu, _peripheralManager);

            if (instructionBlock.HaltCpu)
            {
                _interruptManager.Halt();
                if (instructionBlock.HaltPeripherals)
                {
                    _peripheralManager.Signal(ControlSignal.Halt);
                    _interruptManager.AddResumeTask(() => _peripheralManager.Signal(ControlSignal.Resume));
                }
            }

            if (_interruptManager.IsHalted)
            {
                // Did we request an interrupt or run a HALT opcode.
                if (_interruptManager.IsInterrupted || instructionBlock.HaltCpu)
                {
                    // Notify halt success before halting
                    _interruptManager.NotifyHalt();
                    _interruptAddress = await _interruptManager.WaitForNextInterrupt().ConfigureAwait(false);

                    // Push the program counter onto the stack
                    _registers.StackPointer = (ushort)(_registers.StackPointer - 2);
                    _mmu.WriteWord(_registers.StackPointer, _registers.ProgramCounter);
                }
                else
                {
                    // Dummy halt so we don't block threads trigerring interrupts when disabled.
                    _interruptManager.NotifyHalt();
                }

                _interruptManager.NotifyResume();
            }
            else
            {
                _interruptAddress = null;
            }

            _instructionTimer.SyncToTimings(timings);
        }