open Uxn open Effect.Deep let debug = Option.is_some (Sys.getenv_opt "DBG") let rec run m pc = let dev = Machine.dev m in let console_vector = ref 0 in let console_input ch ty = Bytes.set_uint8 dev 0x12 ch; Bytes.set_uint8 dev 0x17 ty; if Bytes.get_uint8 dev 0x0f = 0 then run m !console_vector in try Machine.dispatch ~trace:debug m pc with | effect Machine.Trace (pc, instr, args), k when debug -> Fmt.epr "PC = %04x | %6s : %a\n" pc (Instr.to_string instr) (Fmt.list ~sep:(Fmt.any " ") (Fmt.fmt "%02x")) args; Out_channel.flush stderr; continue k () | effect Machine.Trace _, k -> continue k () | effect Machine.BRK, _ when !console_vector != 0 -> ( try while Bytes.get_uint8 dev 0x0f = 0 do match In_channel.input_byte stdin with | None -> if debug then Fmt.epr "EOF\n"; console_input 0 4; raise Exit | Some c -> console_input c 1 done with Exit -> ()) | effect Machine.BRK, _ -> () | effect Machine.DEI (`Byte, port), k -> continue k (Bytes.get_uint8 dev port) | effect Machine.DEI (`Short, port), k -> continue k (Util.get_uint16_wrap dev port) | effect Machine.DEO (port, value), k -> (match port with | 0x10 -> console_vector := value | 0x18 -> print_char (Char.chr value); Out_channel.flush stdout | 0x19 -> prerr_char (Char.chr value); Out_channel.flush stderr | _ -> ()); continue k () let main () = if Array.length Sys.argv < 2 then ( Fmt.epr "usage: uxnemu file.rom ...\n"; exit 1); let code = In_channel.with_open_bin Sys.argv.(1) (fun i -> In_channel.input_all i) in In_channel.set_binary_mode stdin true; Out_channel.set_binary_mode stdout true; let mach = Machine.create code in run mach 0x100; exit (Bytes.get_uint8 (Machine.dev mach) 0x0f land 0x7f) let _ = main ()