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)); } }
/// <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); }