From 890327b381a25351b7c3e8a502d720ff04bf20e3 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Tue, 14 Dec 2021 23:54:42 +0100 Subject: [PATCH] the returnvalue of the diskio.load() function family now is just the last load address+1 (like kernal's LOAD routine). This fixes the inconsistent attempt to calculate a size, just let the caller do this if required. Added a small helper function in cx16diskio to do this for loads that span multiple banks. --- compiler/res/prog8lib/cx16/cx16diskio.p8 | 23 +++++---- compiler/res/prog8lib/diskio.p8 | 28 ++++------- docs/source/todo.rst | 2 - examples/test.p8 | 63 ++++++++++++++++++++++-- 4 files changed, 79 insertions(+), 37 deletions(-) diff --git a/compiler/res/prog8lib/cx16/cx16diskio.p8 b/compiler/res/prog8lib/cx16/cx16diskio.p8 index 468b0c39e..28161641c 100644 --- a/compiler/res/prog8lib/cx16/cx16diskio.p8 +++ b/compiler/res/prog8lib/cx16/cx16diskio.p8 @@ -11,28 +11,27 @@ cx16diskio { ; If you don't give an address_override, the location in memory is taken from the 2-byte file header. ; If you specify a custom address_override, the first 2 bytes in the file are ignored ; and the rest is loaded at the given location in memory. - ; Returns the number of bytes loaded (truncated to 16 bits, if the file is larger than 64 Kb, - ; you'll have to compensate yourself by checking the ram banks). + ; Returns the end load address+1 if successful or 0 if a load error occurred. + ; You can use the load_size() function to calcuate the size of the file that was loaded. sub load(ubyte drivenumber, uword filenameptr, ubyte bank, uword address_override) -> uword { cx16.rambank(bank) - uword size = diskio.load(drivenumber, filenameptr, address_override) - if size - return size + $2000 * (cx16.getrambank() - bank) - return 0 + return diskio.load(drivenumber, filenameptr, address_override) } ; Use kernal LOAD routine to load the given file in memory. ; INCLUDING the first 2 bytes in the file: no program header is assumed in the file. ; This is different from Basic's LOAD instruction which always skips the first two bytes. ; The load address is mandatory. Returns the number of bytes loaded. - ; Returns the number of bytes loaded (truncated to 16 bits, if the file is larger than 64 Kb, - ; you'll have to compensate yourself by checking the ram banks). + ; Returns the end load address+1 if successful or 0 if a load error occurred. + ; You can use the load_size() function to calcuate the size of the file that was loaded. sub load_raw(ubyte drivenumber, uword filenameptr, ubyte bank, uword address) -> uword { cx16.rambank(bank) - uword size = diskio.load_raw(drivenumber, filenameptr, address) - if size - return size + $2000 * (cx16.getrambank() - bank) - return 0 + return diskio.load_raw(drivenumber, filenameptr, address) } + ; For use directly after a load or load_raw call (don't mess with the ram bank yet): + ; Calculates the number of bytes loaded (files > 64Kb ar truncated to 16 bits) + sub load_size(ubyte startbank, uword startaddress, uword endaddress) -> uword { + return $2000 * (cx16.getrambank() - startbank) + endaddress - startaddress + } } diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index 612897b0c..281b05159 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -438,9 +438,7 @@ io_error: ; If you don't give an address_override, the location in memory is taken from the 2-byte file header. ; If you specify a custom address_override, the first 2 bytes in the file are ignored ; and the rest is loaded at the given location in memory. - ; Returns the number of bytes loaded if address_override was given, otherwise the end address. - ; TODO this is stupid - why not always return the number of bytes loaded and let the caller figure out the rest - ; + ; Returns the end load address+1 if successful or 0 if a load error occurred. ; NOTE: when the load is larger than 64Kb and/or spans multiple RAM banks ; (which is possible on the Commander X16), the returned size is not correct, ; because it doesn't take the number of ram banks into account. @@ -448,7 +446,7 @@ io_error: sub load(ubyte drivenumber, uword filenameptr, uword address_override) -> uword { c64.SETNAM(string.length(filenameptr), filenameptr) ubyte secondary = 1 - uword end_of_load = 0 + cx16.r1 = 0 if address_override secondary = 0 c64.SETLFS(1, drivenumber, secondary) @@ -459,24 +457,21 @@ io_error: ldy address_override+1 jsr c64.LOAD bcs + - stx end_of_load - sty end_of_load+1 + stx cx16.r1 + sty cx16.r1+1 + ldx P8ZP_SCRATCH_REG }} c64.CLRCHN() c64.CLOSE(1) - - if end_of_load - return end_of_load - address_override ; not correct when the file spans multiple RAM banks - - return 0 + return cx16.r1 } ; Use kernal LOAD routine to load the given file in memory. ; INCLUDING the first 2 bytes in the file: no program header is assumed in the file. ; This is different from Basic's LOAD instruction which always skips the first two bytes. - ; The load address is mandatory. Returns the number of bytes loaded. + ; The load address is mandatory. + ; Returns the end load address+1 if successful or 0 if a load error occurred. ; NOTE: when the load is larger than 64Kb and/or spans multiple RAM banks ; (which is possible on the Commander X16), the returned size is not correct, ; because it doesn't take the number of ram banks into account. @@ -484,15 +479,12 @@ io_error: sub load_raw(ubyte drivenumber, uword filenameptr, uword address) -> uword { if not f_open(drivenumber, filenameptr) return 0 - uword size = f_read(address, 2) + cx16.r1 = f_read(address, 2) f_close() - if size!=2 + if cx16.r1!=2 return 0 address += 2 - size = load(drivenumber, filenameptr, address) - if size - return size+2 - return 0 + return load(drivenumber, filenameptr, address) } sub delete(ubyte drivenumber, uword filenameptr) { diff --git a/docs/source/todo.rst b/docs/source/todo.rst index 5a7dde7f4..099e0ff05 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -3,8 +3,6 @@ TODO For next compiler release (7.6) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -fix return value of diskio.load() (see commment) and possibly other routines? - optimization in call convention: non-asm subroutines with just a single byte or word parameter: pass the parameter via A or A/Y registers. diff --git a/examples/test.p8 b/examples/test.p8 index 6af86efc1..b06744937 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,12 +1,65 @@ +%import diskio +%import cx16diskio %import textio %zeropage basicsafe main { sub start() { - str derp = "derp" * 4 - derp = derp / "zzz" - derp = derp - "zzz" - derp = derp + "zzz" - txt.print(&derp+2) + uword xx + uword yy + + c64.SETMSG(%10000000) + xx = diskio.load(8, "hello", 0) + txt.nl() + yy = diskio.load(8, "hello", $8800) + txt.nl() + c64.SETMSG(0) + + txt.print_uwhex(xx, true) + txt.nl() + txt.print_uwhex(yy, true) + txt.nl() + + c64.SETMSG(%10000000) + xx = diskio.load_raw(8, "hello", $8700) + txt.nl() + c64.SETMSG(0) + txt.print_uwhex(xx, true) + txt.nl() + + txt.print("\ncx16:\n") + + c64.SETMSG(%10000000) + yy = cx16diskio.load(8, "x16edit", 1, $3000) + txt.nl() + c64.SETMSG(0) + txt.print_uwhex(yy, true) + txt.nl() + + c64.SETMSG(%10000000) + xx = cx16diskio.load_raw(8, "x16edit", 1, $3000) + txt.nl() + c64.SETMSG(0) + txt.print_uwhex(xx, true) + txt.nl() + txt.print_uw(cx16diskio.load_size(1, $3000, xx)) + txt.nl() + + c64.SETMSG(%10000000) + xx = cx16diskio.load(8, "x16edit", 4, $a100) + txt.nl() + c64.SETMSG(0) + txt.print_uwhex(xx, true) + txt.nl() + txt.print_uw(cx16diskio.load_size(4, $a100, xx)) + txt.nl() + c64.SETMSG(%10000000) + xx = cx16diskio.load_raw(8, "x16edit", 4, $a100) + txt.nl() + c64.SETMSG(0) + txt.print_uwhex(xx, true) + txt.nl() + txt.print_uw(cx16diskio.load_size(4, $a100, xx)) + txt.nl() } }