move File device to new module system
This commit is contained in:
parent
5769f6d470
commit
b71cf4343e
4 changed files with 291 additions and 226 deletions
|
|
@ -5,7 +5,18 @@ let trace = Option.is_some (Sys.getenv_opt "UXNEMU_DEBUG")
|
||||||
|
|
||||||
module System = Varvara.System.Make ()
|
module System = Varvara.System.Make ()
|
||||||
module Console = Varvara.Console.Make ()
|
module Console = Varvara.Console.Make ()
|
||||||
module Devices = Uxn.Device.Compose (System) (Console)
|
|
||||||
|
module File =
|
||||||
|
Uxn.Device.Compose
|
||||||
|
(Varvara.File.Make (struct
|
||||||
|
let start_addr = 0xa0
|
||||||
|
end))
|
||||||
|
(Varvara.File.Make (struct
|
||||||
|
let start_addr = 0xb0
|
||||||
|
end))
|
||||||
|
|
||||||
|
module Devices =
|
||||||
|
Uxn.Device.Compose (Uxn.Device.Compose (System) (Console)) (File)
|
||||||
|
|
||||||
let print_stack ~name (Machine.Stack { data; sp }) =
|
let print_stack ~name (Machine.Stack { data; sp }) =
|
||||||
Fmt.epr "%s: @[%a@]@." name
|
Fmt.epr "%s: @[%a@]@." name
|
||||||
|
|
@ -14,7 +25,6 @@ let print_stack ~name (Machine.Stack { data; sp }) =
|
||||||
|
|
||||||
let run m pc =
|
let run m pc =
|
||||||
let dev = Machine.dev m in
|
let dev = Machine.dev m in
|
||||||
let ram = Machine.ram m in
|
|
||||||
try Machine.dispatch ~trace m pc with
|
try Machine.dispatch ~trace m pc with
|
||||||
| effect Machine.Trace (pc, instr, args), k ->
|
| effect Machine.Trace (pc, instr, args), k ->
|
||||||
if trace then begin
|
if trace then begin
|
||||||
|
|
@ -34,62 +44,12 @@ let run m pc =
|
||||||
| Some v -> continue k v
|
| Some v -> continue k v
|
||||||
| None -> continue k (Util.get_uint16_wrap dev port))
|
| None -> continue k (Util.get_uint16_wrap dev port))
|
||||||
| effect Machine.DEO (port, value), k ->
|
| effect Machine.DEO (port, value), k ->
|
||||||
(match port with
|
if Devices.can_handle port then Devices.deo m port value;
|
||||||
| _ when Devices.can_handle port -> Devices.deo m port value
|
|
||||||
| 0xaa -> Varvara.File.file_lengths.(0) <- Bytes.get_uint16_be dev 0xaa
|
|
||||||
| 0xa4 ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xa4 in
|
|
||||||
let len = Varvara.File.file_lengths.(0) in
|
|
||||||
let result = Varvara.File.file_stat ram 0 addr len in
|
|
||||||
Varvara.File.file_success dev 0xa2 result
|
|
||||||
| 0xa6 ->
|
|
||||||
let result = Varvara.File.file_delete 0 in
|
|
||||||
Varvara.File.file_success dev 0xa2 (if result = 0 then 1 else 0)
|
|
||||||
| 0xa8 ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xa8 in
|
|
||||||
let result = Varvara.File.file_init ram 0 addr in
|
|
||||||
Varvara.File.file_success dev 0xa2 result
|
|
||||||
| 0xac ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xac in
|
|
||||||
let len = Varvara.File.file_lengths.(0) in
|
|
||||||
let result = Varvara.File.file_read ram 0 addr len in
|
|
||||||
Varvara.File.file_success dev 0xa2 result
|
|
||||||
| 0xae ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xae in
|
|
||||||
let len = Varvara.File.file_lengths.(0) in
|
|
||||||
let append = Bytes.get_uint8 dev 0xa7 in
|
|
||||||
let result = Varvara.File.file_write ram 0 addr len append in
|
|
||||||
Varvara.File.file_success dev 0xa2 result
|
|
||||||
| 0xba -> Varvara.File.file_lengths.(1) <- Bytes.get_uint16_be dev 0xba
|
|
||||||
| 0xb4 ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xb4 in
|
|
||||||
let len = Varvara.File.file_lengths.(1) in
|
|
||||||
let result = Varvara.File.file_stat ram 1 addr len in
|
|
||||||
Varvara.File.file_success dev 0xb2 result
|
|
||||||
| 0xb6 ->
|
|
||||||
let result = Varvara.File.file_delete 1 in
|
|
||||||
Varvara.File.file_success dev 0xb2 (if result = 0 then 1 else 0)
|
|
||||||
| 0xb8 ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xb8 in
|
|
||||||
let result = Varvara.File.file_init ram 1 addr in
|
|
||||||
Varvara.File.file_success dev 0xb2 result
|
|
||||||
| 0xbc ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xbc in
|
|
||||||
let len = Varvara.File.file_lengths.(1) in
|
|
||||||
let result = Varvara.File.file_read ram 1 addr len in
|
|
||||||
Varvara.File.file_success dev 0xb2 result
|
|
||||||
| 0xbe ->
|
|
||||||
let addr = Bytes.get_uint16_be dev 0xbe in
|
|
||||||
let len = Varvara.File.file_lengths.(1) in
|
|
||||||
let append = Bytes.get_uint8 dev 0xb7 in
|
|
||||||
let result = Varvara.File.file_write ram 1 addr len append in
|
|
||||||
Varvara.File.file_success dev 0xb2 result
|
|
||||||
| _ -> ());
|
|
||||||
continue k ()
|
continue k ()
|
||||||
|
|
||||||
let main () =
|
let main () =
|
||||||
if Array.length Sys.argv < 2 then (
|
if Array.length Sys.argv < 2 then (
|
||||||
Fmt.epr "usage: uxnemu file.rom\n";
|
Fmt.epr "usage: uxnemu file.rom ...\n";
|
||||||
exit 1);
|
exit 1);
|
||||||
|
|
||||||
let code =
|
let code =
|
||||||
|
|
|
||||||
|
|
@ -11,12 +11,20 @@ type file_device = {
|
||||||
mutable length : int;
|
mutable length : int;
|
||||||
}
|
}
|
||||||
|
|
||||||
let make_file () = { filepath = None; state = Idle; length = 0 }
|
module type ADDR = sig
|
||||||
let file_devices = [| make_file (); make_file () |]
|
val start_addr : int
|
||||||
let file_lengths = [| 0; 0 |]
|
end
|
||||||
|
|
||||||
(* Read null-terminated string from RAM *)
|
module Make (Addr : ADDR) : Uxn.Device.DEVICE with type state = file_device =
|
||||||
let read_cstring ram addr =
|
struct
|
||||||
|
type state = file_device
|
||||||
|
|
||||||
|
let state = { filepath = None; state = Idle; length = 0 }
|
||||||
|
|
||||||
|
let can_handle port =
|
||||||
|
port >= Addr.start_addr && port <= Addr.start_addr + 0x0f
|
||||||
|
|
||||||
|
let read_cstring ram addr =
|
||||||
let buf = Buffer.create 256 in
|
let buf = Buffer.create 256 in
|
||||||
let rec loop pos =
|
let rec loop pos =
|
||||||
if pos >= Bytes.length ram then Buffer.contents buf
|
if pos >= Bytes.length ram then Buffer.contents buf
|
||||||
|
|
@ -29,7 +37,7 @@ let read_cstring ram addr =
|
||||||
in
|
in
|
||||||
loop addr
|
loop addr
|
||||||
|
|
||||||
let file_reset dev =
|
let file_reset dev =
|
||||||
(match dev.state with
|
(match dev.state with
|
||||||
| File_read ic -> close_in_noerr ic
|
| File_read ic -> close_in_noerr ic
|
||||||
| File_write oc -> close_out_noerr oc
|
| File_write oc -> close_out_noerr oc
|
||||||
|
|
@ -37,20 +45,14 @@ let file_reset dev =
|
||||||
| Idle | Dir_write -> ());
|
| Idle | Dir_write -> ());
|
||||||
dev.state <- Idle
|
dev.state <- Idle
|
||||||
|
|
||||||
let file_init ram id addr =
|
let file_init ram addr =
|
||||||
let dev = file_devices.(id) in
|
file_reset state;
|
||||||
file_reset dev;
|
state.filepath <- Some (read_cstring ram addr);
|
||||||
dev.filepath <- Some (read_cstring ram addr);
|
|
||||||
0
|
0
|
||||||
|
|
||||||
let file_not_ready id =
|
let file_not_ready () = state.filepath |> Option.is_none
|
||||||
match file_devices.(id).filepath with
|
|
||||||
| None ->
|
|
||||||
Format.eprintf "File %d is uninitialized@." id;
|
|
||||||
true
|
|
||||||
| Some _ -> false
|
|
||||||
|
|
||||||
let format_size size len =
|
let format_size size len =
|
||||||
let hex_digits = "0123456789abcdef" in
|
let hex_digits = "0123456789abcdef" in
|
||||||
let buf = Bytes.create len in
|
let buf = Bytes.create len in
|
||||||
for i = 0 to len - 1 do
|
for i = 0 to len - 1 do
|
||||||
|
|
@ -60,7 +62,7 @@ let format_size size len =
|
||||||
done;
|
done;
|
||||||
Bytes.to_string buf
|
Bytes.to_string buf
|
||||||
|
|
||||||
let format_stat ?(capsize = false) filepath len =
|
let format_stat ?(capsize = false) filepath len =
|
||||||
try
|
try
|
||||||
let st = Unix.stat filepath in
|
let st = Unix.stat filepath in
|
||||||
let is_dir = st.Unix.st_kind = Unix.S_DIR in
|
let is_dir = st.Unix.st_kind = Unix.S_DIR in
|
||||||
|
|
@ -69,7 +71,7 @@ let format_stat ?(capsize = false) filepath len =
|
||||||
else format_size st.Unix.st_size len
|
else format_size st.Unix.st_size len
|
||||||
with Unix.Unix_error _ -> String.make len '!'
|
with Unix.Unix_error _ -> String.make len '!'
|
||||||
|
|
||||||
let format_dir_entry filepath basename =
|
let format_dir_entry filepath basename =
|
||||||
let full_path = Filename.concat filepath basename in
|
let full_path = Filename.concat filepath basename in
|
||||||
let stat_str = format_stat ~capsize:true full_path 4 in
|
let stat_str = format_stat ~capsize:true full_path 4 in
|
||||||
try
|
try
|
||||||
|
|
@ -78,7 +80,7 @@ let format_dir_entry filepath basename =
|
||||||
Printf.sprintf "%s %s%s\n" stat_str basename (if is_dir then "/" else "")
|
Printf.sprintf "%s %s%s\n" stat_str basename (if is_dir then "/" else "")
|
||||||
with Unix.Unix_error _ -> Printf.sprintf "%s %s\n" stat_str basename
|
with Unix.Unix_error _ -> Printf.sprintf "%s %s\n" stat_str basename
|
||||||
|
|
||||||
let read_directory filepath maxlen =
|
let read_directory filepath maxlen =
|
||||||
let dh = Unix.opendir filepath in
|
let dh = Unix.opendir filepath in
|
||||||
let buf = Buffer.create 1024 in
|
let buf = Buffer.create 1024 in
|
||||||
let rec read_entries () =
|
let rec read_entries () =
|
||||||
|
|
@ -94,7 +96,7 @@ let read_directory filepath maxlen =
|
||||||
let result = Buffer.contents buf in
|
let result = Buffer.contents buf in
|
||||||
if String.length result > maxlen then String.sub result 0 maxlen else result
|
if String.length result > maxlen then String.sub result 0 maxlen else result
|
||||||
|
|
||||||
let create_directories path =
|
let create_directories path =
|
||||||
let rec mkdir_parents p =
|
let rec mkdir_parents p =
|
||||||
if p <> "" && p <> "." && p <> "/" then
|
if p <> "" && p <> "." && p <> "/" then
|
||||||
if not (Sys.file_exists p) then (
|
if not (Sys.file_exists p) then (
|
||||||
|
|
@ -103,23 +105,22 @@ let create_directories path =
|
||||||
in
|
in
|
||||||
mkdir_parents (Filename.dirname path)
|
mkdir_parents (Filename.dirname path)
|
||||||
|
|
||||||
let is_dir_path path =
|
let is_dir_path path =
|
||||||
String.length path > 0 && path.[String.length path - 1] = '/'
|
String.length path > 0 && path.[String.length path - 1] = '/'
|
||||||
|
|
||||||
let file_read ram id addr len =
|
let file_read ram addr len =
|
||||||
if file_not_ready id then 0
|
if file_not_ready () then 0
|
||||||
else
|
else
|
||||||
let dev = file_devices.(id) in
|
match state.filepath with
|
||||||
match dev.filepath with
|
|
||||||
| None -> 0
|
| None -> 0
|
||||||
| Some filepath -> (
|
| Some filepath -> (
|
||||||
(match dev.state with
|
(match state.state with
|
||||||
| Idle ->
|
| Idle ->
|
||||||
if Sys.is_directory filepath then
|
if Sys.is_directory filepath then
|
||||||
dev.state <- Dir_read (Unix.opendir filepath, filepath)
|
state.state <- Dir_read (Unix.opendir filepath, filepath)
|
||||||
else dev.state <- File_read (open_in_bin filepath)
|
else state.state <- File_read (open_in_bin filepath)
|
||||||
| _ -> ());
|
| _ -> ());
|
||||||
match dev.state with
|
match state.state with
|
||||||
| File_read ic -> (
|
| File_read ic -> (
|
||||||
try
|
try
|
||||||
let bytes_read = input ic ram addr len in
|
let bytes_read = input ic ram addr len in
|
||||||
|
|
@ -133,23 +134,22 @@ let file_read ram id addr len =
|
||||||
let bytes_to_copy = min len (String.length contents) in
|
let bytes_to_copy = min len (String.length contents) in
|
||||||
Bytes.blit_string contents 0 ram addr bytes_to_copy;
|
Bytes.blit_string contents 0 ram addr bytes_to_copy;
|
||||||
Unix.closedir dh;
|
Unix.closedir dh;
|
||||||
dev.state <- Idle;
|
state.state <- Idle;
|
||||||
bytes_to_copy
|
bytes_to_copy
|
||||||
with Unix.Unix_error _ -> 0)
|
with Unix.Unix_error _ -> 0)
|
||||||
| _ -> 0)
|
| _ -> 0)
|
||||||
|
|
||||||
let file_write ram id addr len append_flag =
|
let file_write ram addr len append_flag =
|
||||||
if file_not_ready id then 0
|
if file_not_ready () then 0
|
||||||
else
|
else
|
||||||
let dev = file_devices.(id) in
|
match state.filepath with
|
||||||
match dev.filepath with
|
|
||||||
| None -> 0
|
| None -> 0
|
||||||
| Some filepath -> (
|
| Some filepath -> (
|
||||||
(match dev.state with
|
(match state.state with
|
||||||
| Idle ->
|
| Idle ->
|
||||||
if is_dir_path filepath then (
|
if is_dir_path filepath then (
|
||||||
create_directories filepath;
|
create_directories filepath;
|
||||||
dev.state <- Dir_write)
|
state.state <- Dir_write)
|
||||||
else (
|
else (
|
||||||
create_directories filepath;
|
create_directories filepath;
|
||||||
let mode =
|
let mode =
|
||||||
|
|
@ -159,10 +159,10 @@ let file_write ram id addr len append_flag =
|
||||||
in
|
in
|
||||||
try
|
try
|
||||||
let oc = open_out_gen mode 0o644 filepath in
|
let oc = open_out_gen mode 0o644 filepath in
|
||||||
dev.state <- File_write oc
|
state.state <- File_write oc
|
||||||
with Sys_error _ -> ())
|
with Sys_error _ -> ())
|
||||||
| _ -> ());
|
| _ -> ());
|
||||||
match dev.state with
|
match state.state with
|
||||||
| File_write oc -> (
|
| File_write oc -> (
|
||||||
try
|
try
|
||||||
output oc ram addr len;
|
output oc ram addr len;
|
||||||
|
|
@ -174,11 +174,10 @@ let file_write ram id addr len append_flag =
|
||||||
else 0
|
else 0
|
||||||
| _ -> 0)
|
| _ -> 0)
|
||||||
|
|
||||||
let file_stat ram id addr len =
|
let file_stat ram addr len =
|
||||||
if file_not_ready id then 0
|
if file_not_ready () then 0
|
||||||
else
|
else
|
||||||
let dev = file_devices.(id) in
|
match state.filepath with
|
||||||
match dev.filepath with
|
|
||||||
| None -> 0
|
| None -> 0
|
||||||
| Some filepath ->
|
| Some filepath ->
|
||||||
let stat_str = format_stat filepath len in
|
let stat_str = format_stat filepath len in
|
||||||
|
|
@ -186,11 +185,10 @@ let file_stat ram id addr len =
|
||||||
Bytes.blit_string stat_str 0 ram addr bytes_to_copy;
|
Bytes.blit_string stat_str 0 ram addr bytes_to_copy;
|
||||||
bytes_to_copy
|
bytes_to_copy
|
||||||
|
|
||||||
let file_delete id =
|
let file_delete () =
|
||||||
if file_not_ready id then -1
|
if file_not_ready () then -1
|
||||||
else
|
else
|
||||||
let dev = file_devices.(id) in
|
match state.filepath with
|
||||||
match dev.filepath with
|
|
||||||
| None -> -1
|
| None -> -1
|
||||||
| Some filepath -> (
|
| Some filepath -> (
|
||||||
try
|
try
|
||||||
|
|
@ -198,4 +196,25 @@ let file_delete id =
|
||||||
0
|
0
|
||||||
with Unix.Unix_error _ -> -1)
|
with Unix.Unix_error _ -> -1)
|
||||||
|
|
||||||
let file_success dev port value = Bytes.set_uint16_be dev port value
|
let file_success dev port value = Bytes.set_uint16_be dev port value
|
||||||
|
let dei _ _ = None
|
||||||
|
let dei2 _ _ = None
|
||||||
|
|
||||||
|
let deo mach port value =
|
||||||
|
let open Uxn in
|
||||||
|
let ram = Machine.ram mach in
|
||||||
|
let dev = Machine.dev mach in
|
||||||
|
let with_success result =
|
||||||
|
file_success dev (Addr.start_addr + 0x02) result
|
||||||
|
in
|
||||||
|
match port - Addr.start_addr with
|
||||||
|
| 0x0a -> state.length <- value
|
||||||
|
| 0x04 -> file_stat (Machine.ram mach) value state.length |> with_success
|
||||||
|
| 0x06 -> file_delete () |> with_success
|
||||||
|
| 0x08 -> file_init (Machine.ram mach) value |> with_success
|
||||||
|
| 0x0c -> file_read (Machine.ram mach) value state.length |> with_success
|
||||||
|
| 0x0e ->
|
||||||
|
let append = Bytes.get_uint8 dev (Addr.start_addr + 0x07) in
|
||||||
|
file_write ram value state.length append |> with_success
|
||||||
|
| _ -> ()
|
||||||
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
.PHONY: all clean
|
.PHONY: all clean
|
||||||
.SUFFIXES: .tal .rom
|
.SUFFIXES: .tal .rom
|
||||||
|
|
||||||
all: uxnmin drifloon.rom opctest.rom
|
all: uxnmin drifloon.rom opctest.rom varvara.file.rom
|
||||||
clean:
|
clean:
|
||||||
rm -f uxnmin drifloon.rom opctest.rom
|
rm -f uxnmin drifloon.rom opctest.rom
|
||||||
|
|
||||||
|
|
|
||||||
86
utils/varvara.file.tal
Normal file
86
utils/varvara.file.tal
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
( uxncli file.rom )
|
||||||
|
|
||||||
|
|10 @Console/vector $2 &read $1 &pad $4 &type $1 &write $1 &error $1
|
||||||
|
|a0 @File/vector $2 &success $2 &stat $2 &delete $1 &append $1 &name $2 &length $2 &read $2 &write $2
|
||||||
|
|
||||||
|
|100
|
||||||
|
|
||||||
|
@on-reset ( -> )
|
||||||
|
file/<create>
|
||||||
|
file/<load>
|
||||||
|
#0004 .File/success DEI2 NEQ2 ?fail
|
||||||
|
;file/a1 LDA2 ;file/a2 LDA2 NEQ2 ?fail
|
||||||
|
;dict/load str/<print>
|
||||||
|
;file/b1 LDA2 ;file/b2 LDA2 NEQ2 ?fail
|
||||||
|
;dict/append str/<print>
|
||||||
|
;file/stat-buf file/<stat>
|
||||||
|
;file/stat-hs LDA2 LIT2 "00 NEQ2 ?fail
|
||||||
|
;file/stat-ls LDA2 LIT2 "04 NEQ2 ?fail
|
||||||
|
;dict/stat str/<print>
|
||||||
|
file/<delete>
|
||||||
|
;file/null-buf file/<stat>
|
||||||
|
;file/null-buf LDA2 LIT2 "!! NEQ2 ?fail
|
||||||
|
;dict/delete str/<print>
|
||||||
|
#800f DEO
|
||||||
|
BRK
|
||||||
|
|
||||||
|
@fail ( -> )
|
||||||
|
;dict/failed str/<print>
|
||||||
|
#010f DEO
|
||||||
|
BRK
|
||||||
|
|
||||||
|
(
|
||||||
|
@|File )
|
||||||
|
|
||||||
|
@file/<create> ( -- )
|
||||||
|
;&name .File/name DEO2
|
||||||
|
#0002 .File/length DEO2
|
||||||
|
;&a1 .File/write DEO2
|
||||||
|
( | append )
|
||||||
|
;&name .File/name DEO2
|
||||||
|
#0002 .File/length DEO2
|
||||||
|
#01 .File/append DEO
|
||||||
|
;&b1 .File/write DEO2
|
||||||
|
JMP2r
|
||||||
|
|
||||||
|
@file/<load> ( -- )
|
||||||
|
;&name .File/name DEO2
|
||||||
|
( two more bytes than max length ) #0006 .File/length DEO2
|
||||||
|
;&load-buf .File/read DEO2
|
||||||
|
JMP2r
|
||||||
|
|
||||||
|
@file/<stat> ( buf* -- )
|
||||||
|
;&name .File/name DEO2
|
||||||
|
#0004 .File/length DEO2
|
||||||
|
.File/stat DEO2
|
||||||
|
JMP2r
|
||||||
|
|
||||||
|
@file/<delete> ( -- )
|
||||||
|
;&name .File/name DEO2
|
||||||
|
#01 .File/delete DEO
|
||||||
|
JMP2r
|
||||||
|
|
||||||
|
&name "test.txt $1
|
||||||
|
|
||||||
|
(
|
||||||
|
@|Utils )
|
||||||
|
|
||||||
|
@str/<print> ( str* -- )
|
||||||
|
LDAk DUP ?{ POP POP2 JMP2r }
|
||||||
|
#18 DEO
|
||||||
|
INC2 !/<print>
|
||||||
|
|
||||||
|
(
|
||||||
|
@|Data )
|
||||||
|
|
||||||
|
@dict/failed "File: 20 "fail 0a $1
|
||||||
|
&load "File/load: 20 "pass 0a $1
|
||||||
|
&append "File/append: 20 "pass 0a $1
|
||||||
|
&stat "File/stat: 20 "pass 0a $1
|
||||||
|
&delete "File/delete: 20 "pass 0a $1
|
||||||
|
|
||||||
|
@file/data &a1 1234 &b1 5678
|
||||||
|
( load buf ) &load-buf &a2 $2 &b2 $2
|
||||||
|
( stat buf ) &stat-buf &stat-hs $2 &stat-ls $2
|
||||||
|
( null buf ) &null-buf $4
|
||||||
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue