{"id":14965192,"url":"https://github.com/openrakis/spice86","last_synced_at":"2026-04-02T15:49:17.079Z","repository":{"id":37740586,"uuid":"441631821","full_name":"OpenRakis/Spice86","owner":"OpenRakis","description":"Reverse engineer and rewrite real mode DOS programs! ","archived":false,"fork":false,"pushed_at":"2025-05-11T17:52:56.000Z","size":23868,"stargazers_count":519,"open_issues_count":46,"forks_count":27,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-05-11T18:35:25.765Z","etag":null,"topics":["assembly","avaloniaui","cross-platform","debugger","disassembler","dos","dotnet","emulator","gdb","gdb-commands","linux","macos","reverse-engineering","windows"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/OpenRakis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-12-25T07:57:10.000Z","updated_at":"2025-05-08T19:38:06.000Z","dependencies_parsed_at":"2023-09-22T22:50:18.371Z","dependency_job_id":"32bd682f-8bd2-465f-81d3-dffb02565ebe","html_url":"https://github.com/OpenRakis/Spice86","commit_stats":{"total_commits":1709,"total_committers":8,"mean_commits":213.625,"dds":0.2878876535985957,"last_synced_commit":"fdcd2656cda4aca743e576fcf486a849acb4fca3"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FSpice86","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FSpice86/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FSpice86/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/OpenRakis%2FSpice86/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/OpenRakis","download_url":"https://codeload.github.com/OpenRakis/Spice86/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254160375,"owners_count":22024568,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["assembly","avaloniaui","cross-platform","debugger","disassembler","dos","dotnet","emulator","gdb","gdb-commands","linux","macos","reverse-engineering","windows"],"created_at":"2024-09-24T13:34:21.067Z","updated_at":"2026-04-02T15:49:17.064Z","avatar_url":"https://github.com/OpenRakis.png","language":"C#","readme":"# Spice86 - A PC emulator for real mode reverse engineering\n\n![Linux](https://img.shields.io/badge/-Linux-grey?logo=linux)\n![macOS](https://img.shields.io/badge/-OSX-black?logo=apple)\n![Windows](https://img.shields.io/badge/-Windows-red?logo=windows)\n[![.NET Build](https://github.com/OpenRakis/Spice86/actions/workflows/prerelease.yml/badge.svg)](https://github.com/OpenRakis/Spice86/actions/workflows/prerelease.yml)\n[![NuGet](https://img.shields.io/nuget/v/Spice86.svg)](https://www.nuget.org/packages/Spice86)\n![Licence](https://img.shields.io/badge/License-Apache_2.0-44cc11.svg)\n[![downloads](https://img.shields.io/nuget/dt/Spice86)](https://www.nuget.org/packages/Spice86)\n\nSpice86 is a tool to execute, reverse engineer and rewrite real mode DOS programs for which source code is not available.\n\nReleases are available [on Nuget](https://www.nuget.org/packages/Spice86/).\n\nPre-releases are also available [on the Release page](https://github.com/OpenRakis/Spice86/releases/tag/latest)\n\nNOTE: This is a port, and a continuation from the [original Java Spice86](https://github.com/kevinferrare/spice86).\n\nIt requires [.NET 10](https://dotnet.microsoft.com/en-us/download/dotnet/10.0) and runs on Windows, macOS, and Linux.\n\n## Approach\n\nRewriting a program from only the binary is a hard task.\n\nSpice86 is a tool that helps you do so with a methodic divide and conquer approach.\n\nGeneral process:\n\n- You start by emulating the program in the Spice86 emulator.\n- At the end of each run, the emulator dumps some runtime data (memory dump and execution flow)\n- You load those data into [ghidra](https://github.com/NationalSecurityAgency/ghidra) via the [spice86-ghidra-plugin](https://github.com/OpenRakis/spice86-ghidra-plugin)\n- The plugin converts the assembly instructions in the memory dump to C# that can be loaded into spice86 and used either partially or completely instead of the assembly code.\n- This allows you to gradually reimplement the assembly code with your C# methods\n- This is helpful because:\n  - Small sequences of assembly can be statically analyzed and are generally easy to translate to a higher level language.\n  - You work all the time with a fully working version of the program so it is relatively easy to catch mistakes early.\n  - Rewriting code function by function allows you to discover the intent of the author.\n\n## Running your exe\n\n| Command | Description |\n|---------|-------------|\n| `Spice86 -e file.exe` | Run the specified executable |\n| `Spice86 -e file.com` | Run a COM file |\n| `Spice86 -e file.bin` | Run a BIOS file |\n\n## Dumping data\n\n| Setting | Description |\n|---------|-------------|\n| Environment Variable | `SPICE86_DUMPS_FOLDER` - Set this to control the base directory where data is dumped |\n| Command Line | Use `--RecordedDataDirectory` to specify the base dump location |\n| Default Location | Current directory if neither of the above is specified |\n\n**Note:** Regardless of the base directory setting, dumps are always placed in a subdirectory named with the program's SHA-256 hash. This ensures that multiple executables from the same game (e.g., SETUP.EXE, GAME.EXE) have isolated dump folders.\n\nThe emulator dumps the following files:\n\n- **spice86dumpMemoryDump.bin**: Snapshot of the real mode address space\n- **spice86dumpExecutionFlow.json**: Contains function addresses, labels, and executed instructions\n\nWhen there is already data in the specified location, the emulator will load it first and complement it.\n\n### CPU Heavy Logging\n\nFor detailed debugging, you can enable CPU heavy logging which records every executed instruction to a file.\n\n**⚠️ Warning:** This feature has a significant performance impact and should only be used for debugging purposes.\n\n| Setting | Description |\n|---------|-------------|\n| `--CpuHeavyLog` | Enables CPU heavy logging (default: false) |\n| `--CpuHeavyLogDumpFile` | Custom path for the log file (optional). If set, will enable CpuHeavyLog as well. Default Location: `{DumpDirectory}/cpu_heavy.log` |\n\n**Log Format:** Each line contains: `SegmentedAddress InstructionString`\n\n**Example:**\n\n```\n017D:0000 mov AX,0xDD1D\n017D:0003 call near 0xE4AD\n017D:E4AD mov SI,0x0080\n```\n\n**Usage:**\n\n```bash\n# Enable with default location\nSpice86 -e program.exe --CpuHeavyLog\n\n# Use custom log file path\nSpice86 -e program.exe --CpuHeavyLog --CpuHeavyLogDumpFile \"C:\\logs\\cpu.log\"\n```\n\n## Command line options\n\n```\n  --Debug                            (Default: false) Starts the program paused and pauses once again when stopping.\n  --Cycles                           (Default: null) Target CPU cycles per ms, for the rare speed sensitive game. 3000 by default. Overrides Instructions per second option below if used.\n  --Xms                              (Default: true) Enables 15 MB of XMS memory.\n  --Ems                              (Default: true) Enables EMS memory. EMS adds 8 MB of memory accessible to DOS programs through the EMM Page Frame.\n  --A20Gate                          (Default: false) Disables the 20th address line to support programs relying on the rollover of memory addresses above the HMA (slightly above 1 MB).\n  -m, --Mt32RomsPath                 Zip file or directory containing the MT-32 ROM files\n  -c, --CDrive                       Path to C drive, default is exe parent\n  -r, --RecordedDataDirectory        Directory to dump data to when not specified otherwise. If blank dumps to SPICE86_DUMPS_FOLDER, and if not defined dumps to a sub directory named with the program SHA 256 signature\n  -e, --Exe                          Required. Path to executable\n  -a, --ExeArgs                      List of parameters to give to the emulated program\n  -x, --ExpectedChecksum             Hexadecimal string representing the expected SHA256 checksum of the emulated program\n  -f, --FailOnUnhandledPort          (Default: false) If true, will fail when encountering an unhandled IO port. Useful to check for unimplemented hardware. false by default.\n  -g, --GdbPort                      GDB port. If 0, GDB server will be disabled. Default is 10000.\n  -o, --OverrideSupplierClassName    Name of a class that will generate the initial function information. See documentation for more information.\n  -p, --ProgramEntryPointSegment     (Default: 4096) Segment where to load the program. DOS PSP and MCB will be created before it.\n  -u, --UseCodeOverride              (Default: true) \u003ctrue or false\u003e if false it will use the names provided by overrideSupplierClassName but not the code\n  -i, --InstructionsPerSecond        \u003cnumber of instructions that have to be executed by the emulator to consider a second passed\u003e if blank will use time based timer.\n  -t, --TimeMultiplier               (Default: 1) \u003ctime multiplier\u003e if \u003e1 will go faster, if \u003c1 will go slower.\n  -h, --HeadlessMode [Mode]          (Default: false) Headless mode. The mode 'Minimal' does not use any UI components, 'Avalonia' uses the full UI and consumes a bit more memory.\n  -l, --VerboseLogs                  (Default: false) Enable verbose level logs\n  -w, --WarningLogs                  (Default: false) Enable warning level logs\n  -s, --SilencedLogs                 (Default: false) Disable all logs\n  -i, --InitializeDOS                (Default: true) Install DOS interrupt vectors or not.\n  --CpuHeavyLog                      (Default: false) Enable CPU heavy logging. Logs every executed instruction to a file. Warning: significant performance impact.\n  --CpuHeavyLogDumpFile              Custom file path for CPU heavy log output. If not specified, defaults to {DumpDirectory}/cpu_heavy.log\n  --AsmRenderingStyle                Style of the ASM rendering. Spice86 or DosBox.\n  --StructureFile                    Path to a C header file that describes the structures in the application. Works best with exports from IDA or Ghidra\n  --mcp-http-port                    (Default: 8081) Port for the MCP HTTP server\n  --help                             Display this help screen.\n  --version                          Display version information.\n```\n\n### Sound Blaster and OPL/Adlib Gold Options\n\n- SbType: Sound Blaster card type. Values: None, SB1, SB2, SBPro1, SBPro2, Sb16, GameBlaster, AdlibGold.\n- SbIrq: Sound Blaster IRQ line. Default is 7. Common values: 5, 7, 9, 10.\n- SbDma: Sound Blaster 8-bit DMA channel. Default is 1. Common values: 0, 1, 3.\n- SbHdma: Sound Blaster 16-bit high DMA channel. Default is 5. Common values: 5, 6, 7.\n- SbBase: Sound Blaster base I/O address (hex). Default is 0x220. Common values: 0x220, 0x240, 0x260, 0x280.\n- OplMode: OPL synthesis mode. Values: None, Opl2, DualOpl2, Opl3, Opl3Gold. Default is Opl3.\n- SbMixer: Enable Sound Blaster mixer control of OPL voices. Default is true.\n\n## Dynamic analysis\n\nSpice86 speaks the [GDB](https://www.gnu.org/software/gdb/) remote protocol:\n\n- it supports most of the commands you need to debug.\n- it also provides custom GDB commands to do dynamic analysis.\n\n### Connecting to GDB\n\nThe GDB server is always started along with the program to execute unless option is set to 0.\nDefault port is 10000.\n\nIf you want to pause before starting execution to setup breakpoints and so on, use the --Debug option.\n\nHere is how to connect from GDB command line client and how to set the architecture:\n\n```\n(gdb) target remote localhost:10000\n(gdb) set architecture i8086\n```\n\n### Vanilla GDB\n\nYou can add breakpoints, step, view memory and so on.\n\nExample with a breakpoint on VGA VRAM writes:\n\n```\n(gdb) watch *0xA0000\n```\n\nViewing assembly:\n\n```\n(gdb) layout asm\n```\n\nRemoving a breakpoint:\n\n```\n(gdb) remove 1\n```\n\nSearching for a sequence of bytes in memory (start address 0, length F0000, ascii bytes of 'Spice86' string):\n\n```\n(gdb) find /b 0x0, 0xF0000, 0x53, 0x70, 0x69, 0x63, 0x65, 0x38, 0x36\n```\n\nGDB does not support x86 real mode segmented addressing, so pointers need to refer to the actual physical address in memory. VRAM at address A000:0000 would be 0xA0000 in GDB.\n\nSimilarly, The $pc variable in GDB will be exposed by Spice86 as the physical address pointed by CS:IP.\n\n### Custom GDB commands (where the magic happens)\n\nThe list of custom commands can be displayed like this:\n\n```\n(gdb) monitor help\n```\n\n#### Dump information about current run\n\n```\n(gdb) monitor dumpall\n```\n\nDumps everything described below in one shot. Files are created in the dump folder as explained [here](https://github.com/OpenRakis/Spice86#dumping-data)\nSeveral files are produced:\n\n- spice86dumpMemoryDump.bin: Snapshot of the real mode address space. Contains the instructions that are actually loaded and executed. They may differ from the exe you are running because DOS programs can rewrite some of their instructions / load additional modules in memory.\n- spice86dumpExecutionFlow.json: Contains information used by the [spice86-ghidra-plugin](https://github.com/OpenRakis/spice86-ghidra-plugin) to make sense of the memory dump, like addresses of the functions, the labels, the instructions that have been executed ...\n\n#### Special breakpoints\n\nBreak after x emulated CPU Cycles:\n\n```\n(gdb) monitor breakCycles 1000\n```\n\nBreak at the end of the emulated program:\n\n```\n(gdb) monitor breakStop\n```\n\n## Seer\n\nFor a pleasing and productive experience with GDB, the\n[seerGDB](https://github.com/epasveer/seer) client is highly recommended.\n\nAt best, use the configuration file `spice86.seer` provided in the `doc` directory ([here](doc/spice86.seer)): run Seer with `seergdb --project spice86.seer`.\n\nIf you use a different port for gdb, adjust `spice86.seer` correspondingly.\n\nAlso, while in Seer, set Settings/Configuration/Assembly/Disassembly Mode to\n“Length”, otherwise the Assembly View won't work.\n\n## Emulator features\n\n| Component | Support Level |\n|-----------|--------------|\n| **CPU** | 8086/8088 fully implemented and tested |\n|  | 80186 (BOUND instruction missing) |\n|  | 80286 (protected mode not implemented) |\n|  | 80386 (partial support, protected mode not implemented) |\n|  | Only 16-bit instructions fully supported |\n|  | Most 32-bit instructions implemented but not fully tested |\n|  | No FPU except detection instructions |\n| **Memory** | 1MB address space with segmented addressing |\n|  | A20 Gate support |\n|  | EMS 3.2 implemented |\n|  | XMS 4.0 is implemented |\n|  | HMA is implemented |\n|  | No paging support |\n| **Graphics** | Text modes, VGA, EGA, and CGA implemented |\n|  | EGA and CGA modes are best effort (you may find bugs) |\n|  | No VESA support |\n| **DOS** | Partial int 21h implementation (DOS 5.0) |\n| **Input** | Keyboard and mouse supported |\n|  | No joystick support |\n| **CD-ROM** | No MSCDEX support |\n| **Floppy** | No Floppy Disk support |\n\n## Sound support\n\n| Sound Type | Support Level | Notes |\n|------------|---------------|-------|\n| PC Speaker | ✅ Full | Implemented |\n| Adlib/SB OPL | ✅ Full | Ported from DOSBox Staging |\n| SoundBlaster | ✅ Full | Ported from DOSBox Staging |\n| Adlib Gold | ✅ Full | Ported from DOSBox Staging |\n| MT-32 | ⚠️ Partial | Not available on macOS |\n| Gravis Ultrasound | ❌ None | Not implemented yet |\n| General MIDI | ✅ Full | Supported |\n\n## Misc\n\n| Feature | Details |\n|---------|---------|\n| **C Drive** | Configurable with `--CDrive`, defaults to current folder |\n| **Program Arguments** | Pass up to 127 chars with `--ExeArgs` |\n| **Time Handling** | Real elapsed time (adjustable with `--TimeMultiplier`) or instruction-based timing with `--InstructionsPerSecond` |\n| **Screen Refresh** | 30 FPS and on VGA retrace wait detection |\n| **Structure Viewer** | Requires C header file (`--StructureFile`) to display memory structures |\n\n## Reverse engineering process\n\nConcrete example with Cryo Dune [here](https://github.com/OpenRakis/Cryogenic).\n\nFirst run your program and make sure everything works fine in Spice86. If you encounter issues it could be due to unimplemented hardware / DOS / BIOS features.\n\nWhen Spice86 exits, it should dump data in current folder or in folder specified by env variable\n\nOpen the data in [ghidra](https://github.com/NationalSecurityAgency/ghidra) with the [spice86-ghidra-plugin](https://github.com/OpenRakis/spice86-ghidra-plugin) and generate code. You can import the generated files in a template project you generate via the [spice86-dotnet-templates](https://github.com/OpenRakis/spice86-dotnet-templates):\n\n```\ndotnet new spice86.project\n```\n\n## Overriding emulated code with C# code\n\nYou can provide your own C# code to override the program original assembly code.\n\n### Defining overrides\n\nSpice86 can take in input an instance of Spice86.Core.Emulator.Function.IOverrideSupplier that builds a mapping between the memory address of functions and their C# overrides.\n\nFor a complete example you can check the source code of [Cryogenic](https://github.com/OpenRakis/Cryogenic).\n\nHere is a simple example of how it would look like:\n\n```csharp\nnamespace My.Program;\n\n// This class is responsible for providing the overrides to spice86.\n// There is only one per program you reimplement.\npublic class MyProgramOverrideSupplier : IOverrideSupplier {\n  public IDictionary\u003cSegmentedAddress, FunctionInformation\u003e GenerateFunctionInformations(int programStartSegment,\n                                                                                 Machine machine) {\n    Dictionary\u003cSegmentedAddress, FunctionInformation\u003e res = new();\n    // In more complex examples, overrides may call each other\n    new MyOverrides(res, programStartSegment, machine);\n    return res;\n  }\n\n  public override string ToString() {\n    return \"Overrides My program exe. class is \" + GetType().FullName;\n  }\n}\n\n// This class contains the actual overrides. As the project grows, you will probably need to split the reverse engineered code in several classes.\npublic class MyOverrides : CSharpOverrideHelper {\n  private MyOverridesGlobalsOnDs globalsOnDs;\n\n  public MyOverrides(IDictionary\u003cSegmentedAddress, FunctionInformation\u003e functionInformations, ushort entrySegment, Machine machine, ILoggerService loggerService, Configuration configuration) {\n    // \"myOverides\" is a prefix that will be appended to all the function names defined in this class\n    base(functionInformations, machine,  loggerService, configuration);\n    globalsOnDs = new MyOverridesGlobalsOnDs(machine);\n    // incUnknown47A8_0x1ED_0xA1E8_0xC0B8 will get executed instead of the assembly code when a call to 1ED:A1E8 is performed.\n    // Also when dumping functions, the name myOverides.incUnknown47A8 or instead of unknown\n    // Note: the segment is provided in parameter as spice86 can load executables in different places depending on the configuration\n    DefineFunction(segment, 0xA1E8, \"incDialogueCount47A8\", IncDialogueCount47A8_0x1ED_0xA1E8_0xC0B8);\n    DefineFunction(segment, 0x0100, \"addOneToAX\", AddOneToAX_0x1ED_0x100_0x1FD0);\n  }\n\n  public Action IncDialogueCount47A8_0x1ED_0xA1E8_0xC0B8() {\n    // Accessing the memory via accessors\n    globalsOnDs.SetDialogueCount47A8(globalsOnDs.GetDialogueCount47A8() + 1);\n    // Depends on the actual return instruction performed by the function, needed to be called from the emulated code as\n    // some programs like to mess with the stack ...\n    return NearRet();\n  }\n\n  private Action AddOneToAX_0x1ED_0x100_0x1FD0() {\n    // Assembly for this would be\n    // INC AX\n    // RETF\n    // Note that you can access the whole emulator to change the state in the overrides.\n    state.AX++;\n    return NearRet();\n  }\n}\n\n// Memory accesses can be encapsulated into classes like this to give names to addresses and make the code shorter.\npublic class GlobalsOnDs : MemoryBasedDataStructureWithDsBaseAddress {\n    public GlobalsOnDs(IByteReaderWriter memory, SegmentRegisters segmentRegisters) : base(memory, segmentRegisters) {\n    }\n\n    // Getters and Setters for address 0x1DD:0x2/0x1DD2.\n    // Was accessed via the following registers: DS\n    public int Get01DD_0002_Word16() {\n        return UInt16[0x2];\n    }\n\n    // Operation not registered by running code\n    public void Set01DD_0002_Word16(byte value) {\n        UInt16[0x2] = value;\n    }\n\n    // Getters and Setters for address 0x1138:0x0/0x11380.\n    // Operation not registered by running code\n    public int Get1138_0000_Word16() {\n        return UInt16[0x0];\n    }\n}\n```\n\n*Remember*: You must tell Spice86 to use your assembly code overrides with the command line argument \"--UseCodeOverride true\" when debugging your project.\n\nAlong with the mandatory path to your DOS program, passed with the --ExePath argument.\n\n## Debugger\n\nSpice86 comes with a [built-in debugger](https://github.com/OpenRakis/Spice86/wiki/Spice86-internal-debugger). that can be used to debug the emulated program. It is a simple debugger that allows you to inspect the memory, the disassembly, the registers, and the stack.\n\n### Structure viewer\n\nThe structure viewer allows you to inspect the memory in a structured way. It is useful to inspect the memory as a structure, like the DOS PSP, the DOS MCB, the VGA registers, etc.\n\nFirst you need a C header file that describes the structures in the application. You can generate one with Ghidra or IDA. Then you can load it with the `--StructureFile` commandline argument.\nThis will enable the \"Structure view\" button in the Memory tab of the debugger.\n\nThere you enter a segment:offset address and choose the structure you want to view. The structure will be displayed in a tree view and the memory in a hex view.\n\nThe display updates whenever the application is paused, so you can step through the program and see how the structure changes.\nExporting a new C header file from Ghidra or IDA will also update the structure viewer with the new information real-time.\n\nYou can also enter the Structure view by selecting a range of bytes in the Memory tab and right-clicking on it.\n\n## HTTP server\n\nSpice86 includes a built-in HTTP server for quick runtime inspection and memory access.\n\n- The HTTP server is **disabled by default**. Enable it by specifying a port with `--HttpApiPort`.\n\nAvailable endpoints:\n\n| Method | Route | Description |\n|--------|-------|-------------|\n| `GET` | `/api` | API metadata and endpoint list |\n| `GET` | `/api/status` | Current emulator status (pause state, CPU state, CS:IP, cycles, memory size) |\n| `GET` | `/api/memory/{address}/byte` | Read one byte at address |\n| `PUT` | `/api/memory/{address}/byte` | Write one byte at address |\n| `GET` | `/api/memory/{address}/range/{length}` | Read a memory range |\n\n## Misc details\n\n### C Drive\n\nIt is possible to provide a C: Drive for emulated DOS functions with the option **--CDrive**. Default is executed program folder. For some games you may need to set the C drive to the parent folder.\n\n### Emulated program arguments\n\nYou can pass arguments (max 127 chars!) to the emulated program with the option **--ExeArgs**. Default is empty.\n\n### Time\n\nThe emulated Timer hardware of the PC (Intel 8259) supports measuring time from either:\n\n- The real elapsed time. Speed can be altered with parameter **--TimeMultiplier**.\n- The number of instructions the emulated CPU executed. This is the behaviour that is activated with parameter **--InstructionsPerSecond** and is forced when in GDB mode so that you can debug with peace of mind without the timer triggering.\n\nCompatibility list available [here](COMPATIBILITY.md).\n\n### How to build on your machine\n\n- Install the [.NET 10 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/10.0) (once)\n- clone the repo\n- run this where Spice86.sln is located:\n\n```bash\n   dotnet build\n```\n\n### How to run\n\n```bash\n   Spice86 -e \u003cpath to executable\u003e\n```\n\nor use this where Spice86.csproj is located:\n\n```bash\n   dotnet run -e \u003cpath to executable\u003e\n```\n\n### Ghidra plugin\n\nThis uses Ghidra and Java 17.\n\nBefore using it, define an environnement variable named SPICE86_DUMPS_FOLDER pointing to a folder where the Spice86 dumps are located.\nThey are generated on exit.\n\nGeneral procedure, in order:\n\n1.Ghidra's own script 'ImportSymbolScript.py' (input used is \"spice86dumpGhidraSymbols.txt\")\n\n2.Ghidra's Auto-Analyze (only enable 'Dissasemble Entry Points')\n\n3.Now, you can use the plugin.\n\nRemember: if Ghidra displays SUBROUTINES, use the 'f' key to convert them into functions. The code generator only works with functions.\n\nAlso, if you have any weird behaviour, make sure you have Java 17 and ONLY Java 17. That's how Ghidra likes it.\n\n### Cfg Cpu\n\nDoc [here](doc/cfgcpuReadme.md)\n\n### MCP\n\nMCP server documentation is available in [doc/mcp.md](doc/mcp.md).\n\n### Some screenshots\n\nCryo dune:\n\n![](doc/cryodune_duke.png)\n\n![](doc/cryodune_worm.png)\n\n![](doc/cryodune_orni.png)\n\nPrince of persia:\n![](doc/prince_of_persia.PNG)\n\nStunts:\n![](doc/stunts_menu.PNG)\n\n![](doc/stunts_loop.png)\n\n![](doc/stunts_crash.PNG)\n\n![](doc/stunts_skid.PNG)\n\nBetrayal at Krondor:\n\n![](doc/BaK.png)\n\n## Credits\n\nThe SoundBlaster implementation is fully ported from [dosbox-staging](https://github.com/dosbox-staging/dosbox-staging), replacing the previous one which was modified from the Aeon emulator. This includes PCM and OPL sound quality improvements, emulation accuracy, SB/OPL compatibility, mixer thread logic, audio events, audio hardware delays, and a complete audio re-architecture.\n\nAdditionally, the project no longer relies on PortAudio. Instead, it uses a fully cross-platform C# port of the SDL2 audio APIs.\nWe only depend on WASAPI (Windows), ALSA (Linux), or CoreAudio (macOS).\n\nThis project uses JetBrains Rider licenses, thanks to JetBrains' [Open Source Community Support](https://www.jetbrains.com/community/opensource/#support).\n\n![](jetbrainsrider.svg)\n\nThe UI is powered by [Avalonia UI](https://avaloniaui.net/).\n\n![](avalonia.png)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenrakis%2Fspice86","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopenrakis%2Fspice86","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopenrakis%2Fspice86/lists"}