/// <summary> /// Sets the button status /// </summary> /// <param name="machineState"> /// The machine state. /// </param> private void SetButtonStatus(IMachineState machineState) { for (int i = 0; i < this.buttonList.Count(); i++) { this.buttonList.ElementAt(i).BackColor = machineState.Keys[i] ? Color.Green : Color.Transparent; } }
public void GivenANewlyInitialisedSM() { MachineBuilder = new InitialMachineBuilder(); MachineDefinition = MachineBuilder.GetMachineDefinition(); MachineState = MachineDefinition.NewMachineInstance(new State()); }
private static void Dispatch <TInternalState, TEvent>(TEvent evnt , IMachineState <TInternalState> internalState , InternalState <TInternalState> currentState , IReadOnlyDictionary <InternalState <TInternalState>, InternalState <TInternalState> > relations , IEnumerable <Func <object, object> > eventInterceptors , MachineConfiguration <TInternalState> config , bool outerTransitionsTakePrecedence , Func <string, InternalState <TInternalState> > lookup) { var currentStates = Misc <TInternalState> .FindAllStates(relations, currentState); if (!outerTransitionsTakePrecedence) { currentStates.Reverse(); } var nextState = DispatchToStates(evnt, internalState, currentStates, eventInterceptors, config, lookup); if (nextState != null && nextState != currentStates.Last()) { nextState = TransitionTo((object)evnt, internalState, relations, nextState, eventInterceptors, false, config, lookup); } if (nextState != null) { UpdateStateHistories(internalState, relations, nextState); } }
public void GivenANewlyInitialisedSM() { machine.AddEventInterceptor((evnt) => { Console.WriteLine("Rx'd Event: {0}", evnt.GetType().Name); return(evnt); }); machine.AddEventInterceptor((evnt) => { Console.WriteLine("Rx'd Event2: {0}", evnt.GetType().Name); return(evnt); }); MachineDefinition = machine.GetMachineDefinition(config => { /* Name the Statemachine */ config.Name("FastSlow"); /* Define where the logging information is going! */ config.Logger(x => Console.WriteLine(x)); /* Define a function that will be used to serialise an event to a string */ config.LogEventWith(x => x.ToString()); /* Hmmm - Every state machine needs a unique Id - Get this one from here, otherwise it's a GUID! */ config.UniqueId.FromProperty(p => p.Id); }); MachineState = MachineDefinition.NewMachineInstance(new SlowFastStoppedInternalState()); }
/// <summary> /// Loads a ROM, from a given path, in memory /// </summary> /// <param name="romPath"> /// The rom path. /// </param> /// <param name="machineState"> /// The machine state. /// </param> public void LoadRom(string romPath, IMachineState machineState) { if (File.Exists(romPath)) { var rom = new FileStream(romPath, FileMode.Open); if (rom.Length == 0) { throw new Exception(string.Format("File '{0}' empty or damaged", romPath)); } int index; // Load rom starting at 0x200 for (index = 0; index < rom.Length; index++) { machineState.Memory[C8Constants.StartRomAddress + index] = (byte)rom.ReadByte(); } machineState.NumberOfOpcodeBytes = index; rom.Close(); } else { throw new FileNotFoundException(string.Format("The file '{0}' does not exist", romPath)); } }
public static IDisposable AsObservable <TInternalState, TEvent>( this IObservable <TEvent> t , MachineDefinition <TInternalState> machineDefinition , IMachineState <TInternalState> internalState) { return(t.Subscribe(x => MachineRunner.Dispatch(machineDefinition, internalState, x))); }
public DisassemblerControl(IMachineState state) { // TODO: maybe I don't need the ENTIRE state _state = state; _textArea = new RichTextArea { //BackgroundColor = Color.FromRgb(0), //TextColor = Color.FromGrayscale(1, 1), Font = new Font("Monospace", 10), Width = 300, ReadOnly = true, }; //var stream = new MemoryStream(); //var sw = new StreamWriter(stream); //sw.WriteLine("{\\rtf1 Hi {\\b Hi } \\line \\par asdf }"); //sw.Flush(); var stream = DisassembleAndFormat(100); _textArea.Buffer.Load(stream, RichTextAreaFormat.Rtf); Content = _textArea; }
/// <summary> /// Fx65 - LD Vx, [I] /// Read registers V0 through Vx from machineState.Memory starting at location I. /// The interpreter reads values from machineState.Memory starting at location I into registers V0 through Vx. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void LoadFromValueInRegisterIntoAllRegisters(IMachineState machineState) { for (int i = 0; i <= machineState.XRegisterFromCurrentOpcode; i++) { machineState.VRegisters[i] = machineState.Memory[machineState.IndexRegister + i]; } }
/// <summary> /// Fx29 - LD F, Vx /// Set I = location of sprite for digit Vx. /// The value of I is set to the location for the hexadecimal sprite corresponding to the value of Vx. /// See section 2.4, Display, for more information on the Chip-8 hexadecimal font. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void LoadFontSpriteLocationFromValueInRegister(IMachineState machineState) { // Comments from NGEmu about this opcode /*Mmm... basically, set the machineState.Memory pointer I to the location of the character of the hexadecimal stored in register VX. * So... if it's FA29, you look in register VA and see what value it holds. * If it's F129, you look in register V1 and see what value it holds. * You can assume that the value stored in those registers only goes from 0x0 to 0xF. * Now... your emulator should have a table of sprite data already preset somewhere in the machineState.Memory (preferrably in the locations before 0x200). * These are sprite of characters from 0 to F, and they are 4x5 each in dimension. * Which means... mmm... the number 0 should be somewhat like this in binary data: * * 1111 0000 * 1001 0000 * 1001 0000 * 1001 0000 * 1111 0000 * * If you have to ask, that's because the draw instruction draws 8 bits at a time.*/ ushort character = machineState.VRegisters[machineState.XRegisterFromCurrentOpcode]; // We assume that the value for character goes from 0x0 to 0xF and that each digit has size 5 (5 rows per digit) // Fonts are loaded starting at 0x0 machineState.IndexRegister = (ushort)(5 * character); }
/// <summary> /// Initializes a new instance of the <see cref="C8Engine"/> class. /// Engine constructor with an injected machine state /// </summary> /// <param name="machineState"> /// An injected machine state /// </param> /// <param name="pluginService"> /// The plugin Service. /// </param> /// <param name="configurationService"> /// The configuration Service. /// </param> /// <param name="romService"> /// The rom Service. /// </param> /// <param name="opcodeMapService"> /// The opcode Map Service. /// </param> public C8Engine( IMachineState machineState, IPluginService pluginService, IConfigurationService configurationService, IRomService romService, IOpcodeMapService opcodeMapService) { // Injects the machine state this.machineState = machineState; // Inject the plugin service this.PluginService = pluginService; // Inject the configuration service this.ConfigurationService = configurationService; // Inject the ROM Service this.RomService = romService; // Inject the opcode map service this.OpcodeMapService = opcodeMapService; // Gets the instruction map this.instructionMap = this.OpcodeMapService.GetInstructionMap(); // Loads the user saved configuration this.LoadSavedEngineSettings(); // Loads the plugins this.LoadPlugins(); }
/// <summary> /// ExA1 - SKNP Vx /// Skip next instruction if key with the value of Vx is not pressed. /// Checks the keyboard, and if the key corresponding to the value of Vx is currently in the up position, /// PC is increased by 2. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void SkipNextInstructionIfRegisterNotEqualsKeyPressed(IMachineState machineState) { if (!machineState.Keys[machineState.VRegisters[machineState.XRegisterFromCurrentOpcode]]) { machineState.IncreaseProgramCounter(); } }
/// <summary> /// Dxyn - DRW Vx, Vy, nibble /// Display n-byte sprite starting at machineState.Memory location I at (Vx, Vy), set VF = collision. /// The interpreter reads n bytes from machineState.Memory, starting at the address stored in I. /// These bytes are then displayed as sprites on screen at coordinates (Vx, Vy). /// Sprites are XORed onto the existing screen. /// If this causes any pixels to be erased, VF is set to 1, otherwise it is set to 0. /// If the sprite is positioned so part of it is outside the coordinates of the display, it wraps around to the opposite side of the screen. /// See instruction 8xy3 for more information on XOR, and section 2.4, Display, for more information on the Chip-8 screen and sprites. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void DrawSprite(IMachineState machineState) { var numbytes = (ushort)(machineState.CurrentOpcode & 0x000F); var positionX = machineState.VRegisters[machineState.XRegisterFromCurrentOpcode]; var positionY = machineState.VRegisters[machineState.YRegisterFromCurrentOpcode]; for (var rowNum = 0; rowNum < numbytes; rowNum++) { ushort currentpixel = machineState.Memory[machineState.IndexRegister + rowNum]; // We assume sprites are always 8 pixels wide for (var colNum = 0; colNum < 8; colNum++) { if ((currentpixel & (0x80 >> colNum)) != 0) { int positioninGraphics = (positionX + colNum + ((positionY + rowNum) * C8Constants.ResolutionWidth)) % (C8Constants.ResolutionWidth * C8Constants.ResolutionHeight); // Make sure we get a value inside boundaries if (machineState.Graphics[positioninGraphics]) { // Collision! machineState.VRegisters[0xF] = 1; } machineState.Graphics[positioninGraphics] ^= true; } } machineState.IsDrawFlagSet = true; } }
/// <summary> /// Cxkk - RND Vx, byte /// Set Vx = random byte AND kk. /// The interpreter generates a random number from 0 to 255, which is then ANDed with the value kk. /// The results are stored in Vx. See instruction 8xy2 for more information on AND. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void LoadRandomIntoRegister(IMachineState machineState) { var randomnumber = (ushort)new Random().Next(0, 255); machineState.VRegisters[machineState.XRegisterFromCurrentOpcode] = (ushort)(randomnumber & (machineState.CurrentOpcode & 0x00FF)); }
public static bool IsInState <TInternalState>(IMachineState <TInternalState> internalState, MachineDefinition <TInternalState> machineDefinition, State state) { return(Misc <TInternalState> .FindAllStates(machineDefinition.ParentStates, internalState.CurrentState) .Any(currentState => currentState.Name == state.Name)); }
/// <summary> /// Sets the registry Values /// </summary> /// <param name="machineState"> /// The machine state /// </param> private void SetRegisterValues(IMachineState machineState) { for (int i = 0; i < this.registerList.Count(); i++) { this.registerList.ElementAt(i).Text = machineState.VRegisters[i].ToString("X"); } }
/// <summary> /// 9xy0 - SNE Vx, Vy /// Skip next instruction if Vx != Vy. /// The values of Vx and Vy are compared, and if they are not equal, the program counter is increased by 2. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void SkipNextInstructionIfRegisterNotEqualsRegister(IMachineState machineState) { if (machineState.VRegisters[machineState.XRegisterFromCurrentOpcode] != machineState.VRegisters[machineState.YRegisterFromCurrentOpcode]) { machineState.IncreaseProgramCounter(); } }
/// <summary> /// Binds the list of opcodes to the data grid view /// </summary> /// <param name="machineState"> /// The machine state /// </param> public void BindOpcodeList(IMachineState machineState) { this.opcodeList = this.GetDecodedInstructionsFromMemory(machineState); this.MemoryAddressColumn.DataPropertyName = "Item1"; this.RawOpcodeColumn.DataPropertyName = "Item2"; this.MnemonicColumn.DataPropertyName = "Item3"; this.dataGridViewOpcodes.DataSource = this.opcodeList; }
/// <summary> /// 2nnn - CALL addr /// Call subroutine at nnn. /// The interpreter increments the machineState.Stack pointer, then puts the current PC on the top of the machineState.Stack. /// The PC is then set to nnn. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void CallAtAdress(IMachineState machineState) { // Program counter will be increased right after the instruction fetch // So theres no need to increase the program counter before pushing machineState.Stack.Push(machineState.ProgramCounter); machineState.ProgramCounter = (ushort)(machineState.CurrentOpcode & 0x0FFF); }
/// <summary> /// 4xkk - SNE Vx, byte /// Skip next instruction if Vx != kk. /// The interpreter compares register Vx to kk, and if they are not equal, increments the program counter by 2. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void SkipNextInstructionIfRegisterNotEqualsImmediate(IMachineState machineState) { if (machineState.VRegisters[machineState.XRegisterFromCurrentOpcode] != (machineState.CurrentOpcode & 0x00FF)) { machineState.IncreaseProgramCounter(); } }
public static IEnumerator <byte> Passive(IMachineState state) { var pc = state.Registers.PC.Value; while (true) { yield return(state.Memory[pc++]); } }
public void GivenANewlyInitialisedSM() { MachineBuilder = new HistoryStateMachineBuilder(); MachineDefinition = MachineBuilder.GetMachineDefinition(); InternalState = MachineDefinition.NewMachineInstance(new HistoryState()); // Given - The Machine is started MachineRunner.Start(MachineDefinition, InternalState); }
/// <summary> /// The refresh disassembler status. /// </summary> /// <param name="machineState"> /// The monitored machine state /// </param> public void RefreshDisassemblerStatus(IMachineState machineState) { this.SetButtonStatus(machineState); this.SetRegisterValues(machineState); this.SetStackValues(machineState); this.SetTimerValues(machineState); this.SetProgramCounter(machineState); this.SetDrawFlag(machineState); }
public bool checkInfo(IMachineState state) { if (!Info.IsOn) { return(false); } var needWriteMemoryCheck = IsNeedWriteMemoryCheck; IsNeedWriteMemoryCheck = false; // reset flag for next cycle if (IsForceStop) { IsForceStop = false; // reset stop flag for next cycle return(true); // return true to force stop } if (needWriteMemoryCheck && checkInfoMemory(state)) { return(true); } lock (lockingObj) { if (debuggerStop) { debuggerStop = false; return(true); } } switch (Info.AccessType) { //e.g.: fZ == 1 case BreakPointConditionType.flagVsValue: //e.g.: PC == #9C40 case BreakPointConditionType.registryVsValue: //e.g.: (PC) == #AFC9 - instruction breakpoint; must be here because the registry change must be taking into account, not memory change case BreakPointConditionType.registryMemoryReferenceVsValue: if (Info.CheckBreakpoint()) { if (Info.IsMulticonditional) { return(Info.CheckSecondCondition()); } else { return(true); } } else { return(false); } default: return(false); } }
public static string Trace(IMachineState state) { var pc = state.Registers.PC.Value; var disassembledInstr = Disassembler.DisassembleInstruction(InstructionLookahead.Passive(state)); var bytes = string.Join(" ", Enumerable.Range(0, disassembledInstr.Length).Select(i => state.Memory[pc + i].ToString("X2"))); var hl = state.Memory[state.Registers.HL.Value]; return($"0x{pc:X4}: {bytes,-10} {disassembledInstr.Text,-15} {state.Registers.ToString()}; (HL)={hl:X2}"); }
/// <summary> /// Sets the stack Values /// </summary> /// <param name="machineState"> /// The machine state /// </param> private void SetStackValues(IMachineState machineState) { this.stackList.ForEach(x => x.Text = @"0"); for (int i = 0; i < machineState.Stack.Count; i++) { this.stackList.ElementAt(i).Text = machineState.Stack.ElementAtOrDefault(i).ToString("X"); } }
/// <summary> /// Returns a list of of the Events that the state machine will currently perform an action on. /// </summary> /// <typeparam name="TInternalState"></typeparam> /// <param name="internalState"></param> /// <param name="machineDefinition"></param> /// <returns>Will not return Events.EntryEvents or exit Events.ExitEvent events</returns> public static IEnumerable <Type> CurrentlyActionableEvents <TInternalState>(IMachineState <TInternalState> internalState, MachineDefinition <TInternalState> machineDefinition) { return(Misc <TInternalState> .FindAllStates(machineDefinition.ParentStates, internalState.CurrentState) .SelectMany(x => x.Handlers) .Select(x => x.Key) .Where(x => x != typeof(Events.EntryEvent)) .Where(x => x != typeof(Events.ExitEvent)) .Distinct() .ToList()); }
public void DispenseProduct() { vendingMachineState.DispenseProduct(); // Product has been dispensed so vending Machine changed the // internal state to 'NoMoneyState' if (vendingMachineState is HasMoneyState) { vendingMachineState = new NoMoney(); Console.WriteLine("VendingMachine internal state has been moved to : " + vendingMachineState.GetType().Name); } }
public void SelectProductAndInsertMoney(int amount, string productName) { vendingMachineState.SelectProductAndInsertMoney(amount, productName); // Money has been inserted so vending Machine internal state // changed to 'hasMoneyState' if (vendingMachineState is NoMoney) { vendingMachineState = new HasMoneyState(); Console.WriteLine("VendingMachine internal state has been moved to : " + vendingMachineState.GetType().Name); } }
/// <summary> /// Fx33 - LD B, Vx /// Store BCD representation of Vx in machineState.Memory locations I, I+1, and I+2. /// The interpreter takes the decimal value of Vx, /// and places the hundreds digit in machineState.Memory at location in I, /// the tens digit at location I+1, /// and the ones digit at location I+2. /// </summary> /// <param name="machineState"> /// The machine State. /// </param> public void LoadBcdRepresentationFromRegister(IMachineState machineState) { machineState.Memory[machineState.IndexRegister] = (byte)(machineState.VRegisters[machineState.XRegisterFromCurrentOpcode] / 100); // Hundreds machineState.Memory[machineState.IndexRegister + 1] = (byte)((machineState.VRegisters[machineState.XRegisterFromCurrentOpcode] / 10) % 10); // Tens machineState.Memory[machineState.IndexRegister + 2] = (byte)(machineState.VRegisters[machineState.XRegisterFromCurrentOpcode] % 10); // Ones }
private bool checkInfoMemory(IMachineState state) { if (!Info.IsOn) { return(false); } lock (lockingObj) { if (debuggerStop) { debuggerStop = false; return(true); } } ushort leftValue = 0; switch (Info.AccessType) { // e.g.: (#9C40) != #2222 case BreakPointConditionType.memoryVsValue: if (Info.CheckBreakpoint()) { if (Info.IsMulticonditional) { return(Info.CheckSecondCondition()); } else { return(true); } } else { return(false); } default: break; } //condition if (Info.IsConditionEquals) // is equal { return(leftValue == Info.RightValue); } else { return(leftValue != Info.RightValue); } }
private bool checkInfo(IMachineState state) { if (!Info.isOn) return false; ushort leftValue = 0; ushort rightValue = 0; switch (Info.accessType) { // e.g.: PC == #9C40 case BreakPointConditionType.registryVsValue: leftValue = DebuggerManager.getRegistryValueByName(state.CPU.regs, Info.leftCondition); rightValue = Info.rightValue; break; // e.g.: (#9C40) != #2222 case BreakPointConditionType.memoryVsValue: leftValue = state.ReadMemory(Info.leftValue); rightValue = Info.rightValue; break; // e.g.: (PC) == #D1 - instruction breakpoint case BreakPointConditionType.registryMemoryReferenceVsValue: leftValue = state.ReadMemory(DebuggerManager.getRegistryValueByName(state.CPU.regs, DebuggerManager.getRegistryFromReference(Info.leftCondition))); rightValue = Info.rightValue; if (rightValue > 0xFF) //check on 2 bytes right condition, e.g.: (PC) == #5EED { int hiByte = DebuggerManager.getRegistryValueByName(state.CPU.regs, DebuggerManager.getRegistryFromReference(Info.leftCondition)) + 1; if (hiByte > 0xFFFF) hiByte = 0; leftValue += Convert.ToUInt16(state.ReadMemory(Convert.ToUInt16(hiByte)) * 256); } break; default: break; } //condition if (Info.conditionTypeSign == "==") // is equal { if (leftValue == rightValue) return true; } else if (Info.conditionTypeSign == "!=") // is not equal { if (leftValue != rightValue) return true; }; return false; }