diff --git a/compiler/res/prog8lib/cx16/cx16diskio.p8 b/compiler/res/prog8lib/cx16/cx16diskio.p8 deleted file mode 100644 index 18f6826ab..000000000 --- a/compiler/res/prog8lib/cx16/cx16diskio.p8 +++ /dev/null @@ -1,239 +0,0 @@ -; Cx16 specific disk drive I/O routines. - -%import diskio -%import string - -cx16diskio { - - ; Same as diskio.load() but with additional bank parameter to select the Ram bank to load into. - ; Use kernal LOAD routine to load the given program file in memory. - ; This is similar to Basic's LOAD "filename",drive / LOAD "filename",drive,1 - ; 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 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. - ; TODO remove this, but add comment about bank and load_size to diskio.load_raw() - sub load(uword filenameptr, ubyte bank, uword address_override) -> uword { - cx16.rambank(bank) - return diskio.internal_load_routine(filenameptr, address_override, false) - } - - ; Same as diskio.load_raw() but with additional bank parameter to select the Ram bank to load into. - ; 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. - ; The load address is mandatory. Returns the number of bytes loaded. - ; If you load into regular system ram, use cx16.getrambank() for the bank argument, - ; or alternatively make sure to reset the correct ram bank yourself after the load! - ; 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. - ; TODO remove this, but add comment about bank and load_size to diskio.load_raw() - sub load_raw(uword filenameptr, ubyte bank, uword address_override) -> uword { - cx16.rambank(bank) - return diskio.internal_load_routine(filenameptr, address_override, true) - } - - ; Replacement function that makes use of fast block read capability of the X16, - ; and can wrap over multiple ram banks while reading. - ; Use this in place of regular diskio.f_read() on X16. - ; TODO use this one, get rid of diskio.f_read - sub f_read(uword bufferpointer, uword num_bytes) -> uword { - ; -- read from the currently open file, up to the given number of bytes. - ; returns the actual number of bytes read. (checks for End-of-file and error conditions) - if not diskio.iteration_in_progress or not num_bytes - return 0 - - diskio.list_blocks = 0 ; we reuse this variable for the total number of bytes read - - ; commander X16 supports fast block-read via macptr() kernal call - uword size - while num_bytes { - size = 255 - if num_bytes uword { - ; -- read the full contents of the file, returns number of bytes read. - if not diskio.iteration_in_progress - return 0 - - uword total_read = 0 - while not cbm.READST() { - cx16.r0 = cx16diskio.f_read(bufferpointer, 256) - total_read += cx16.r0 - bufferpointer += cx16.r0 - } - return total_read - } - - - ; CommanderX16 extensions over the basic C64/C128 diskio routines: - - ; 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 - } - - asmsub vload(str name @R0, 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 {{ - clc -internal_vload: - phx - pha - ldx diskio.drivenumber - bcc + - ldy #%00000010 ; headerless load mode - bne ++ -+ ldy #0 ; normal load mode -+ lda #1 - jsr cbm.SETLFS - lda cx16.r0 - ldy cx16.r0+1 - jsr prog8_lib.strlen - tya - ldx cx16.r0 - ldy cx16.r0+1 - jsr cbm.SETNAM - pla - clc - adc #2 - ldx cx16.r1 - ldy cx16.r1+1 - stz P8ZP_SCRATCH_B1 - jsr cbm.LOAD - bcs + - inc P8ZP_SCRATCH_B1 - + jsr cbm.CLRCHN - lda #1 - jsr cbm.CLOSE - plx - lda P8ZP_SCRATCH_B1 - rts - }} - } - - asmsub vload_raw(str name @R0, 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 {{ - sec - jmp vload.internal_vload - }} - } - - sub chdir(str path) { - ; -- change current directory. - diskio.list_filename[0] = 'c' - diskio.list_filename[1] = 'd' - diskio.list_filename[2] = ':' - void string.copy(path, &diskio.list_filename+3) - diskio.send_command(diskio.list_filename) - } - - sub mkdir(str name) { - ; -- make a new subdirectory. - diskio.list_filename[0] = 'm' - diskio.list_filename[1] = 'd' - diskio.list_filename[2] = ':' - void string.copy(name, &diskio.list_filename+3) - diskio.send_command(diskio.list_filename) - } - - sub rmdir(str name) { - ; -- remove a subdirectory. - void string.find(name, '*') - if_cs - return ; refuse to act on a wildcard * - diskio.list_filename[0] = 'r' - diskio.list_filename[1] = 'd' - diskio.list_filename[2] = ':' - void string.copy(name, &diskio.list_filename+3) - diskio.send_command(diskio.list_filename) - } - - sub relabel(str name) { - ; -- change the disk label. - diskio.list_filename[0] = 'r' - diskio.list_filename[1] = '-' - diskio.list_filename[2] = 'h' - diskio.list_filename[3] = ':' - void string.copy(name, &diskio.list_filename+4) - diskio.send_command(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: - cbm.SETNAM(sizeof(command), &command) - cbm.SETLFS(15, diskio.drivenumber, 15) - void cbm.OPEN() - cbm.CLOSE(15) - } - - ; 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] = 13 ; f_open_w uses channel 13 -; cx16diskio.f_seek.command[2] = lsb(pos_loword) -; cx16diskio.f_seek.command[3] = msb(pos_loword) -; cx16diskio.f_seek.command[4] = lsb(pos_hiword) -; cx16diskio.f_seek.command[5] = msb(pos_hiword) -; goto cx16diskio.f_seek.send_command -; } -} diff --git a/compiler/res/prog8lib/cx16/diskio.p8 b/compiler/res/prog8lib/cx16/diskio.p8 index 76a616197..aa7375719 100644 --- a/compiler/res/prog8lib/cx16/diskio.p8 +++ b/compiler/res/prog8lib/cx16/diskio.p8 @@ -129,7 +129,7 @@ io_error: if lf_start_list(pattern_ptr) { while lf_next_entry() { if list_filetype!="dir" { - filenames_buffer += string.copy(diskio.list_filename, filenames_buffer) + 1 + filenames_buffer += string.copy(list_filename, filenames_buffer) + 1 files_found++ if filenames_buffer - buffer_start > filenames_buf_size-20 { @(filenames_buffer)=0 @@ -282,18 +282,37 @@ close_end: return false } + ; optimized for Commander X16 to use MACPTR block read kernal call sub f_read(uword bufferpointer, uword num_bytes) -> uword { ; -- read from the currently open file, up to the given number of bytes. ; returns the actual number of bytes read. (checks for End-of-file and error conditions) - ; NOTE: on systems with banked ram (such as Commander X16) this routine DOES NOT - ; automatically load into subsequent banks if it reaches a bank boundary! - ; Consider using cx16diskio.f_read() on X16. - ; TODO join modules if not iteration_in_progress or not num_bytes return 0 list_blocks = 0 ; we reuse this variable for the total number of bytes read + ; commander X16 supports fast block-read via macptr() kernal call + uword size + while num_bytes { + size = 255 + if num_bytes uword { ; -- read the full contents of the file, returns number of bytes read. - ; Note: Consider using cx16diskio.f_read_all() on X16! TODO join modules if not iteration_in_progress return 0 @@ -482,20 +501,17 @@ io_error: ; 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. - ; Also consider using cx16diskio.load() instead on the Commander X16. TODO join modules + ; You can use the load_size() function to calcuate the size in this case. + ; NOTE: data is read into the current Ram bank if you're reading into banked ram. + ; if you require loading into another ram bank, you have to set that + ; yourself using cx16.rambank(bank) before calling load(). sub load(uword filenameptr, uword address_override) -> uword { return internal_load_routine(filenameptr, address_override, false) } - ; 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 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. - ; Also consider using cx16diskio.load_raw() instead on the Commander X16. TODO join modules + ; Identical to load(), but DOES INCLUDE the first 2 bytes in the file. + ; No program header is assumed in the file. Everything is loaded. + ; See comments on load() for more details. sub load_raw(uword filenameptr, uword address) -> uword { return internal_load_routine(filenameptr, address, true) } @@ -561,4 +577,131 @@ io_error: cbm.CLRCHN() cbm.CLOSE(15) } + + + ; CommanderX16 extensions over the basic C64/C128 diskio routines: + + ; 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 + } + + asmsub vload(str name @R0, 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 {{ + clc +internal_vload: + phx + pha + ldx drivenumber + bcc + + ldy #%00000010 ; headerless load mode + bne ++ ++ ldy #0 ; normal load mode ++ lda #1 + jsr cbm.SETLFS + lda cx16.r0 + ldy cx16.r0+1 + jsr prog8_lib.strlen + tya + ldx cx16.r0 + ldy cx16.r0+1 + jsr cbm.SETNAM + pla + clc + adc #2 + ldx cx16.r1 + ldy cx16.r1+1 + stz P8ZP_SCRATCH_B1 + jsr cbm.LOAD + bcs + + inc P8ZP_SCRATCH_B1 + + jsr cbm.CLRCHN + lda #1 + jsr cbm.CLOSE + plx + lda P8ZP_SCRATCH_B1 + rts + }} + } + + asmsub vload_raw(str name @R0, 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 {{ + sec + jmp vload.internal_vload + }} + } + + sub chdir(str path) { + ; -- change current directory. + list_filename[0] = 'c' + list_filename[1] = 'd' + list_filename[2] = ':' + void string.copy(path, &list_filename+3) + send_command(list_filename) + } + + sub mkdir(str name) { + ; -- make a new subdirectory. + list_filename[0] = 'm' + list_filename[1] = 'd' + list_filename[2] = ':' + void string.copy(name, &list_filename+3) + send_command(list_filename) + } + + sub rmdir(str name) { + ; -- remove a subdirectory. + void string.find(name, '*') + if_cs + return ; refuse to act on a wildcard * + list_filename[0] = 'r' + list_filename[1] = 'd' + list_filename[2] = ':' + void string.copy(name, &list_filename+3) + send_command(list_filename) + } + + sub relabel(str name) { + ; -- change the disk label. + list_filename[0] = 'r' + list_filename[1] = '-' + list_filename[2] = 'h' + list_filename[3] = ':' + void string.copy(name, &list_filename+4) + send_command(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: + cbm.SETNAM(sizeof(command), &command) + cbm.SETLFS(15, drivenumber, 15) + void cbm.OPEN() + cbm.CLOSE(15) + } + + ; 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 +; f_seek.command[1] = 13 ; f_open_w uses channel 13 +; f_seek.command[2] = lsb(pos_loword) +; f_seek.command[3] = msb(pos_loword) +; f_seek.command[4] = lsb(pos_hiword) +; f_seek.command[5] = msb(pos_hiword) +; goto f_seek.send_command +; } + } diff --git a/compiler/res/prog8lib/diskio.p8 b/compiler/res/prog8lib/diskio.p8 index 40fd35b41..792c68ba8 100644 --- a/compiler/res/prog8lib/diskio.p8 +++ b/compiler/res/prog8lib/diskio.p8 @@ -128,7 +128,7 @@ io_error: if lf_start_list(pattern_ptr) { while lf_next_entry() { if list_filetype!="dir" { - filenames_buffer += string.copy(diskio.list_filename, filenames_buffer) + 1 + filenames_buffer += string.copy(list_filename, filenames_buffer) + 1 files_found++ if filenames_buffer - buffer_start > filenames_buf_size-20 { @(filenames_buffer)=0 @@ -497,11 +497,9 @@ io_error: 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 end load address+1 if successful or 0 if a load error occurred. + ; Identical to load(), but DOES INCLUDE the first 2 bytes in the file. + ; No program header is assumed in the file. Everything is loaded. + ; See comments on load() for more details. sub load_raw(uword filenameptr, uword address) -> uword { ; read the 2 header bytes separately to skip them if not f_open(filenameptr) diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index bdcb26b3c..d8120705e 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -150,7 +150,12 @@ Provides several routines that deal with disk drive I/O, such as: - delete and rename files on the disk - send arbitrary CbmDos command to disk drive +Commander X16 additions: On the Commander X16 it tries to use that machine's fast Kernal loading routines if possible. +Routines to directly load data into video ram are also present (vload and vload_raw). +Also contains a helper function to calculate the file size of a loaded file (although that is truncated +to 16 bits, 64Kb) +Als contains routines for operating on subdirectories (chdir, mkdir, rmdir) and to relabel the disk. string @@ -381,16 +386,6 @@ because the Commander X16's default colors for this (the first 16 colors) are to and are quite different than how they looked on a VIC-II chip in a C64. -cx16diskio (cx16 only) ------------------------ -Available for the Cx16 target. Contains extensions to the load and load_raw routines from the regular -diskio module, to deal with loading of potentially large files in to banked ram (HiRam). -Routines to directly load data into video ram are also present (vload and vload_raw). -Also contains a helper function to calculate the file size of a loaded file (although that is truncated -to 16 bits, 64Kb) -Als contains routines for operating on subdirectories (chdir, mkdir, rmdir) and to relabel the disk. - - psg (cx16 only) ---------------- Available for the Cx16 target. diff --git a/docs/source/todo.rst b/docs/source/todo.rst index bd2c60d4f..c96360bb4 100644 --- a/docs/source/todo.rst +++ b/docs/source/todo.rst @@ -8,14 +8,14 @@ For 9.0 major changes - DONE: rename sqrt16() to just sqrt(), make it accept multiple numeric types. Renamed floats.sqrt() to floats.sqrtf() but you can just use sqrt() - DONE: abs() now supports multiple datatypes including float. No need to use floats.fabs() anymore. - DONE: divmod() now supports multiple datatypes. divmodw() has been removed. -- DONE: drivenumber parameter removed from all routines in diskio and cx16diskio modules. The drive to work on is now simply stored as a diskio.drivenumber variable, which defaults to 8. +- DONE: cx16diskio module merged into diskio (which got specialized for commander x16 target). load() and load_raw() with extra ram bank parameter are gone. +- DONE: drivenumber parameter removed from all routines in diskio module. The drive to work on is now simply stored as a diskio.drivenumber variable, which defaults to 8. -- duplicate diskio for cx16 (get rid of cx16diskio, just copy diskio and tweak everything) + documentation +- get f_seek_w working like in the BASIC program on the sdcard - this needs the changes to diskio.f_open to use suffixes ,p,m - 6502 codegen: see if we can let for loops skip the loop if startvar>endvar, without adding a lot of code size/duplicating the loop condition. It is documented behavior to now loop 'around' $00 but it's too easy to forget about! Lot of work because of so many special cases in ForLoopsAsmgen..... (vm codegen already behaves like this!) -- get f_seek_w working like in the BASIC program - this needs the changes to diskio.f_open to use suffixes ,p,m - once 9.0 is stable, upgrade other programs (assem, shell, etc) to it. + add migration guide to the manual. - [much work:] add special (u)word array type (or modifier such as @fast? ) that puts the array into memory as 2 separate byte-arrays 1 for LSB 1 for MSB -> allows for word arrays of length 256 and faster indexing this is an enormous amout of work, if this type is to be treated equally as existing (u)word , because all expression / lookup / assignment routines need to know about the distinction.... diff --git a/examples/cx16/diskspeed.p8 b/examples/cx16/diskspeed.p8 index d2660b7c6..5964ff1e9 100644 --- a/examples/cx16/diskspeed.p8 +++ b/examples/cx16/diskspeed.p8 @@ -1,5 +1,4 @@ %import diskio -%import cx16diskio %import floats %zeropage basicsafe %option no_sysinit @@ -59,7 +58,8 @@ main { batchtotaltime = 0 repeat REPEATS { cbm.SETTIM(0,0,0) - if not cx16diskio.load("benchmark.dat", 4, $a000) + cx16.rambank(4) + if not diskio.load("benchmark.dat", $a000) sys.exit(1) batchtotaltime += cbm.RDTIM16() txt.chrout('.') @@ -70,7 +70,7 @@ main { batchtotaltime = 0 repeat REPEATS { cbm.SETTIM(0,0,0) - if not cx16diskio.vload("benchmark.dat", 0, $0000) + if not diskio.vload("benchmark.dat", 0, $0000) sys.exit(1) batchtotaltime += cbm.RDTIM16() txt.chrout('.') @@ -99,7 +99,7 @@ main { if diskio.f_open("benchmark.dat") { cbm.SETTIM(0,0,0) repeat 65536/255 { - if not cx16diskio.f_read(buffer, 255) + if not diskio.f_read(buffer, 255) sys.exit(1) } batchtotaltime += cbm.RDTIM16() diff --git a/examples/cx16/fileseek.p8 b/examples/cx16/fileseek.p8 index 93fd72cde..93c24c94a 100644 --- a/examples/cx16/fileseek.p8 +++ b/examples/cx16/fileseek.p8 @@ -2,7 +2,6 @@ ; (this only works on Commander X16 DOS. on sdcard, not on host filesystem.) %import diskio -%import cx16diskio %import textio %zeropage basicsafe %option no_sysinit @@ -35,7 +34,7 @@ main { ; NOTE: f_seek_w() doesn't work right now. It requires substantial changes to the diskio library that are not compatible with the C64/C128. ; txt.print("\nseeking to 1292 and writing a few bytes...\n") ; if diskio.f_open_w("seektestfile.bin,p,m") { -; cx16diskio.f_seek_w(0, 1292) +; diskio.f_seek_w(0, 1292) ; void diskio.f_write("123", 3) ; diskio.f_close_w() ; } else { @@ -65,7 +64,7 @@ main { txt.print("\nseeking to 1290 and reading...\n") if diskio.f_open("seektestfile.bin") { - cx16diskio.f_seek(0, 1290) + diskio.f_seek(0, 1290) uword ptr = megabuffer do { size = diskio.f_read(ptr, 255) diff --git a/examples/cx16/pcmaudio/stream-wav.p8 b/examples/cx16/pcmaudio/stream-wav.p8 index de03cba1f..6de700d4b 100644 --- a/examples/cx16/pcmaudio/stream-wav.p8 +++ b/examples/cx16/pcmaudio/stream-wav.p8 @@ -1,6 +1,5 @@ %import textio %import diskio -%import cx16diskio %import floats %import adpcm %import wavfile @@ -41,7 +40,7 @@ main { txt.print(MUSIC_FILENAME) txt.nl() if diskio.f_open(MUSIC_FILENAME) { - void cx16diskio.f_read(buffer, 128) + void diskio.f_read(buffer, 128) wav_ok = wavfile.parse_header(buffer) diskio.f_close() } @@ -105,13 +104,13 @@ main { uword block_size = 1024 if wavfile.wavefmt==wavfile.WAVE_FORMAT_DVI_ADPCM block_size = wavfile.block_align - void cx16diskio.f_read(buffer, wavfile.data_offset) ; skip to actual sample data start - void cx16diskio.f_read(buffer, block_size) ; preload buffer + void diskio.f_read(buffer, wavfile.data_offset) ; skip to actual sample data start + void diskio.f_read(buffer, block_size) ; preload buffer cx16.VERA_AUDIO_RATE = vera_rate ; start playback repeat { interrupt.wait_and_clear_aflow_semaphore() ;; cx16.vpoke(1,$fa00, $a0) ; paint a screen color - uword size = cx16diskio.f_read(buffer, block_size) + uword size = diskio.f_read(buffer, block_size) ;; cx16.vpoke(1,$fa00, $00) ; paint a screen color if size