From f870e4965a8da10e83e86cdefb7b03a5345485c7 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Wed, 23 Nov 2022 01:14:43 +0100 Subject: [PATCH] added cx16diskio.f_seek() function to seek to a position in an opened file f_open uses channel 12 now, f_open_w uses 13 --- compiler/res/prog8lib/cx16/cx16diskio.p8 | 45 ++++++++++--- compiler/res/prog8lib/diskio.p8 | 48 ++++++------- compiler/test/TestCompilerOnExamples.kt | 1 + docs/source/todo.rst | 4 ++ examples/cx16/fileseek.p8 | 85 ++++++++++++++++++++++++ 5 files changed, 151 insertions(+), 32 deletions(-) create mode 100644 examples/cx16/fileseek.p8 diff --git a/compiler/res/prog8lib/cx16/cx16diskio.p8 b/compiler/res/prog8lib/cx16/cx16diskio.p8 index a8e7d9ee4..1c705862a 100644 --- a/compiler/res/prog8lib/cx16/cx16diskio.p8 +++ b/compiler/res/prog8lib/cx16/cx16diskio.p8 @@ -35,8 +35,8 @@ cx16diskio { return $2000 * (cx16.getrambank() - startbank) + endaddress - startaddress } - asmsub vload(str name @R0, ubyte device @Y, ubyte bank @A, uword address @R1) -> ubyte @A { - ; -- like the basic command VLOAD "filename",device,bank,address + asmsub vload(str name @R0, ubyte drivenumber @Y, ubyte bank @A, uword address @R1) -> ubyte @A { + ; -- like the basic command VLOAD "filename",drivenumber,bank,address ; loads a file into Vera's video memory in the given bank:address, returns success in A ; the file has to have the usual 2 byte header (which will be skipped) %asm {{ @@ -77,8 +77,8 @@ internal_vload: }} } - asmsub vload_raw(str name @R0, ubyte device @Y, ubyte bank @A, uword address @R1) -> ubyte @A { - ; -- like the basic command BVLOAD "filename",device,bank,address + asmsub vload_raw(str name @R0, ubyte drivenumber @Y, ubyte bank @A, uword address @R1) -> ubyte @A { + ; -- like the basic command BVLOAD "filename",drivenumber,bank,address ; loads a file into Vera's video memory in the given bank:address, returns success in A ; the file is read fully including the first two bytes. %asm {{ @@ -104,7 +104,7 @@ internal_vload: num_bytes-- } - void c64.CHKIN(11) ; use #11 as input channel again + void c64.CHKIN(12) ; use #12 as input channel again ; commander X16 supports fast block-read via macptr() kernal call uword size @@ -191,7 +191,7 @@ m_in_buffer sta $ffff diskio.list_filename[1] = 'd' diskio.list_filename[2] = ':' void string.copy(path, &diskio.list_filename+3) - void diskio.send_command(drivenumber, diskio.list_filename) + diskio.send_command(drivenumber, diskio.list_filename) } sub mkdir(ubyte drivenumber, str name) { @@ -200,7 +200,7 @@ m_in_buffer sta $ffff diskio.list_filename[1] = 'd' diskio.list_filename[2] = ':' void string.copy(name, &diskio.list_filename+3) - void diskio.send_command(drivenumber, diskio.list_filename) + diskio.send_command(drivenumber, diskio.list_filename) } sub rmdir(ubyte drivenumber, str name) { @@ -212,7 +212,7 @@ m_in_buffer sta $ffff diskio.list_filename[1] = 'd' diskio.list_filename[2] = ':' void string.copy(name, &diskio.list_filename+3) - void diskio.send_command(drivenumber, diskio.list_filename) + diskio.send_command(drivenumber, diskio.list_filename) } sub relabel(ubyte drivenumber, str name) { @@ -222,6 +222,33 @@ m_in_buffer sta $ffff diskio.list_filename[2] = 'h' diskio.list_filename[3] = ':' void string.copy(name, &diskio.list_filename+4) - void diskio.send_command(drivenumber, diskio.list_filename) + diskio.send_command(drivenumber, diskio.list_filename) } + + sub f_seek(uword pos_hiword, uword pos_loword) { + ; -- seek in the reading file opened with f_open, to the given 32-bits position + ubyte[6] command = ['p',0,0,0,0,0] + command[1] = 12 ; f_open uses channel 12 + command[2] = lsb(pos_loword) + command[3] = msb(pos_loword) + command[4] = lsb(pos_hiword) + command[5] = msb(pos_hiword) + send_command: + c64.SETNAM(sizeof(command), &command) + c64.SETLFS(15, diskio.last_drivenumber, 15) + void c64.OPEN() + c64.CLOSE(15) + diskio.have_first_byte = false + } + + ; TODO see if we can get this to work as well: +; sub f_seek_w(uword pos_hiword, uword pos_loword) { +; ; -- seek in the output file opened with f_open_w, to the given 32-bits position +; cx16diskio.f_seek.command[1] = 1 ; f_open_w uses secondary channel 1 +; cx16diskio.f_seek.command[2] = poslo +; cx16diskio.f_seek.command[3] = posmidlo +; cx16diskio.f_seek.command[4] = posmidhi +; cx16diskio.f_seek.command[5] = poshi +; goto cx16diskio.f_seek.send_command +; } } diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index e3ec8e3f8..47f986c22 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -10,12 +10,12 @@ diskio { ; -- Prints the directory contents of disk drive 8-11 to the screen. Returns success. c64.SETNAM(1, "$") - c64.SETLFS(13, drivenumber, 0) + c64.SETLFS(12, drivenumber, 0) ubyte status = 1 - void c64.OPEN() ; open 13,8,0,"$" + void c64.OPEN() ; open 12,8,0,"$" if_cs goto io_error - void c64.CHKIN(13) ; use #13 as input channel + void c64.CHKIN(12) ; use #12 as input channel if_cs goto io_error @@ -53,7 +53,7 @@ diskio { io_error: c64.CLRCHN() ; restore default i/o devices - c64.CLOSE(13) + c64.CLOSE(12) if status and status & $40 == 0 { ; bit 6=end of file txt.print("\ni/o error, status: ") @@ -69,12 +69,12 @@ io_error: ; -- Returns pointer to disk name string or 0 if failure. c64.SETNAM(1, "$") - c64.SETLFS(13, drivenumber, 0) + c64.SETLFS(12, drivenumber, 0) ubyte okay = false - void c64.OPEN() ; open 13,8,0,"$" + void c64.OPEN() ; open 12,8,0,"$" if_cs goto io_error - void c64.CHKIN(13) ; use #13 as input channel + void c64.CHKIN(12) ; use #12 as input channel if_cs goto io_error @@ -96,7 +96,7 @@ io_error: io_error: c64.CLRCHN() ; restore default i/o devices - c64.CLOSE(13) + c64.CLOSE(12) if okay return &list_filename return 0 @@ -109,6 +109,7 @@ io_error: bool iteration_in_progress = false ubyte @zp first_byte bool have_first_byte + ubyte last_drivenumber = 8 ; which drive was last used for a f_open operation? str list_filetype = "???" ; prg, seq, dir str list_filename = "?" * 50 @@ -249,7 +250,7 @@ close_end: } - ; ----- iterative file loader functions (uses io channel 11) ----- + ; ----- iterative file loader functions (uses io channel 12) ----- sub f_open(ubyte drivenumber, uword filenameptr) -> bool { ; -- open a file for iterative reading with f_read @@ -257,13 +258,14 @@ close_end: f_close() c64.SETNAM(string.length(filenameptr), filenameptr) - c64.SETLFS(11, drivenumber, 0) - void c64.OPEN() ; open 11,8,0,"filename" + c64.SETLFS(12, drivenumber, 12) ; note: has to be 12,x,12 because otherwise f_seek doesn't work + last_drivenumber = drivenumber + void c64.OPEN() ; open 12,8,12,"filename" if_cc { if c64.READST()==0 { iteration_in_progress = true have_first_byte = false - void c64.CHKIN(11) ; use #11 as input channel + void c64.CHKIN(12) ; use #12 as input channel if_cc { first_byte = c64.CHRIN() ; read first byte to test for file not found if not c64.READST() { @@ -294,7 +296,7 @@ close_end: num_bytes-- } - void c64.CHKIN(11) ; use #11 as input channel again + void c64.CHKIN(12) ; use #12 as input channel again %asm {{ lda bufferpointer @@ -359,8 +361,8 @@ m_in_buffer sta $ffff %asm {{ sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 - ldx #11 - jsr c64.CHKIN ; use channel 11 again for input + ldx #12 + jsr c64.CHKIN ; use channel 12 again for input ldy #0 lda have_first_byte beq _loop @@ -389,23 +391,23 @@ _end rts ; -- end an iterative file loading session (close channels). if iteration_in_progress { c64.CLRCHN() - c64.CLOSE(11) + c64.CLOSE(12) iteration_in_progress = false } } - ; ----- iterative file saver functions (uses io channel 14) ----- + ; ----- iterative file writing functions (uses io channel 13) ----- sub f_open_w(ubyte drivenumber, uword filenameptr) -> bool { ; -- open a file for iterative writing with f_write f_close_w() c64.SETNAM(string.length(filenameptr), filenameptr) - c64.SETLFS(14, drivenumber, 1) - void c64.OPEN() ; open 14,8,1,"filename" + c64.SETLFS(13, drivenumber, 1) + void c64.OPEN() ; open 13,8,1,"filename" if_cc { - void c64.CHKOUT(14) ; use #14 as output channel + c64.CHKOUT(13) ; use #13 as output channel return not c64.READST() } f_close_w() @@ -413,9 +415,9 @@ _end rts } sub f_write(uword bufferpointer, uword num_bytes) -> bool { - ; -- write the given umber of bytes to the currently open file + ; -- write the given number of bytes to the currently open file if num_bytes!=0 { - void c64.CHKOUT(14) ; use #14 as output channel again + c64.CHKOUT(13) ; use #13 as output channel again repeat num_bytes { c64.CHROUT(@(bufferpointer)) bufferpointer++ @@ -428,7 +430,7 @@ _end rts sub f_close_w() { ; -- end an iterative file writing session (close channels). c64.CLRCHN() - c64.CLOSE(14) + c64.CLOSE(13) } diff --git a/compiler/test/TestCompilerOnExamples.kt b/compiler/test/TestCompilerOnExamples.kt index e3a4f6126..ff887eb31 100644 --- a/compiler/test/TestCompilerOnExamples.kt +++ b/compiler/test/TestCompilerOnExamples.kt @@ -102,6 +102,7 @@ class TestCompilerOnExamplesCx16: FunSpec({ "cube3d", "datetime", "diskspeed", + "fileseek", "highresbitmap", "kefrenbars", "keyboardhandler", diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 6a9d7237d..051556c99 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,7 +3,11 @@ TODO For next release ^^^^^^^^^^^^^^^^ +- get rid of diskio.have_first_byte. But detecting invalid filenames should still work. +- diskio.f_read doesn't signal end of file condition if the requested number of bytes==1 ? +- diskio.f_read doesn't work if used after seek with buffer too small? - ir/vm: check weird asm chunks appearing in block? +- try to get the cx16 adpcm example to output audio - attempt to fix the expression codegen bug with reused temp vars (github #89) - AstIdentifiersChecker: can a subroutine really not have the same name as its enclosing block? 64tass problem? - 6502 codegen: make it possible to use cpu opcodes such as 'nop' as variable names by prefixing all asm vars with something such as ``p8v_``? Or not worth it (most 3 letter opcodes as variables are nonsensical anyway) diff --git a/examples/cx16/fileseek.p8 b/examples/cx16/fileseek.p8 new file mode 100644 index 000000000..8f0256c36 --- /dev/null +++ b/examples/cx16/fileseek.p8 @@ -0,0 +1,85 @@ +; this program shows the use of the f_seek function to seek to a position in an opened file. +; (this only works on Commander X16 DOS. on sdcard, not on host filesystem.) + +%import diskio +%import cx16diskio +%import textio +%zeropage basicsafe +%option no_sysinit + +main { + str FILENAME = "seektestfile.bin" + + sub start() { + txt.print("writing data file...\n") + uword total=0 + diskio.delete(8, FILENAME) + if diskio.f_open_w(8, FILENAME) { + repeat 1000 { + str text = "hello world." + void diskio.f_write(text, string.length(text)) + total += string.length(text) + } + diskio.f_close_w() + txt.print("written size=") + txt.print_uw(total) + txt.nl() + } else { + txt.print("error: ") + txt.print(diskio.status(8)) + sys.exit(1) + } + + read_last_bytes() + +; txt.print("\nseeking to 11992 and writing a few bytes...\n") +; if diskio.f_open_w(8, FILENAME) { +; cx16diskio.f_seek_w(0,0,msb(11992),lsb(11992)) +; txt.print(diskio.status(8)) +; txt.nl() +; void diskio.f_write("123", 3) +; diskio.f_close_w() +; } else { +; txt.print("error: ") +; txt.print(diskio.status(8)) +; sys.exit(1) +; } +; +; read_last_bytes() + } + + sub read_last_bytes() { + ; read the last 10 bytes of the 12000 bytes file + ubyte[256] buffer + uword total = 0 + uword size + txt.print("\nseeking to 11990 and reading...\n") + if diskio.f_open(8, FILENAME) { + cx16diskio.f_seek(0, 11990) + do { + size = diskio.f_read(buffer, sizeof(buffer)) + total += size + } until size==0 + diskio.f_close() + txt.print("size read=") + txt.print_uw(total) + txt.nl() + buffer[lsb(total)] = 0 + txt.print("buffer read=") + ubyte idx + for idx in 0 to lsb(total-1) { + txt.print_ubhex(buffer[idx], false) + txt.spc() + } + txt.spc() + txt.chrout('{') + txt.print(buffer) + txt.chrout('}') + txt.nl() + } else { + txt.print("error: ") + txt.print(diskio.status(8)) + sys.exit(1) + } + } +}