mirror of
https://github.com/KarolS/millfork.git
synced 2024-05-31 18:41:30 +00:00
first attempt at a ProDOS library for the Apple II
This commit is contained in:
parent
3a2e29888d
commit
ef34f534f9
37
examples/apple2/diskrom_dump.mfk
Normal file
37
examples/apple2/diskrom_dump.mfk
Normal 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
273
include/apple2_prodos.mfk
Normal 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)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user