Created
June 28, 2024 20:27
-
-
Save nzrsky/0c605c1451a1fe6bfddab2b10e47a446 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import Foundation | |
| let args = ProcessInfo.processInfo.arguments | |
| guard let filename = args.dropFirst().last.map ({ | |
| if let url = URL(string: $0), url.scheme != nil { url } | |
| else { URL(fileURLWithPath: $0) } | |
| }) else { | |
| printe("usage: \(args[0]) FILE") | |
| exit(EXIT_FAILURE) | |
| } | |
| do { | |
| try disasm(filename) | |
| } catch { | |
| printe("error: \(filename.path): \(error)") | |
| exit(EXIT_FAILURE) | |
| } | |
| exit(EXIT_SUCCESS) | |
| func disasm(_ filename: URL) throws { | |
| print("; \(filename.path)\n") | |
| print("bits 16\n") | |
| try Data(contentsOf: filename).withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in | |
| var offset = 0 | |
| while offset < ptr.count { | |
| let inst = ptr.load(fromByteOffset: offset, as: RawInst.self) | |
| print(try decode(inst)) | |
| offset += RawInst.bitWidth / 8 | |
| } | |
| } | |
| } | |
| typealias RawInst = UInt16 | |
| enum Inst { | |
| enum Opcode: UInt8 { | |
| case mov = 0b100010 | |
| } | |
| enum Mod { | |
| typealias RawValue = UInt8 | |
| static let mem0: RawValue = 0b00 | |
| static let mem8: RawValue = 0b01 | |
| static let mem16: RawValue = 0b10 | |
| static let reg: RawValue = 0b11 | |
| } | |
| enum Width { | |
| typealias RawValue = UInt8 | |
| static let byte: RawValue = 0b0 | |
| static let word: RawValue = 0b1 | |
| } | |
| enum Dir { | |
| typealias RawValue = UInt8 | |
| static let toReg: RawValue = 0b0 | |
| static let fromReg: RawValue = 0b1 | |
| } | |
| enum Reg { | |
| static let table: [[String]] = [ | |
| ["al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"], // w = 0 | |
| ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di"] // w = 1 | |
| ] | |
| static func decode(uint8: UInt8, width: Width.RawValue) -> String { | |
| table[Int(width)][Int(uint8)] | |
| } | |
| } | |
| enum DecodingError: Error { | |
| case unknownInstruction(String) | |
| case unimplemented(String) | |
| } | |
| } | |
| func decode(_ inst: RawInst) throws -> String { | |
| let b0 = UInt8(inst & 0xff), b1 = UInt8(inst >> 8) | |
| let w = b0 & 0b01 | |
| let d = (b0 & 0b10) >> 1 | |
| let mod = b1 >> 6 | |
| let reg = (b1 >> 3) & 0b00_111 | |
| let rm = b1 & 0b00_000_111 | |
| let binInst = "\(String(b0, radix: 2)) \(String(b1, radix: 2))" | |
| let mnemo = try { () throws -> String in | |
| switch b0 >> 2 { | |
| case Inst.Opcode.mov.rawValue: | |
| let op1 = Inst.Reg.decode(uint8: reg, width: w) | |
| switch mod { | |
| case Inst.Mod.reg: | |
| let op2 = Inst.Reg.decode(uint8: rm, width: w) | |
| let ops = d == Inst.Dir.fromReg ? (op1, op2) : (op2, op1) | |
| return "mov \(ops.0), \(ops.1)" | |
| default: | |
| throw Inst.DecodingError.unimplemented("inst(\(binInst), mod = \(mod)") | |
| } | |
| default: | |
| throw Inst.DecodingError.unknownInstruction(binInst) | |
| } | |
| }() | |
| return "\(mnemo.padded(to: 30)); \(binInst)" | |
| } | |
| func printe(_ msg: String) { | |
| FileHandle.standardError.write((msg + "\n").data(using: .utf8) ?? .init()) | |
| } | |
| extension String { | |
| func padded(to length: Int, pad: String = " ") -> String { | |
| self + String(repeating: pad, count: max(0, length - count)) | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment