open Uxn open Effect.Deep let print_stack ?(name = "wst") (Machine.Stack stack) = if stack.sp != 0 then let stack = Bytes.to_seq stack.data |> Seq.take stack.sp |> Bytes.of_seq in Fmt.epr "@[%s: [@[%a@]]@]@." name (Fmt.on_bytes (Fmt.octets ())) stack let print_instruction i pc = Fmt.epr "%6s (PC = %04x)@." (Instr.to_string i) pc let debug = Option.is_some (Sys.getenv_opt "DBG") let console_vector = ref 0 let dispatch = if debug then Machine.dispatch ~dbg: (Some (fun m i pc -> print_instruction i pc; print_stack (Machine.wst m); print_stack ~name:"rst" (Machine.rst m))) else Machine.dispatch ~dbg:None let eval m pc = let console_input mach ch ty k = Bytes.set_uint8 (Machine.dev mach) 0x12 ch; Bytes.set_uint8 (Machine.dev mach) 0x17 ty; if !console_vector != 0 && Bytes.get_uint8 (Machine.dev mach) 0x0f = 0 then continue k !console_vector in try dispatch m pc with | effect Machine.BRK, k -> if !console_vector != 0 then ( try while Bytes.get_uint8 (Machine.dev m) 0x0f = 0 do match In_channel.input_char stdin with | None -> raise Exit | Some c -> console_input m (Char.code c) 1 k done with Exit -> Bytes.set_uint8 (Machine.dev m) 0x12 0; Bytes.set_uint8 (Machine.dev m) 0x17 4; continue k !console_vector) | effect Machine.DEI port, k -> continue k (Bytes.get_uint8 (Machine.dev m) port) | effect Machine.DEI2 port, k -> continue k (Util.get_uint16_wrap (Machine.dev m) 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 Bytes.set_uint8 (Machine.dev mach) 0x17 0; eval mach 0x100; if debug then ( Fmt.epr "Execution ended:@."; Machine.wst mach |> print_stack; Machine.rst mach |> print_stack ~name:"rst"); Out_channel.flush_all () let _ = main ()