first attempt at a ProDOS library for the Apple II

This commit is contained in:
Joel Heikkila 2021-02-02 23:33:45 -05:00
parent 3a2e29888d
commit ef34f534f9
2 changed files with 310 additions and 0 deletions

View File

@ -0,0 +1,37 @@
// simple demonstration of ProDOS library routines that will write
// the Disk II ROM (assuming it is in slot 6) to the file DISKII.ROM
import stdio
import apple2_prodos
void main() {
// ProDOS requires a 1K aligned page for an open file as an IO buffer
array iobuf [1024] align(256)
// you have to explicitly create a file if it doesn't exist yet
// this can fail (so you should check prodos_error
// 06 is general binary type
prodos_create("DISKII.ROM"p, $06)
if prodos_error != 0 {
// prodos error call will be returned in prodos_error so you know
// what went wrong. 0 = no error
putstrz("{n}couldn't create file"z)
panic()
}
// ProDOS file handle
byte fp
fp = prodos_open("DISKII.ROM"p, iobuf)
// should check here again for error, and after all calls
// write the disk controller ROM to the file
prodos_write(fp, $c600, 256)
// closing frees the handle and io buffer
prodos_close(fp)
putstrz("{n}DONE"z)
while true { }
}

273
include/apple2_prodos.mfk Normal file
View File

@ -0,0 +1,273 @@
const byte PRODOS_ALLOC_INTERRUPT = $40
const byte PRODOS_DEALLOC_INTERRUPT = $41
const byte PRODOS_READ_BLOCK = $80
const byte PRODOS_WRITE_BLOCK = $81
const byte PRODOS_GET_TIME = $82
const byte PRODOS_CREATE = $c0
const byte PRODOS_DESTROY = $c1
const byte PRODOS_RENAME = $c2
const byte PRODOS_SET_FILE_INFO = $c3
const byte PRODOS_GET_FILE_INFO = $c4
const byte PRODOS_ON_LINE = $c5
const byte PRODOS_SET_PREFIX = $c6
const byte PRODOS_GET_PREFIX = $c7
const byte PRODOS_OPEN = $c8
const byte PRODOS_NEWLINE = $c9
const byte PRODOS_READ = $ca
const byte PRODOS_WRITE = $cb
const byte PRODOS_CLOSE = $cc
const byte PRODOS_FLUSH = $cd
const byte PRODOS_SET_MARK = $ce
const byte PRODOS_GET_MARK = $cf
const byte PRODOS_SET_EOF = $d0
const byte PRODOS_GET_EOF = $d1
const byte PRODOS_SET_BUF = $d2
const byte PRODOS_GET_BUF = $d3
// ProDOS MLI parameter lists
struct read_block_plist {
byte param_count
byte unit_num
pointer data_buffer
word block_num
}
struct write_block_plist {
byte param_count
byte unit_num
pointer data_buffer
word block_num
}
struct close_plist {
byte param_count
byte ref_num
}
struct flush_plist {
byte param_count
byte ref_num
}
struct create_plist {
byte param_count
pointer pathname
byte access
byte file_type
word aux_type
byte storage_type
word create_time
word create_date
}
struct destroy_plist {
byte param_count
pointer pathname
}
struct open_plist {
byte param_count
pointer pathname
pointer io_buffer
byte ref_num
}
struct newline_plist {
byte param_count
byte ref_num
byte enable_mask
byte newline_char
}
struct read_plist {
byte param_count
byte ref_num
pointer data_buffer
word request_count
word trans_count
}
struct rename_plist {
byte param_count
pointer pathname
pointer new_pathname
}
struct write_plist {
byte param_count
byte ref_num
pointer data_buffer
word request_count
word trans_count
}
struct get_prefix_plist {
byte param_count
pointer data_buffer
}
struct set_prefix_plist {
byte param_count
pointer data_buffer
}
// we'll just reuse the same area for all plists
union prodos_plist {
read_block_plist read_block
write_block_plist write_block
create_plist create
destroy_plist destroy
rename_plist rename
open_plist open
newline_plist newline
read_plist read
write_plist write
close_plist close
flush_plist flush
get_prefix_plist get_prefix
set_prefix_plist set_prefix
}
prodos_plist plist
byte prodos_error
// Millfork doesn't support self-modification in the assembler yet, so this
// code is placed in the following array:
//
// jsr $bf00
// $00
// plist.addr
// rts
//
// We modify mli_trampoline[3] ($00 on the second line) to set the specific
// ProDOS call before we jsr to $bf00
//
// TODO: can we just jmp to bf00 and save the extra rts ?
array mli_trampoline = [ $20, 0, $bf, 0, plist.addr.lo, plist.addr.hi, $60 ]
asm void prodos_mli_call(byte register(a) pdcall) {
sta mli_trampoline+3
jsr mli_trampoline
sta prodos_error
rts
}
void prodos_read_block(byte unum, pointer dbuf, word bnum) {
plist.read_block.param_count = 3
plist.read_block.unit_num = unum
plist.read_block.data_buffer = dbuf
plist.read_block.block_num = bnum
prodos_mli_call(PRODOS_READ_BLOCK)
}
void prodos_write_block(byte unum, pointer dbuf, word bnum) {
plist.write_block.param_count = 3
plist.write_block.unit_num = unum
plist.write_block.data_buffer = dbuf
plist.write_block.block_num = bnum
prodos_mli_call(PRODOS_WRITE_BLOCK)
}
void prodos_close(byte rnum) {
plist.close.param_count = 1
plist.close.ref_num = rnum
prodos_mli_call(PRODOS_CLOSE)
}
void prodos_flush(byte fp) {
plist.flush.param_count = 1
plist.flush.ref_num = fp
prodos_mli_call(PRODOS_FLUSH)
}
void prodos_get_prefix(pointer fnbuf) {
plist.get_prefix.param_count = 1
plist.get_prefix.data_buffer = fnbuf
prodos_mli_call(PRODOS_GET_PREFIX)
}
void prodos_set_prefix(pointer fnbuf) {
plist.set_prefix.param_count = 1
plist.set_prefix.data_buffer = fnbuf
prodos_mli_call(PRODOS_SET_PREFIX)
}
void prodos_create(pointer fn, byte ftype) {
plist.create.param_count = 7
plist.create.pathname = fn
plist.create.access = $c3
plist.create.file_type = ftype
plist.create.aux_type = $0
plist.create.storage_type = 1
plist.create.create_time = 0
plist.create.create_date = 0
prodos_mli_call(PRODOS_CREATE)
}
void prodos_destroy (pointer fn) {
plist.destroy.param_count = 0
plist.destroy.pathname = fn
prodos_mli_call(PRODOS_DESTROY)
}
void prodos_rename(pointer fn, pointer newfn) {
plist.rename.param_count = 2
plist.rename.pathname = fn
plist.rename.new_pathname = newfn
prodos_mli_call(PRODOS_RENAME)
}
// returns file handle if no error
byte prodos_open (pointer fn, pointer b) {
plist.open.param_count = 3
plist.open.pathname = fn
plist.open.io_buffer = b
prodos_mli_call(PRODOS_OPEN)
return plist.open.ref_num
}
void prodos_newline(byte fp, byte mask, byte nlchar) {
plist.newline.param_count = 3
plist.newline.ref_num = fp
plist.newline.enable_mask = mask
plist.newline.newline_char = nlchar
prodos_mli_call(PRODOS_NEWLINE)
}
void prodos_read(byte rnum, pointer dbuf, word rcnt) {
plist.read.param_count = 4
plist.read.ref_num = rnum
plist.read.data_buffer = dbuf
plist.read.request_count = rcnt
prodos_mli_call(PRODOS_READ)
}
void prodos_write(byte rnum, pointer dbuf, word rcnt) {
plist.write.param_count = 4
plist.write.ref_num = rnum
plist.write.data_buffer = dbuf
plist.write.request_count = rcnt
prodos_mli_call(PRODOS_WRITE)
}