void PushLocalVariableOnToTheStack(IProgramCounter programCounter, IVariableManager localVariables) { var variableName = programCounter.GetNullTerminatedString(); var value = localVariables.GetVariable(variableName); _stack.PushValue(value); }
public bool Run(IProgramCounter programCounter, IVariableManager localVariables) { while (RunScriptCommand(programCounter, localVariables)) { } return(programCounter.Eof); }
void SetLocalVariableToBottomValueOfStack(IProgramCounter programCounter, IVariableManager localVariables) { var value = _stack.PopValue(); var variableName = programCounter.GetNullTerminatedString(); localVariables.SetVariable(variableName, value); }
void PushGlobalVariableOnToTheStack(IProgramCounter programCounter) { var variableName = programCounter.GetNullTerminatedString(); var value = _variableManager.GetVariable(variableName); _stack.PushValue(value); }
void MoveScriptPointerIfStackValueIsZero(IProgramCounter programCounter) { var distance = programCounter.GetInteger(); if (_stack.PopValue() == 0) { programCounter.MoveScriptPointer(distance); } }
void SetUpScriptData(Action <BinaryWriter> action) { var memoryStream = new MemoryStream(); var bw = new BinaryWriter(memoryStream); action(bw); _programCounter = new ProgramCounter(); _programCounter.SetScript(new SingleScript("Script Name", memoryStream.ToArray())); }
void ProcessFnRoutine(IProgramCounter programCounter, IVariableManager localVariables) { var parameterCount = programCounter.GetInteger(); var fnRoutineName = programCounter.GetNullTerminatedString(); var parameters = GetStackParametersIfRequired(parameterCount); var result = _fnRoutinesCaller.CallFnRoutine(localVariables, fnRoutineName, parameters); _stack.PushValue(result); }
bool ProcessDropSkipPauseNotZero(IProgramCounter programCounter) { var distance = programCounter.GetInteger(); var value = _stack.PopValue(); switch (value) { case (int)ScriptReturn.Continue: return(true); case (int)ScriptReturn.PauseRepeat: programCounter.MoveScriptPointer(distance - 4); return(false); case (int)ScriptReturn.Pause: return(false); } return(true); }
public Processor6502(IClock clock, IProgramCounter programCounter) { clock.OnTick = Tick; _programCounter = programCounter; _registers = new RegisterManager(); _alu = new Alu(_registers); _opcodes = new Dictionary <OpCode, Action> { { OpCode.ADC_Immediate, () => _alu.ADC(Immediate()) }, { OpCode.ADC_ZeroPage, () => _alu.ADC(ZeroPage()) }, { OpCode.ADC_ZeroPageX, () => _alu.ADC(ZeroPageX()) }, { OpCode.ADC_Absolute, () => _alu.ADC(Absolute()) }, { OpCode.ADC_AbsoluteX, () => _alu.ADC(AbsoluteX()) }, { OpCode.ADC_AbsoluteY, () => _alu.ADC(AbsoluteY()) }, { OpCode.ADC_ZeroPageIndirectX, () => _alu.ADC(ZeroPageIndirectX()) }, { OpCode.ADC_ZeroPageYIndirect, () => _alu.ADC(ZeroPageYIndirect()) }, { OpCode.AND_Immediate, () => _alu.AND(Immediate()) }, { OpCode.AND_ZeroPage, () => _alu.AND(ZeroPage()) }, { OpCode.AND_ZeroPageX, () => _alu.AND(ZeroPageX()) }, { OpCode.AND_Absolute, () => _alu.AND(Absolute()) }, { OpCode.AND_AbsoluteX, () => _alu.AND(AbsoluteX()) }, { OpCode.AND_AbsoluteY, () => _alu.AND(AbsoluteY()) }, { OpCode.AND_ZeroPageIndirectX, () => _alu.AND(ZeroPageIndirectX()) }, { OpCode.AND_ZeroPageYIndirect, () => _alu.AND(ZeroPageYIndirect()) }, { OpCode.ASL, () => _registers.A = _alu.ASL(_registers.A) }, { OpCode.ASL_ZeroPage, () => SetByte(GetNextByte(), _alu.ASL) }, { OpCode.ASL_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, _alu.ASL) }, { OpCode.ASL_Absolute, () => SetByte(GetUShort(), _alu.ASL) }, { OpCode.ASL_AbsoluteX, () => SetByte(GetUShort(), _registers.X, _alu.ASL) }, { OpCode.BCC, () => BranchIfNotSet(ProcessorFlags.Carry) }, { OpCode.BCS, () => BranchIfSet(ProcessorFlags.Carry) }, { OpCode.BNE, () => BranchIfNotSet(ProcessorFlags.Zero) }, { OpCode.BEQ, () => BranchIfSet(ProcessorFlags.Zero) }, { OpCode.BPL, () => BranchIfNotSet(ProcessorFlags.Negative) }, { OpCode.BMI, () => BranchIfSet(ProcessorFlags.Negative) }, { OpCode.BVC, () => BranchIfNotSet(ProcessorFlags.Overflow) }, { OpCode.BVS, () => BranchIfSet(ProcessorFlags.Overflow) }, { OpCode.BRK, BRK }, { OpCode.CMP_Immediate, () => _alu.CMP(Immediate()) }, { OpCode.CMP_ZeroPage, () => _alu.CMP(ZeroPage()) }, { OpCode.CMP_ZeroPageX, () => _alu.CMP(ZeroPageX()) }, { OpCode.CMP_Absolute, () => _alu.CMP(Absolute()) }, { OpCode.CMP_AbsoluteX, () => _alu.CMP(AbsoluteX()) }, { OpCode.CMP_AbsoluteY, () => _alu.CMP(AbsoluteY()) }, { OpCode.CMP_ZeroPageIndirectX, () => _alu.CMP(ZeroPageIndirectX()) }, { OpCode.CMP_ZeroPageYIndirect, () => _alu.CMP(ZeroPageYIndirect()) }, { OpCode.CPX_Immediate, () => _alu.CPX(Immediate()) }, { OpCode.CPX_ZeroPage, () => _alu.CPX(ZeroPage()) }, { OpCode.CPX_Absolute, () => _alu.CPX(Absolute()) }, { OpCode.CPY_Immediate, () => _alu.CPY(Immediate()) }, { OpCode.CPY_ZeroPage, () => _alu.CPY(ZeroPage()) }, { OpCode.CPY_Absolute, () => _alu.CPY(Absolute()) }, { OpCode.CLC, () => _registers.Status &= ~ProcessorFlags.Carry }, { OpCode.CLD, () => _registers.Status &= ~ProcessorFlags.Decimal }, { OpCode.CLI, () => _registers.Status &= ~ProcessorFlags.InterruptDisable }, { OpCode.CLV, () => _registers.Status &= ~ProcessorFlags.Overflow }, { OpCode.DEC_ZeroPage, () => SetByte(GetNextByte(), _alu.DEC) }, { OpCode.DEC_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, _alu.DEC) }, { OpCode.DEC_Absolute, () => SetByte(GetUShort(), _alu.DEC) }, { OpCode.DEC_AbsoluteX, () => SetByte(GetUShort(), _registers.X, _alu.DEC) }, { OpCode.DEX, () => _registers.X = _alu.DEC(_registers.X) }, { OpCode.DEY, () => _registers.Y = _alu.DEC(_registers.Y) }, { OpCode.EOR_Immediate, () => _alu.EOR(Immediate()) }, { OpCode.EOR_ZeroPage, () => _alu.EOR(ZeroPage()) }, { OpCode.EOR_ZeroPageX, () => _alu.EOR(ZeroPageX()) }, { OpCode.EOR_Absolute, () => _alu.EOR(Absolute()) }, { OpCode.EOR_AbsoluteX, () => _alu.EOR(AbsoluteX()) }, { OpCode.EOR_AbsoluteY, () => _alu.EOR(AbsoluteY()) }, { OpCode.EOR_ZeroPageIndirectX, () => _alu.EOR(ZeroPageIndirectX()) }, { OpCode.EOR_ZeroPageYIndirect, () => _alu.EOR(ZeroPageYIndirect()) }, { OpCode.INC_ZeroPage, () => SetByte(GetNextByte(), _alu.INC) }, { OpCode.INC_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, _alu.INC) }, { OpCode.INC_Absolute, () => SetByte(GetUShort(), _alu.INC) }, { OpCode.INC_AbsoluteX, () => SetByte(GetUShort(), _registers.X, _alu.INC) }, { OpCode.INX, () => _registers.X = _alu.INC(_registers.X) }, { OpCode.INY, () => _registers.Y = _alu.INC(_registers.Y) }, { OpCode.JMP_Absolute, () => _programCounter.Set(GetUShort()) }, { OpCode.JMP_Indirect, () => _programCounter.Set(GetUShort(GetUShort())) }, { OpCode.JSR, () => JSR() }, { OpCode.LDA_Immediate, () => _alu.LDA(Immediate()) }, { OpCode.LDA_ZeroPage, () => _alu.LDA(ZeroPage()) }, { OpCode.LDA_ZeroPageX, () => _alu.LDA(ZeroPageX()) }, { OpCode.LDA_Absolute, () => _alu.LDA(Absolute()) }, { OpCode.LDA_AbsoluteX, () => _alu.LDA(AbsoluteX()) }, { OpCode.LDA_AbsoluteY, () => _alu.LDA(AbsoluteY()) }, { OpCode.LDA_ZeroPageIndirectX, () => _alu.LDA(ZeroPageIndirectX()) }, { OpCode.LDA_ZeroPageYIndirect, () => _alu.LDA(ZeroPageYIndirect()) }, { OpCode.LDX_Immediate, () => _alu.LDX(Immediate()) }, { OpCode.LDX_ZeroPage, () => _alu.LDX(ZeroPage()) }, { OpCode.LDX_ZeroPageY, () => _alu.LDX(GetByte(GetNextByte(), _registers.Y)) }, { OpCode.LDX_Absolute, () => _alu.LDX(Absolute()) }, { OpCode.LDX_AbsoluteY, () => _alu.LDX(AbsoluteY()) }, { OpCode.LDY_Immediate, () => _alu.LDY(Immediate()) }, { OpCode.LDY_ZeroPage, () => _alu.LDY(ZeroPage()) }, { OpCode.LDY_ZeroPageX, () => _alu.LDY(ZeroPageX()) }, { OpCode.LDY_Absolute, () => _alu.LDY(Absolute()) }, { OpCode.LDY_AbsoluteX, () => _alu.LDY(AbsoluteX()) }, { OpCode.LSR, () => _registers.A = _alu.LSR(_registers.A) }, { OpCode.LSR_ZeroPage, () => SetByte(GetNextByte(), _alu.LSR) }, { OpCode.LSR_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, _alu.LSR) }, { OpCode.LSR_Absolute, () => SetByte(GetUShort(), _alu.LSR) }, { OpCode.LSR_AbsoluteX, () => SetByte(GetUShort(), _registers.X, _alu.LSR) }, { OpCode.NOP, () => { } }, { OpCode.ORA_Immediate, () => _alu.ORA(Immediate()) }, { OpCode.ORA_ZeroPage, () => _alu.ORA(ZeroPage()) }, { OpCode.ORA_ZeroPageX, () => _alu.ORA(ZeroPageX()) }, { OpCode.ORA_Absolute, () => _alu.ORA(Absolute()) }, { OpCode.ORA_AbsoluteX, () => _alu.ORA(AbsoluteX()) }, { OpCode.ORA_AbsoluteY, () => _alu.ORA(AbsoluteY()) }, { OpCode.ORA_ZeroPageIndirectX, () => _alu.ORA(ZeroPageIndirectX()) }, { OpCode.ORA_ZeroPageYIndirect, () => _alu.ORA(ZeroPageYIndirect()) }, { OpCode.PHA, () => Push(_registers.A) }, { OpCode.PLA, () => _registers.A = Pull() }, { OpCode.PHP, () => Push((byte)_registers.Status) }, { OpCode.PLP, () => _registers.Status = (ProcessorFlags)Pull() }, { OpCode.ROL, () => _registers.A = _alu.ROL(_registers.A) }, { OpCode.ROL_ZeroPage, () => SetByte(GetNextByte(), _alu.ROL) }, { OpCode.ROL_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, _alu.ROL) }, { OpCode.ROL_Absolute, () => SetByte(GetUShort(), _alu.ROL) }, { OpCode.ROL_AbsoluteX, () => SetByte(GetUShort(), _registers.X, _alu.ROL) }, { OpCode.ROR, () => _registers.A = _alu.ROR(_registers.A) }, { OpCode.ROR_ZeroPage, () => SetByte(GetNextByte(), _alu.ROR) }, { OpCode.ROR_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, _alu.ROR) }, { OpCode.ROR_Absolute, () => SetByte(GetUShort(), _alu.ROR) }, { OpCode.ROR_AbsoluteX, () => SetByte(GetUShort(), _registers.X, _alu.ROR) }, { OpCode.RTS, RTS }, { OpCode.RTI, RTI }, { OpCode.SBC_Immediate, () => _alu.SBC(Immediate()) }, { OpCode.SBC_ZeroPage, () => _alu.SBC(ZeroPage()) }, { OpCode.SBC_ZeroPageX, () => _alu.SBC(ZeroPageX()) }, { OpCode.SBC_Absolute, () => _alu.SBC(Absolute()) }, { OpCode.SBC_AbsoluteX, () => _alu.SBC(AbsoluteX()) }, { OpCode.SBC_AbsoluteY, () => _alu.SBC(AbsoluteY()) }, { OpCode.SBC_ZeroPageIndirectX, () => _alu.SBC(ZeroPageIndirectX()) }, { OpCode.SBC_ZeroPageYIndirect, () => _alu.SBC(ZeroPageYIndirect()) }, { OpCode.SEC, () => _registers.Status |= ProcessorFlags.Carry }, { OpCode.SED, () => _registers.Status |= ProcessorFlags.Decimal }, { OpCode.SEI, () => _registers.Status |= ProcessorFlags.InterruptDisable }, { OpCode.STA_ZeroPage, () => SetByte(GetNextByte(), v => _registers.A) }, { OpCode.STA_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, v => _registers.A) }, { OpCode.STA_Absolute, () => SetByte(GetUShort(), v => _registers.A) }, { OpCode.STA_AbsoluteX, () => SetByte(GetUShort(), _registers.X, v => _registers.A) }, { OpCode.STA_AbsoluteY, () => SetByte(GetUShort(), _registers.Y, v => _registers.A) }, { OpCode.STA_ZeroPageIndirectX, () => SetByte(GetUShort(GetNextByte(_registers.X)), v => _registers.A) }, { OpCode.STA_ZeroPageYIndirect, () => SetByte(GetUShort(GetNextByte()), _registers.Y, v => _registers.A) }, { OpCode.STX_ZeroPage, () => SetByte(GetNextByte(), v => _registers.X) }, { OpCode.STX_ZeroPageY, () => SetByte(GetNextByte(), _registers.Y, v => _registers.X) }, { OpCode.STX_Absolute, () => SetByte(GetUShort(), v => _registers.X) }, { OpCode.STY_ZeroPage, () => SetByte(GetNextByte(), v => _registers.Y) }, { OpCode.STY_ZeroPageX, () => SetByte(GetNextByte(), _registers.X, v => _registers.Y) }, { OpCode.STY_Absolute, () => SetByte(GetUShort(), v => _registers.Y) }, { OpCode.TAX, () => _alu.TAX() }, { OpCode.TAY, () => _alu.TAY() }, { OpCode.TSX, () => _registers.X = _stackPointer }, { OpCode.TXA, () => _alu.TXA() }, { OpCode.TXS, () => _stackPointer = _registers.X }, { OpCode.TYA, () => _alu.TYA() }, }; }
bool RunScriptCommand(IProgramCounter programCounter, IVariableManager localVariables) { if (programCounter.Eof) { throw new Exception($"Unexpected end of script found in '{programCounter.GetScriptName()}'"); } var command = programCounter.GetCommand(); switch ((ScriptToken)command) { case ScriptToken.PushIntValue: _stack.PushValue(programCounter.GetInteger()); break; case ScriptToken.PushStringValue: _stack.PushValue(programCounter.GetNullTerminatedString()); break; case ScriptToken.PushGlobalVariable: // 4 PushGlobalVariableOnToTheStack(programCounter); break; case ScriptToken.PopGlobalVariable: // 5 SetGlobalVariableToBottomValueOfStack(programCounter); break; case ScriptToken.Jfalse: // 6 MoveScriptPointerIfStackValueIsZero(programCounter); break; case ScriptToken.Jtrue: // 7 MoveScriptPointerIfStackValueIsNotZero(programCounter); break; case ScriptToken.Jall: // 8 MoveScriptPointerAlways(programCounter); break; case ScriptToken.Add: // 9 _stack.Add(); break; case ScriptToken.Subtract: // 10 _stack.Subtract(); break; case ScriptToken.Multiply: // 11 _stack.Multiply(); break; case ScriptToken.Divide: // 12 _stack.Divide(); break; case ScriptToken.Negate: // 13 _stack.Negate(); break; case ScriptToken.LogicalNot: // 14 _stack.LogicalNot(); break; case ScriptToken.Lt: // 15 _stack.Lt(); break; case ScriptToken.Gt: // 16 _stack.Gt(); break; case ScriptToken.Lte: // 17 _stack.Lte(); break; case ScriptToken.Gte: // 18 _stack.Gte(); break; case ScriptToken.VariableEquals: // 19 _stack.VariableEquals(); break; case ScriptToken.LogicalAnd: // 20 _stack.LogicalAnd(); break; case ScriptToken.LogicalOr: // 21 _stack.LogicalOr(); break; case ScriptToken.CallFnRoutine: // 22 ProcessFnRoutine(programCounter, localVariables); break; case ScriptToken.DropStackValue: // 23 return(_stack.PopValue() == 0); case ScriptToken.EndScript: // 24 return(false); case ScriptToken.DropSkipPauseNotZero: // 25 return(ProcessDropSkipPauseNotZero(programCounter)); case ScriptToken.PauseScript: // 26 return(false); case ScriptToken.PushLocalVariable: // 27 PushLocalVariableOnToTheStack(programCounter, localVariables); break; case ScriptToken.PopLocalVariable: // 28 SetLocalVariableToBottomValueOfStack(programCounter, localVariables); break; default: throw new InvalidOperationException($"Invalid Script Command {command}"); } return(true); }
void MoveScriptPointerAlways(IProgramCounter programCounter) { var distance = programCounter.GetInteger(); programCounter.MoveScriptPointer(distance); }