diff --git a/src/Chip8.Cli/AsmCommand.cs b/src/Chip8.Cli/AsmCommand.cs new file mode 100644 index 0000000..0ac103a --- /dev/null +++ b/src/Chip8.Cli/AsmCommand.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; +using Chip8.Core; +using Chip8.Core.Assembly; + +namespace Chip8.Cli; + +static class AsmCommand +{ + public static int run(string[] args) + { + if (args.Length < 1) + { + Console.Error.WriteLine("usage: chip8 asm [-o out.ch8] [--listing]"); + return 1; + } + + string sourcePath = args[0]; + string? outputPath = null; + bool showListing = false; + + for (int index = 1; index < args.Length; index++) + { + switch (args[index]) + { + case "-o": + case "--out": + outputPath = args[++index]; + break; + case "--listing": + showListing = true; + break; + default: + Console.Error.WriteLine($"error: unknown asm option {args[index]}"); + return 1; + } + } + + if (!File.Exists(sourcePath)) + { + Console.Error.WriteLine($"error: source not found: {sourcePath}"); + return 1; + } + + string source = File.ReadAllText(sourcePath); + AssemblyResult result; + try + { + result = new Assembler().assemble(source); + } + catch (AsmException error) + { + Console.Error.WriteLine($"error: {error.Message}"); + return 1; + } + + outputPath ??= Path.ChangeExtension(sourcePath, ".ch8"); + File.WriteAllBytes(outputPath, result.rom); + Console.WriteLine($"assembled {result.rom.Length} bytes -> {outputPath}"); + + if (showListing) + { + Console.Write(result.listing); + } + + return 0; + } +} diff --git a/src/Chip8.Cli/DisasmCommand.cs b/src/Chip8.Cli/DisasmCommand.cs new file mode 100644 index 0000000..b56cd08 --- /dev/null +++ b/src/Chip8.Cli/DisasmCommand.cs @@ -0,0 +1,46 @@ +using System; +using System.Globalization; +using System.IO; +using Chip8.Core; + +namespace Chip8.Cli; + +static class DisasmCommand +{ + public static int run(string[] args) + { + if (args.Length < 1) + { + Console.Error.WriteLine("usage: chip8 disasm [--base 0x200]"); + return 1; + } + + string romPath = args[0]; + ushort baseAddress = Machine.programStart; + + for (int index = 1; index < args.Length; index++) + { + if (args[index] == "--base") + { + string value = args[++index]; + string digits = value.StartsWith("0x", StringComparison.OrdinalIgnoreCase) ? value.Substring(2) : value; + baseAddress = ushort.Parse(digits, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + } + else + { + Console.Error.WriteLine($"error: unknown disasm option {args[index]}"); + return 1; + } + } + + if (!File.Exists(romPath)) + { + Console.Error.WriteLine($"error: ROM not found: {romPath}"); + return 1; + } + + byte[] rom = File.ReadAllBytes(romPath); + Console.Write(Disassembler.render(rom, baseAddress)); + return 0; + } +} diff --git a/src/Chip8.Cli/TuiDebugger.cs b/src/Chip8.Cli/TuiDebugger.cs new file mode 100644 index 0000000..8257177 --- /dev/null +++ b/src/Chip8.Cli/TuiDebugger.cs @@ -0,0 +1,65 @@ +using System; +using System.IO; +using Chip8.Core; + +namespace Chip8.Cli; + +static class TuiDebugger +{ + public static int run(string[] args) + { + if (args.Length < 1) + { + Console.Error.WriteLine("usage: chip8 debug [--platform NAME]"); + return 1; + } + + var forwarded = new string[args.Length]; + forwarded[0] = args[0]; + Array.Copy(args, 1, forwarded, 1, args.Length - 1); + + Options options; + try + { + options = Options.parse(forwarded); + } + catch (ArgumentException error) + { + Console.Error.WriteLine($"error: {error.Message}"); + return 1; + } + + if (!File.Exists(options.romPath)) + { + Console.Error.WriteLine($"error: ROM not found: {options.romPath}"); + return 1; + } + + var machine = new Machine(options.buildQuirks(), options.seed, options.buildPlatform()); + machine.loadRom(File.ReadAllBytes(options.romPath)); + + var console = new DebuggerConsole(new Debugger(machine)); + Console.WriteLine($"chip8-sharp debugger - {Path.GetFileName(options.romPath)} ({options.buildPlatform()})"); + Console.WriteLine("type 'help' for commands"); + Console.Write(console.execute("dis 5")); + Console.WriteLine(); + + while (!console.quitRequested) + { + Console.Write("(chip8) "); + string? line = Console.ReadLine(); + if (line is null) + { + break; + } + + string output = console.execute(line); + if (output.Length > 0) + { + Console.WriteLine(output); + } + } + + return 0; + } +}