Beispiel #1
0
 internal void UpdateTotal(ExecState newExecState)
 {
     CyclesConsumed             += newExecState.CyclesConsumed;
     InstructionsExecutionCount += newExecState.InstructionsExecutionCount;
     UnknownOpCodeCount         += newExecState.UnknownOpCodeCount;
     LastOpCodeWasHandled        = newExecState.LastOpCodeWasHandled;
     LastOpCode = newExecState.LastOpCode;
     PCBeforeLastOpCodeExecuted = newExecState.PCBeforeLastOpCodeExecuted;
 }
Beispiel #2
0
 public CPU(ExecState execState)
 {
     ProcessorStatus = new ProcessorStatus();
     ExecState       = execState;
     // TODO: Inject instruction list?
     InstructionList = InstructionList.GetAllInstructions();
     // TODO: Inject InstructionExecutor?
     _instructionExecutor = new InstructionExecutor();
 }
Beispiel #3
0
        public static ExecState ExecStateAfterInstruction(ulong cyclesConsumed, bool unknownInstruction, byte?lastOpCode, ushort?lastPC)
        {
            var execState = new ExecState();

            execState.InstructionsExecutionCount  = 1;
            execState.CyclesConsumed              = cyclesConsumed;
            execState.InstructionsExecutionCount += unknownInstruction?(ulong)1:(ulong)0;
            execState.PCBeforeLastOpCodeExecuted  = lastPC;
            execState.LastOpCode = lastOpCode;
            return(execState);
        }
Beispiel #4
0
        public ExecState Execute(
            Memory mem,
            ExecOptions execOptions)
        {
            // Collect stats for this invocation of Execute().
            // Whereas the property Cpu.ExecState contains the aggregate stats for all invocations of Execute().
            var thisExecState = new ExecState();

            // Get current cycle count
            bool doNextInstruction = true;

            while (doNextInstruction)
            {
                // Fire event before instruction executes
                OnInstructionToBeExecuted(new CPUInstructionToBeExecutedEventArgs(this, mem));

                // Execute instruction
                ushort PCBeforeInstructionExecuted = PC;
                var    instructionExecutionResult  = _instructionExecutor.Execute(this, mem);

                // Collect stats for this instruction.
                // Whereas the property thisExecState contains the aggregate stats for this invocation of Execute().
                // and the property Cpu.ExecState contains the aggregate stats for all invocations of Execute().
                var instructionExecState = ExecState.ExecStateAfterInstruction(
                    cyclesConsumed: instructionExecutionResult.CyclesConsumed,
                    unknownInstruction: instructionExecutionResult.UnknownInstruction,
                    lastOpCode: instructionExecutionResult.OpCodeByte,
                    lastPC: PCBeforeInstructionExecuted
                    );

                // Update/Aggregate total Cpu.ExecState stats
                ExecState.UpdateTotal(instructionExecState);
                // Update/Aggregate this invocation of Execute() ExecState stats
                thisExecState.UpdateTotal(instructionExecState);

                // Fire "unknown opcode" or "instruction executed" event
                if (instructionExecutionResult.UnknownInstruction)
                {
                    OnUnknownOpCodeDetected(new CPUUnknownOpCodeDetectedEventArgs(this, mem, instructionExecutionResult.OpCodeByte));
                    Debug.WriteLine($"Unknown opcode: {instructionExecutionResult.OpCodeByte.ToHex()}");

                    // Check if we're configured to throw exception when unknown exception occurs
                    if (execOptions.UnknownInstructionThrowsException)
                    {
                        throw new DotNet6502Exception($"Unknown opcode: {instructionExecutionResult.OpCodeByte.ToHex()}");
                    }
                }
                else
                {
                    OnInstructionExecuted(new CPUInstructionExecutedEventArgs(this, mem));
                }

                // Check if we should continue executing instructions
                if (execOptions.CyclesRequested.HasValue && thisExecState.CyclesConsumed >= execOptions.CyclesRequested.Value)
                {
                    doNextInstruction = false;
                }
                if (execOptions.MaxNumberOfInstructions.HasValue && thisExecState.InstructionsExecutionCount >= execOptions.MaxNumberOfInstructions.Value)
                {
                    doNextInstruction = false;
                }
                if (!instructionExecutionResult.UnknownInstruction && execOptions.ExecuteUntilInstruction.HasValue && instructionExecutionResult.OpCodeByte == execOptions.ExecuteUntilInstruction.Value.ToByte())
                {
                    doNextInstruction = false;
                }
                if (execOptions.ExecuteUntilInstructions.Count > 0 && execOptions.ExecuteUntilInstructions.Contains(instructionExecutionResult.OpCodeByte))
                {
                    doNextInstruction = false;
                }
                if (execOptions.ExecuteUntilPC.HasValue && PC == execOptions.ExecuteUntilPC.Value)
                {
                    doNextInstruction = false;
                }
                if (execOptions.ExecuteUntilExecutedInstructionAtPC.HasValue && PCBeforeInstructionExecuted == execOptions.ExecuteUntilExecutedInstructionAtPC.Value)
                {
                    doNextInstruction = false;
                }
            }

            // Return stats for this invocation of Execute();
            return(thisExecState);
        }