mirror of
https://github.com/a2stuff/prodos-drivers.git
synced 2024-09-27 20:56:50 +00:00
Use common driver chain logic
This commit is contained in:
parent
2769d1d7a6
commit
db977835ac
8
Makefile
8
Makefile
@ -4,6 +4,12 @@ LDFLAGS = --config apple2-asm.cfg
|
|||||||
|
|
||||||
TARGETS = bye.system.SYS buhbye.system.SYS quit.system.SYS
|
TARGETS = bye.system.SYS buhbye.system.SYS quit.system.SYS
|
||||||
|
|
||||||
|
# For timestamps
|
||||||
|
MM = $(shell date "+%-m")
|
||||||
|
DD = $(shell date "+%-d")
|
||||||
|
YY = $(shell date "+%-y")
|
||||||
|
DEFINES = -D DD=$(DD) -D MM=$(MM) -D YY=$(YY)
|
||||||
|
|
||||||
.PHONY: clean all
|
.PHONY: clean all
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
|
||||||
@ -14,7 +20,7 @@ clean:
|
|||||||
rm -f $(TARGETS)
|
rm -f $(TARGETS)
|
||||||
|
|
||||||
%.o: %.s $(HEADERS)
|
%.o: %.s $(HEADERS)
|
||||||
ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $<
|
ca65 $(CAFLAGS) $(DEFINES) --listing $(basename $@).list -o $@ $<
|
||||||
|
|
||||||
%.SYS: %.o
|
%.SYS: %.o
|
||||||
ld65 $(LDFLAGS) -o $@ $<
|
ld65 $(LDFLAGS) -o $@ $<
|
||||||
|
112
buhbye.system.s
112
buhbye.system.s
@ -3,10 +3,18 @@
|
|||||||
;;; (so this is Bell's Better Bird's Better Bye - Buh-Bye)
|
;;; (so this is Bell's Better Bird's Better Bye - Buh-Bye)
|
||||||
;;; * alpha key advances to next matching filename
|
;;; * alpha key advances to next matching filename
|
||||||
;;; * replaced directory enumeration (smaller, per PDTRM)
|
;;; * replaced directory enumeration (smaller, per PDTRM)
|
||||||
|
;;; * installs, then chains to next .SYSTEM file
|
||||||
|
|
||||||
.setcpu "65C02"
|
.setcpu "65C02"
|
||||||
|
.linecont +
|
||||||
|
.feature string_escapes
|
||||||
|
|
||||||
.include "apple2.inc"
|
.include "apple2.inc"
|
||||||
.include "prodos.inc"
|
.include "apple2.mac"
|
||||||
|
|
||||||
|
.include "inc/apple2.inc"
|
||||||
|
.include "inc/macros.inc"
|
||||||
|
.include "inc/prodos.inc"
|
||||||
|
|
||||||
;;; Miscellaneous
|
;;; Miscellaneous
|
||||||
|
|
||||||
@ -14,12 +22,6 @@ COL80HPOS := $57B
|
|||||||
|
|
||||||
;;; I/O Soft Switches / Firmware
|
;;; I/O Soft Switches / Firmware
|
||||||
|
|
||||||
RAMRDOFF := $C002 ; If 80STORE Off: Read Main Mem $0200-$BFFF
|
|
||||||
RAMRDON := $C003 ; If 80STORE Off: Read Aux Mem $0200-$BFFF
|
|
||||||
RAMWRTOFF := $C004 ; If 80STORE Off: Write Main Mem $0200-$BFFF
|
|
||||||
RAMWRTON := $C005 ; If 80STORE Off: Write Aux Mem $0200-$BFFF
|
|
||||||
ALTZPOFF := $C008 ; Main Stack and Zero Page
|
|
||||||
ALTZPON := $C009 ; Aux Stack and Zero Page
|
|
||||||
ROMINNW := $C082 ; Read ROM; no write
|
ROMINNW := $C082 ; Read ROM; no write
|
||||||
ROMINWB1 := $C089 ; Read ROM; write RAM bank 1
|
ROMINWB1 := $C089 ; Read ROM; write RAM bank 1
|
||||||
|
|
||||||
@ -31,10 +33,7 @@ SETTXT := $FB39
|
|||||||
TABV := $FB5B
|
TABV := $FB5B
|
||||||
SETPWRC := $FB6F
|
SETPWRC := $FB6F
|
||||||
BELL1 := $FBDD
|
BELL1 := $FBDD
|
||||||
HOME := $FC58
|
|
||||||
COUT := $FDED
|
|
||||||
SETINV := $FE80
|
SETINV := $FE80
|
||||||
SETNORM := $FE84
|
|
||||||
|
|
||||||
;;; ASCII/Key codes
|
;;; ASCII/Key codes
|
||||||
ASCII_TAB := $9
|
ASCII_TAB := $9
|
||||||
@ -47,21 +46,10 @@ ASCII_ETB := $17 ; scroll text window down
|
|||||||
ASCII_EM := $19 ; move cursor to upper left
|
ASCII_EM := $19 ; move cursor to upper left
|
||||||
ASCII_ESCAPE := $1B
|
ASCII_ESCAPE := $1B
|
||||||
|
|
||||||
;;; ------------------------------------------------------------
|
|
||||||
|
|
||||||
.define HI(char) (char|$80)
|
|
||||||
|
|
||||||
.macro HIASCII arg
|
|
||||||
.repeat .strlen(arg), i
|
|
||||||
.byte .strat(arg, i) | $80
|
|
||||||
.endrep
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
.macro HIASCIIZ arg
|
|
||||||
HIASCII arg
|
|
||||||
.byte 0
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
|
;;; ************************************************************
|
||||||
|
.include "driver_preamble.inc"
|
||||||
|
;;; ************************************************************
|
||||||
|
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
@ -76,11 +64,10 @@ ASCII_ESCAPE := $1B
|
|||||||
;;; Installer
|
;;; Installer
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
.org $2000
|
|
||||||
|
|
||||||
install_size := $300 ; must fit in $D100...$D3FF = $300
|
install_size := $300 ; must fit in $D100...$D3FF = $300
|
||||||
|
|
||||||
.proc install
|
.proc maybe_install_driver
|
||||||
|
|
||||||
src := install_src
|
src := install_src
|
||||||
end := install_src + install_size
|
end := install_src + install_size
|
||||||
dst := $D100 ; Install location in ProDOS (bank 2)
|
dst := $D100 ; Install location in ProDOS (bank 2)
|
||||||
@ -123,28 +110,17 @@ loop: lda (src_ptr) ; *src_ptr = *dst_ptr
|
|||||||
sta ALTZPOFF
|
sta ALTZPOFF
|
||||||
sta ROMINWB1
|
sta ROMINWB1
|
||||||
sta ROMINWB1
|
sta ROMINWB1
|
||||||
;; fall through
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
.proc quit
|
rts
|
||||||
MLI_CALL QUIT, params
|
|
||||||
|
|
||||||
.proc params
|
|
||||||
params: .byte 4
|
|
||||||
type: .byte 0
|
|
||||||
res1: .word 0
|
|
||||||
res2: .byte 0
|
|
||||||
res3: .addr 0
|
|
||||||
.endproc
|
.endproc
|
||||||
.endproc
|
|
||||||
|
|
||||||
install_src := *
|
|
||||||
|
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
;;; Selector
|
;;; Selector
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
.org $1000
|
install_src := *
|
||||||
|
|
||||||
|
pushorg $1000
|
||||||
.proc selector
|
.proc selector
|
||||||
|
|
||||||
prefix := $280 ; length-prefixed
|
prefix := $280 ; length-prefixed
|
||||||
@ -259,7 +235,7 @@ fail: lda prefix_depth ; root?
|
|||||||
|
|
||||||
;; Store entry_length (byte), entries_per_block (byte), file_count (word)
|
;; Store entry_length (byte), entries_per_block (byte), file_count (word)
|
||||||
ldx #3
|
ldx #3
|
||||||
: lda read_buffer + DirectoryHeader::entry_length,x
|
: lda read_buffer + SubdirectoryHeader::entry_length,x
|
||||||
sta entry_length,x
|
sta entry_length,x
|
||||||
dex
|
dex
|
||||||
bpl :-
|
bpl :-
|
||||||
@ -290,9 +266,9 @@ while_loop:
|
|||||||
;; Check file type
|
;; Check file type
|
||||||
ldy #FileEntry::file_type
|
ldy #FileEntry::file_type
|
||||||
lda (entry_pointer),y
|
lda (entry_pointer),y
|
||||||
cmp #FileType::Directory
|
cmp #FT_DIRECTORY
|
||||||
beq store_entry
|
beq store_entry
|
||||||
cmp #FileType::System
|
cmp #FT_SYSTEM
|
||||||
bne done_active_entry
|
bne done_active_entry
|
||||||
|
|
||||||
store_entry:
|
store_entry:
|
||||||
@ -693,7 +669,8 @@ cout: jmp COUT
|
|||||||
text_resources := *
|
text_resources := *
|
||||||
|
|
||||||
.proc help_string
|
.proc help_string
|
||||||
HIASCIIZ "RETURN: Select | TAB: Chg Vol | ESC: Back"
|
scrcode "RETURN: Select | TAB: Chg Vol | ESC: Back"
|
||||||
|
.byte 0
|
||||||
.endproc
|
.endproc
|
||||||
|
|
||||||
;; Mousetext sequence: Enable, folder left, folder right, disable
|
;; Mousetext sequence: Enable, folder left, folder right, disable
|
||||||
@ -704,43 +681,26 @@ cout: jmp COUT
|
|||||||
|
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
.proc open_params
|
DEFINE_OPEN_PARAMS open_params, prefix, $1C00
|
||||||
params: .byte 3
|
|
||||||
path: .addr prefix
|
|
||||||
buffer: .addr $1C00
|
|
||||||
ref_num:.byte 0
|
|
||||||
.endproc
|
|
||||||
open_params_ref_num := open_params::ref_num
|
open_params_ref_num := open_params::ref_num
|
||||||
|
|
||||||
.proc close_params
|
DEFINE_CLOSE_PARAMS close_params
|
||||||
params: .byte 1
|
|
||||||
ref_num:.byte 0
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
.proc on_line_params
|
DEFINE_ON_LINE_PARAMS on_line_params, $60, prefix+1
|
||||||
params: .byte 2
|
on_line_params_unit := on_line_params::unit_num
|
||||||
unit: .byte $60
|
|
||||||
buffer: .addr prefix+1
|
|
||||||
.endproc
|
|
||||||
on_line_params_unit := on_line_params::unit
|
|
||||||
|
|
||||||
.proc set_prefix_params
|
DEFINE_SET_PREFIX_PARAMS set_prefix_params, prefix
|
||||||
params: .byte 1
|
|
||||||
path: .addr prefix
|
|
||||||
.endproc
|
|
||||||
|
|
||||||
.proc read_params
|
DEFINE_READ_PARAMS read_params, read_buffer, 0
|
||||||
params: .byte 4
|
|
||||||
ref_num:.byte 1
|
|
||||||
buffer: .word read_buffer
|
|
||||||
request:.word 0 ; This can be beyond $12FF - MARKER
|
|
||||||
trans: .word 0
|
|
||||||
.endproc
|
|
||||||
read_params_ref_num := read_params::ref_num
|
read_params_ref_num := read_params::ref_num
|
||||||
read_params_request := read_params::request
|
read_params_request := read_params::request_count
|
||||||
|
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
.assert read_params::request - selector <= install_size, error, "Must fit in $300 bytes"
|
|
||||||
|
|
||||||
.endproc
|
.endproc
|
||||||
|
.assert .sizeof(selector) <= install_size, error, "Must fit in $300 bytes"
|
||||||
|
poporg
|
||||||
|
|
||||||
|
;;; ************************************************************
|
||||||
|
.include "driver_postamble.inc"
|
||||||
|
;;; ************************************************************
|
||||||
|
3
driver_postamble.inc
Normal file
3
driver_postamble.inc
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
|
||||||
|
poporg
|
||||||
|
reloc_end := *
|
458
driver_preamble.inc
Normal file
458
driver_preamble.inc
Normal file
@ -0,0 +1,458 @@
|
|||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
;; SYS files load at $2000; relocates self to $1000
|
||||||
|
.org SYS_ADDR
|
||||||
|
dst_addr := $1000
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
jmp relocate
|
||||||
|
|
||||||
|
.byte MM, DD, YY ; version date stamp
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Relocate this code from $2000 (.SYSTEM start location) to $1000
|
||||||
|
;;; and start executing there. This is done so that the next .SYSTEM
|
||||||
|
;;; file can be loaded/run at $2000.
|
||||||
|
|
||||||
|
.proc relocate
|
||||||
|
src := reloc_start
|
||||||
|
dst := dst_addr
|
||||||
|
|
||||||
|
ldx #(reloc_end - reloc_start + $FF) / $100 ; pages
|
||||||
|
ldy #0
|
||||||
|
load: lda src,y ; self-modified
|
||||||
|
load_hi := *-1
|
||||||
|
sta dst,y ; self-modified
|
||||||
|
store_hi := *-1
|
||||||
|
iny
|
||||||
|
bne load
|
||||||
|
inc load_hi
|
||||||
|
inc store_hi
|
||||||
|
dex
|
||||||
|
bne load
|
||||||
|
|
||||||
|
jmp main
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Start of relocated code
|
||||||
|
|
||||||
|
reloc_start := *
|
||||||
|
pushorg dst_addr
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Main routine
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
.proc main
|
||||||
|
jsr save_chain_info
|
||||||
|
jsr init_system
|
||||||
|
jsr maybe_install_driver
|
||||||
|
jmp launch_next
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Preserve state needed to chain to next file
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
.proc save_chain_info
|
||||||
|
;; --------------------------------------------------
|
||||||
|
;; Save most recent device for later, when chaining
|
||||||
|
;; to next .SYSTEM file.
|
||||||
|
lda DEVNUM
|
||||||
|
sta devnum
|
||||||
|
|
||||||
|
;; --------------------------------------------------
|
||||||
|
;; Identify the name of this SYS file, which should be present at
|
||||||
|
;; $280 with or without a path prefix. Search pathname buffer
|
||||||
|
;; backwards for '/', then copy name into |self_name|.
|
||||||
|
|
||||||
|
;; Find '/' (which may not be present, prefix is optional)
|
||||||
|
ldx PATHNAME
|
||||||
|
beq no_name
|
||||||
|
ldy #0 ; Y = length
|
||||||
|
: lda PATHNAME,x
|
||||||
|
and #$7f ; ignore high bit
|
||||||
|
cmp #'/'
|
||||||
|
beq copy_name
|
||||||
|
iny
|
||||||
|
dex
|
||||||
|
bne :-
|
||||||
|
|
||||||
|
;; Copy name into |self_name| buffer
|
||||||
|
copy_name:
|
||||||
|
cpy #0
|
||||||
|
beq no_name
|
||||||
|
sty self_name
|
||||||
|
|
||||||
|
ldx PATHNAME
|
||||||
|
: lda PATHNAME,x
|
||||||
|
sta self_name,y
|
||||||
|
dex
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
|
||||||
|
;; Done
|
||||||
|
rts
|
||||||
|
|
||||||
|
no_name:
|
||||||
|
lda #0
|
||||||
|
sta self_name
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
devnum: .byte 0
|
||||||
|
self_name: .res 16
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Init system state
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
;;; Before installing, get the system to a known state.
|
||||||
|
|
||||||
|
.proc init_system
|
||||||
|
cld
|
||||||
|
bit ROMIN2
|
||||||
|
|
||||||
|
;; Update reset vector - ProDOS QUIT
|
||||||
|
lda #<quit
|
||||||
|
sta $03F2
|
||||||
|
lda #>quit
|
||||||
|
sta $03F3
|
||||||
|
eor #$A5
|
||||||
|
sta $03F4
|
||||||
|
|
||||||
|
;; Quit 80-column firmware
|
||||||
|
lda #$95 ; Ctrl+U (quit 80 col firmware)
|
||||||
|
jsr COUT
|
||||||
|
|
||||||
|
;; Reset I/O
|
||||||
|
sta CLR80VID
|
||||||
|
sta CLRALTCHAR
|
||||||
|
jsr SETVID
|
||||||
|
jsr SETKBD
|
||||||
|
jsr SETNORM
|
||||||
|
jsr INIT
|
||||||
|
jsr HOME
|
||||||
|
|
||||||
|
;; Update System Bit Map
|
||||||
|
ldx #BITMAP_SIZE-1
|
||||||
|
lda #%00000001 ; protect page $BF
|
||||||
|
: sta BITMAP,x
|
||||||
|
lda #%00000000 ; nothing else protected until...
|
||||||
|
dex
|
||||||
|
bne :-
|
||||||
|
lda #%11001111 ; ZP ($00), stack ($01), text page 1 ($04-$07)
|
||||||
|
sta BITMAP
|
||||||
|
|
||||||
|
;; Determine lowercase support
|
||||||
|
lda MACHID
|
||||||
|
and #$88 ; IIe or IIc (or IIgs) ?
|
||||||
|
bne :+
|
||||||
|
lda #$DF
|
||||||
|
sta lowercase_mask ; lower case to upper case
|
||||||
|
|
||||||
|
: rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Find and invoke the next .SYSTEM file
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
online_buf := $1C00
|
||||||
|
io_buf := $1C00
|
||||||
|
dir_buf := $2000
|
||||||
|
block_len = $200
|
||||||
|
|
||||||
|
DEFINE_ON_LINE_PARAMS on_line_params,,online_buf
|
||||||
|
DEFINE_OPEN_PARAMS open_params, PATHNAME, io_buf
|
||||||
|
DEFINE_READ_PARAMS read_params, SYS_ADDR, SYS_LEN
|
||||||
|
DEFINE_READ_PARAMS read_block_params, dir_buf, block_len
|
||||||
|
DEFINE_CLOSE_PARAMS close_params
|
||||||
|
|
||||||
|
|
||||||
|
.proc launch_next
|
||||||
|
;; Read directory and look for .SYSTEM files; find this
|
||||||
|
;; one, and invoke the following one.
|
||||||
|
|
||||||
|
ptr := $A5
|
||||||
|
num := $A7
|
||||||
|
len := $A8
|
||||||
|
|
||||||
|
;; --------------------------------------------------
|
||||||
|
;; Own name found? If not, just quit
|
||||||
|
lda self_name
|
||||||
|
bne :+
|
||||||
|
jmp quit
|
||||||
|
|
||||||
|
;; --------------------------------------------------
|
||||||
|
;; Find name of boot device, copy into PATHNAME
|
||||||
|
: lda devnum
|
||||||
|
sta on_line_params::unit_num
|
||||||
|
MLI_CALL ON_LINE, on_line_params
|
||||||
|
bcc :+
|
||||||
|
jmp on_error
|
||||||
|
|
||||||
|
: lda #'/' ; Prefix by '/'
|
||||||
|
sta PATHNAME+1
|
||||||
|
lda online_buf
|
||||||
|
and #$0F ; Mask off length
|
||||||
|
sta PATHNAME
|
||||||
|
ldx #0 ; Copy name
|
||||||
|
: lda online_buf+1,x
|
||||||
|
sta PATHNAME+2,x
|
||||||
|
inx
|
||||||
|
cpx PATHNAME
|
||||||
|
bne :-
|
||||||
|
inx ; One more for '/' prefix
|
||||||
|
stx PATHNAME
|
||||||
|
|
||||||
|
;; Open directory
|
||||||
|
MLI_CALL OPEN, open_params
|
||||||
|
bcc :+
|
||||||
|
jmp on_error
|
||||||
|
: lda open_params::ref_num
|
||||||
|
sta read_block_params::ref_num
|
||||||
|
sta close_params::ref_num
|
||||||
|
|
||||||
|
;; Read first "block"
|
||||||
|
MLI_CALL READ, read_block_params
|
||||||
|
bcc :+
|
||||||
|
jmp on_error
|
||||||
|
|
||||||
|
;; Get sizes out of header
|
||||||
|
: lda dir_buf + VolumeDirectoryHeader::entry_length
|
||||||
|
sta entry_length_mod
|
||||||
|
lda dir_buf + VolumeDirectoryHeader::entries_per_block
|
||||||
|
sta entries_per_block_mod
|
||||||
|
lda #1
|
||||||
|
sta num
|
||||||
|
|
||||||
|
;; Set up pointers to entry
|
||||||
|
lda #<(dir_buf + .sizeof(VolumeDirectoryHeader))
|
||||||
|
sta ptr
|
||||||
|
lda #>(dir_buf + .sizeof(VolumeDirectoryHeader))
|
||||||
|
sta ptr+1
|
||||||
|
|
||||||
|
;; Process directory entry
|
||||||
|
entry: ldy #FileEntry::file_type ; file_type
|
||||||
|
lda (ptr),y
|
||||||
|
cmp #$FF ; type=SYS
|
||||||
|
bne next
|
||||||
|
ldy #FileEntry::storage_type_name_length
|
||||||
|
lda (ptr),y
|
||||||
|
and #$30 ; regular file (not directory, pascal)
|
||||||
|
beq next
|
||||||
|
lda (ptr),y
|
||||||
|
and #$0F ; name_length
|
||||||
|
sta len
|
||||||
|
tay
|
||||||
|
|
||||||
|
;; Compare suffix - is it .SYSTEM?
|
||||||
|
ldx suffix
|
||||||
|
: lda (ptr),y
|
||||||
|
cmp suffix,x
|
||||||
|
bne next
|
||||||
|
dey
|
||||||
|
dex
|
||||||
|
bne :-
|
||||||
|
|
||||||
|
;; Yes; is it *this* .SYSTEM file?
|
||||||
|
ldy self_name
|
||||||
|
cpy len
|
||||||
|
bne handle_sys_file
|
||||||
|
: lda (ptr),y
|
||||||
|
cmp self_name,y
|
||||||
|
bne handle_sys_file
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
sec
|
||||||
|
ror found_self_flag
|
||||||
|
|
||||||
|
;; Move to the next entry
|
||||||
|
next: lda ptr
|
||||||
|
clc
|
||||||
|
adc #$27 ; self-modified: entry_length
|
||||||
|
entry_length_mod := *-1
|
||||||
|
sta ptr
|
||||||
|
bcc :+
|
||||||
|
inc ptr+1
|
||||||
|
: inc num
|
||||||
|
lda num
|
||||||
|
cmp #$0D ; self-modified: entries_per_block
|
||||||
|
entries_per_block_mod := *-1
|
||||||
|
bcc entry
|
||||||
|
|
||||||
|
;; Read next "block"
|
||||||
|
MLI_CALL READ, read_block_params
|
||||||
|
bcs not_found
|
||||||
|
|
||||||
|
;; Set up pointers to entry
|
||||||
|
lda #0
|
||||||
|
sta num
|
||||||
|
lda #<(dir_buf + $04)
|
||||||
|
sta ptr
|
||||||
|
lda #>(dir_buf + $04)
|
||||||
|
sta ptr+1
|
||||||
|
jmp entry
|
||||||
|
|
||||||
|
;; --------------------------------------------------
|
||||||
|
;; Found a .SYSTEM file which is not this one; invoke
|
||||||
|
;; it if follows this one.
|
||||||
|
handle_sys_file:
|
||||||
|
bit found_self_flag
|
||||||
|
bpl next
|
||||||
|
|
||||||
|
MLI_CALL CLOSE, close_params
|
||||||
|
|
||||||
|
;; Compose the path to invoke.
|
||||||
|
ldx PATHNAME
|
||||||
|
inx
|
||||||
|
lda #'/'
|
||||||
|
sta PATHNAME,x
|
||||||
|
ldy #0
|
||||||
|
: iny
|
||||||
|
inx
|
||||||
|
lda (ptr),y
|
||||||
|
sta PATHNAME,x
|
||||||
|
cpy len
|
||||||
|
bcc :-
|
||||||
|
stx PATHNAME
|
||||||
|
|
||||||
|
jmp invoke_system_file
|
||||||
|
|
||||||
|
not_found:
|
||||||
|
jsr zstrout
|
||||||
|
scrcode "\r\r* Unable to find next '.SYSTEM' file *\r"
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
bit KBDSTRB
|
||||||
|
: lda KBD
|
||||||
|
bpl :-
|
||||||
|
bit KBDSTRB
|
||||||
|
jmp quit
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Load/execute the system file in PATHNAME
|
||||||
|
|
||||||
|
.proc invoke_system_file
|
||||||
|
MLI_CALL OPEN, open_params
|
||||||
|
bcs on_error
|
||||||
|
|
||||||
|
lda open_params::ref_num
|
||||||
|
sta read_params::ref_num
|
||||||
|
sta close_params::ref_num
|
||||||
|
|
||||||
|
MLI_CALL READ, read_params
|
||||||
|
bcs on_error
|
||||||
|
|
||||||
|
MLI_CALL CLOSE, close_params
|
||||||
|
bcs on_error
|
||||||
|
|
||||||
|
jmp SYS_ADDR ; Invoke loaded SYSTEM file
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Error handler - invoked if any ProDOS error occurs.
|
||||||
|
|
||||||
|
.proc on_error
|
||||||
|
pha
|
||||||
|
jsr zstrout
|
||||||
|
scrcode "\r\r* Disk Error $"
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
pla
|
||||||
|
jsr PRBYTE
|
||||||
|
|
||||||
|
jsr zstrout
|
||||||
|
scrcode " *\r"
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
bit KBDSTRB
|
||||||
|
: lda KBD
|
||||||
|
bpl :-
|
||||||
|
bit KBDSTRB
|
||||||
|
jmp quit
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
.proc quit
|
||||||
|
MLI_CALL QUIT, quit_params
|
||||||
|
brk ; crash if QUIT fails
|
||||||
|
|
||||||
|
DEFINE_QUIT_PARAMS quit_params
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Data
|
||||||
|
|
||||||
|
suffix:
|
||||||
|
PASCAL_STRING ".SYSTEM"
|
||||||
|
|
||||||
|
found_self_flag:
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Common Routines
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Output a high-ascii, null-terminated string.
|
||||||
|
;;; String immediately follows the JSR.
|
||||||
|
|
||||||
|
.proc zstrout
|
||||||
|
ptr := $A5
|
||||||
|
|
||||||
|
pla ; read address from stack
|
||||||
|
sta ptr
|
||||||
|
pla
|
||||||
|
sta ptr+1
|
||||||
|
bne skip ; always (since data not on ZP)
|
||||||
|
|
||||||
|
next: cmp #HI('a') ; lower-case?
|
||||||
|
bcc :+
|
||||||
|
and lowercase_mask ; make upper-case if needed
|
||||||
|
: jsr COUT
|
||||||
|
skip: inc ptr
|
||||||
|
bne :+
|
||||||
|
inc ptr+1
|
||||||
|
: ldy #0
|
||||||
|
lda (ptr),y
|
||||||
|
bne next
|
||||||
|
|
||||||
|
lda ptr+1 ; restore address to stack
|
||||||
|
pha
|
||||||
|
lda ptr
|
||||||
|
pha
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
lowercase_mask:
|
||||||
|
.byte $FF ; Set to $DF on systems w/o lower-case
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; COUT a 2-digit number in A
|
||||||
|
|
||||||
|
.proc cout_number
|
||||||
|
ldx #HI('0')
|
||||||
|
cmp #10 ; >= 10?
|
||||||
|
bcc tens
|
||||||
|
|
||||||
|
;; divide by 10, dividend(+'0') in x remainder in a
|
||||||
|
: sbc #10
|
||||||
|
inx
|
||||||
|
cmp #10
|
||||||
|
bcs :-
|
||||||
|
|
||||||
|
tens: pha
|
||||||
|
cpx #HI('0')
|
||||||
|
beq units
|
||||||
|
txa
|
||||||
|
jsr COUT
|
||||||
|
|
||||||
|
units: pla
|
||||||
|
ora #HI('0')
|
||||||
|
jsr COUT
|
||||||
|
rts
|
||||||
|
.endproc
|
54
inc/apple2.inc
Normal file
54
inc/apple2.inc
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
;;; ============================================================
|
||||||
|
;;;
|
||||||
|
;;; More Apple II Symbols
|
||||||
|
;;;
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Soft Switches
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
RAMRDOFF := $C002
|
||||||
|
RAMRDON := $C003
|
||||||
|
RAMWRTOFF := $C004
|
||||||
|
RAMWRTON := $C005
|
||||||
|
ALTZPOFF := $C008
|
||||||
|
ALTZPON := $C009
|
||||||
|
|
||||||
|
CLR80VID := $C00C
|
||||||
|
SET80VID := $C00D
|
||||||
|
RDALTZP := $C016
|
||||||
|
RD80STORE := $C018
|
||||||
|
RDPAGE2 := $C01C
|
||||||
|
|
||||||
|
BANKSEL := $C073 ; Select RamWorks bank
|
||||||
|
|
||||||
|
ROMIN2 := $C082 ; Read ROM; no write
|
||||||
|
RWRAM1 := $C08B ; Read/write RAM bank 1
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; I/O Registers (for Slot 2)
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
TDREG := $C088 + $20 ; ACIA Transmit Register (write)
|
||||||
|
RDREG := $C088 + $20 ; ACIA Receive Register (read)
|
||||||
|
STATUS := $C089 + $20 ; ACIA Status/Reset Register
|
||||||
|
COMMAND := $C08A + $20 ; ACIA Command Register (read/write)
|
||||||
|
CONTROL := $C08B + $20 ; ACIA Control Register (read/write)
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Monitor ROM routines
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
INIT := $FB2F
|
||||||
|
HOME := $FC58
|
||||||
|
GETLN := $FD6A ; with prompt character
|
||||||
|
GETLN2 := $FD6F ; no prompt character
|
||||||
|
CROUT := $FD8E
|
||||||
|
PRBYTE := $FDDA
|
||||||
|
COUT := $FDED
|
||||||
|
SETNORM := $FE84
|
||||||
|
SETKBD := $FE89
|
||||||
|
SETVID := $FE93
|
||||||
|
|
||||||
|
INPUT_BUFFER := $200
|
123
inc/macros.inc
Normal file
123
inc/macros.inc
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
;;; ============================================================
|
||||||
|
;;; Generic Macros
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
.define _is_immediate(arg) (.match (.mid (0, 1, {arg}), #))
|
||||||
|
.define _is_register(arg) (.match ({arg}, x) .or .match ({arg}, y))
|
||||||
|
.define _is_y_register(arg) (.match ({arg}, y))
|
||||||
|
.define _immediate_value(arg) (.right (.tcount ({arg})-1, {arg}))
|
||||||
|
|
||||||
|
.macro _op_lo op, arg
|
||||||
|
.if _is_immediate {arg}
|
||||||
|
op #<_immediate_value {arg}
|
||||||
|
.else
|
||||||
|
op arg
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro _op_hi op, arg
|
||||||
|
.if _is_immediate {arg}
|
||||||
|
op #>_immediate_value {arg}
|
||||||
|
.else
|
||||||
|
op arg+1
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Temporary org change, for relocated routines
|
||||||
|
|
||||||
|
__pushorg_depth__ .set 0
|
||||||
|
|
||||||
|
.macro pushorg addr
|
||||||
|
::__pushorg_depth__ .set ::__pushorg_depth__ + 1
|
||||||
|
.ident(.sprintf("__pushorg_saved__%d", ::__pushorg_depth__)) := *
|
||||||
|
.org addr
|
||||||
|
.ident(.sprintf("__pushorg_start__%d", ::__pushorg_depth__)) := *
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro poporg
|
||||||
|
.org .ident(.sprintf("__pushorg_saved__%d", ::__pushorg_depth__)) + (* - .ident(.sprintf("__pushorg_start__%d", ::__pushorg_depth__)))
|
||||||
|
::__pushorg_depth__ .set ::__pushorg_depth__ - 1
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Length-prefixed string
|
||||||
|
;;;
|
||||||
|
;;; Can include control chars by using:
|
||||||
|
;;;
|
||||||
|
;;; PASCAL_STRING {"abc",$0D,"def"}
|
||||||
|
|
||||||
|
.macro PASCAL_STRING str,res
|
||||||
|
.local data
|
||||||
|
.local end
|
||||||
|
.byte end - data
|
||||||
|
data: .byte str
|
||||||
|
end:
|
||||||
|
.if .paramcount > 1
|
||||||
|
.res res - (end - data), 0
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Common patterns
|
||||||
|
|
||||||
|
.macro copy arg1, arg2, arg3, arg4
|
||||||
|
.if _is_register {arg2} && _is_register {arg4}
|
||||||
|
;; indexed load/indexed store
|
||||||
|
lda arg1,arg2
|
||||||
|
sta arg3,arg4
|
||||||
|
.elseif _is_register {arg2}
|
||||||
|
;; indexed load variant (arg2 is x or y)
|
||||||
|
lda arg1,arg2
|
||||||
|
sta arg3
|
||||||
|
.elseif _is_register {arg3}
|
||||||
|
;; indexed store variant (arg3 is x or y)
|
||||||
|
lda arg1
|
||||||
|
sta arg2,arg3
|
||||||
|
.else
|
||||||
|
lda arg1
|
||||||
|
sta arg2
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
;;; Copy 16-bit value
|
||||||
|
;;; copy16 #$1111, $2222 ; immediate, absolute
|
||||||
|
;;; copy16 $1111, $2222 ; absolute, absolute
|
||||||
|
;;; copy16 $1111,x, $2222 ; indirect load, absolute store
|
||||||
|
;;; copy16 $1111, $2222,x ; absolute load, indirect store
|
||||||
|
;;; copy16 $1111,x $2222,x ; indirect load, indirect store
|
||||||
|
;;; copy16 #$1111, $2222,x ; immediate load, indirect store
|
||||||
|
.macro copy16 arg1, arg2, arg3, arg4
|
||||||
|
.if _is_register {arg2} && _is_register {arg4}
|
||||||
|
;; indexed load/indexed store
|
||||||
|
lda arg1,arg2
|
||||||
|
sta arg3,arg4
|
||||||
|
lda arg1+1,arg2
|
||||||
|
sta arg3+1,arg4
|
||||||
|
.elseif _is_register {arg2}
|
||||||
|
;; indexed load variant (arg2 is x or y)
|
||||||
|
lda arg1,arg2
|
||||||
|
sta arg3
|
||||||
|
lda arg1+1,arg2
|
||||||
|
sta arg3+1
|
||||||
|
.elseif _is_register {arg3}
|
||||||
|
;; indexed store variant (arg3 is x or y)
|
||||||
|
_op_lo lda, {arg1}
|
||||||
|
sta arg2,arg3
|
||||||
|
_op_hi lda, {arg1}
|
||||||
|
sta arg2+1,arg3
|
||||||
|
.else
|
||||||
|
_op_lo lda, {arg1}
|
||||||
|
sta arg2
|
||||||
|
_op_hi lda, {arg1}
|
||||||
|
sta arg2+1
|
||||||
|
.endif
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
;;; Set the high bit on the passed byte
|
||||||
|
.define HI(c) ((c)|$80)
|
477
inc/prodos.inc
Normal file
477
inc/prodos.inc
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
;;; ============================================================
|
||||||
|
;;;
|
||||||
|
;;; ProDOS MLI
|
||||||
|
;;;
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
;;; Entry point / Global Page
|
||||||
|
MLI := $BF00 ; Entry point
|
||||||
|
DATETIME := $BF06 ; JMP to clock routine
|
||||||
|
DEVADR := $BF10 ; Device driver addresses ($BF10-$BF2F)
|
||||||
|
NODEV := $BF10 ; "No Device Connected" entry (slot 0)
|
||||||
|
DEVNUM := $BF30 ; Most recent accessed device
|
||||||
|
DEVCNT := $BF31 ; Number of on-line devices minus 1
|
||||||
|
DEVLST := $BF32 ; Up to 14 units ($BF32-$BF3F)
|
||||||
|
BITMAP := $BF58 ; System memory bitmap
|
||||||
|
BITMAP_SIZE = $18 ; Bits for pages $00 to $BF
|
||||||
|
DATELO := $BF90 ; Date lo
|
||||||
|
DATEHI := $BF91 ; Date hi
|
||||||
|
TIMELO := $BF92 ; Time lo
|
||||||
|
TIMEHI := $BF93 ; Time hi
|
||||||
|
LEVEL := $BF94 ; File level
|
||||||
|
MACHID := $BF98 ; Machine ID
|
||||||
|
SLTBYT := $BF99 ; '1' bits indicate rom in slot (bit#)
|
||||||
|
IVERSION := $BFFD ; Interpreter Version
|
||||||
|
KVERSION := $BFFF ; ProDOS Kernel Version
|
||||||
|
|
||||||
|
;;; Patch Locations
|
||||||
|
SELECTOR := $D100
|
||||||
|
|
||||||
|
BLOCK_SIZE = $200
|
||||||
|
|
||||||
|
PATHNAME := $280
|
||||||
|
SYS_ADDR := $2000 ; Load address for SYS files
|
||||||
|
SYS_LEN = $BF00 - SYS_ADDR ; Maximum SYS file length
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; MLI Calls
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
;;; Housekeeping Calls
|
||||||
|
CREATE = $C0
|
||||||
|
DESTROY = $C1
|
||||||
|
RENAME = $C2
|
||||||
|
SET_FILE_INFO = $C3
|
||||||
|
GET_FILE_INFO = $C4
|
||||||
|
ON_LINE = $C5
|
||||||
|
SET_PREFIX = $C6
|
||||||
|
GET_PREFIX = $C7
|
||||||
|
|
||||||
|
;;; Filing Calls
|
||||||
|
OPEN = $C8
|
||||||
|
NEWLINE = $C9
|
||||||
|
READ = $CA
|
||||||
|
WRITE = $CB
|
||||||
|
CLOSE = $CC
|
||||||
|
FLUSH = $CD
|
||||||
|
SET_MARK = $CE
|
||||||
|
GET_MARK = $CF
|
||||||
|
SET_EOF = $D0
|
||||||
|
GET_EOF = $D1
|
||||||
|
SET_BUF = $D2
|
||||||
|
GET_BUF = $D3
|
||||||
|
|
||||||
|
;;; System Calls
|
||||||
|
GET_TIME = $82
|
||||||
|
ALLOC_INTERRUPT = $40
|
||||||
|
DEALLOC_INTERRUPT = $41
|
||||||
|
QUIT = $65
|
||||||
|
|
||||||
|
;;; Direct Disk Access Commands
|
||||||
|
READ_BLOCK = $80
|
||||||
|
WRITE_BLOCK = $81
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; File Types
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
FT_TYPELESS = $00
|
||||||
|
FT_BAD = $01
|
||||||
|
FT_TEXT = $04 ; ASCII Text File *
|
||||||
|
FT_BINARY = $06 ; Generic Binary File *
|
||||||
|
FT_GRAPHICS = $08 ; Graphics File
|
||||||
|
FT_DIRECTORY = $0F ; Directory *
|
||||||
|
FT_ADB = $19 ; AppleWorks Database *
|
||||||
|
FT_AWP = $1A ; AppleWorks Word Processing *
|
||||||
|
FT_ASP = $1B ; AppleWorks Spreadsheet *
|
||||||
|
FT_SRC = $B0 ; IIgs system type; re-used?
|
||||||
|
FT_S16 = $B3 ; IIgs Application Program
|
||||||
|
FT_PAS = $EF ; Pascal Area *
|
||||||
|
FT_CMD = $F0 ; ProDOS Command File *
|
||||||
|
FT_INT = $FA ; Integer BASIC Program *
|
||||||
|
FT_IVR = $FB ; Integer BASIC Variable File *
|
||||||
|
FT_BASIC = $FC ; Applesoft BASIC Program *
|
||||||
|
FT_VAR = $FD ; Applesoft BASIC Variable File *
|
||||||
|
FT_REL = $FE ; EDASM/Contiki Relocatable File *
|
||||||
|
FT_SYSTEM = $FF ; ProDOS System File *
|
||||||
|
|
||||||
|
;;; Types marked with * are known to BASIC.SYSTEM and have an
|
||||||
|
;;; associated three-letter abbreviation.
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Access
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
ACCESS_DEFAULT = %11000011
|
||||||
|
ACCESS_LOCKED = %00100001
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Storage Types
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
ST_STANDARD_FILE = $01
|
||||||
|
ST_LINKED_DIRECTORY = $0D
|
||||||
|
ST_VOLUME_DIRECTORY = $0F
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Errors
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
ERR_DEVICE_NOT_CONNECTED = $28
|
||||||
|
ERR_WRITE_PROTECTED = $2B
|
||||||
|
ERR_INVALID_PATHNAME = $40
|
||||||
|
ERR_INVALID_REFERENCE = $43
|
||||||
|
ERR_PATH_NOT_FOUND = $44
|
||||||
|
ERR_VOL_NOT_FOUND = $45
|
||||||
|
ERR_FILE_NOT_FOUND = $46
|
||||||
|
ERR_DUPLICATE_FILENAME= $47
|
||||||
|
ERR_OVERRUN_ERROR = $48
|
||||||
|
ERR_VOLUME_DIR_FULL = $49
|
||||||
|
ERR_END_OF_FILE = $4C
|
||||||
|
ERR_ACCESS_ERROR = $4E
|
||||||
|
ERR_DUPLICATE_VOLUME = $57
|
||||||
|
ERR_NETWORK_ERROR = $88
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Directory Structures
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
STORAGE_TYPE_MASK = $F0
|
||||||
|
NAME_LENGTH_MASK = $0F
|
||||||
|
|
||||||
|
;;; Volume Directory Header structure
|
||||||
|
.struct VolumeDirectoryHeader
|
||||||
|
prev_block .word
|
||||||
|
next_block .word
|
||||||
|
storage_type_name_length .byte
|
||||||
|
file_name .byte 15
|
||||||
|
reserved .byte 8
|
||||||
|
creation_date .word
|
||||||
|
creation_time .word
|
||||||
|
version .byte
|
||||||
|
min_version .byte
|
||||||
|
access .byte
|
||||||
|
entry_length .byte
|
||||||
|
entries_per_block .byte
|
||||||
|
file_count .word
|
||||||
|
;; same through here ---------
|
||||||
|
bit_map_pointer .word
|
||||||
|
total_blocks .word
|
||||||
|
.endstruct
|
||||||
|
.assert .sizeof(VolumeDirectoryHeader) = $2B, error, "incorrect struct size"
|
||||||
|
|
||||||
|
;;; Subdirectory Header structure
|
||||||
|
.struct SubdirectoryHeader
|
||||||
|
prev_block .word
|
||||||
|
next_block .word
|
||||||
|
storage_type_name_length .byte
|
||||||
|
file_name .byte 15
|
||||||
|
reserved .byte 8
|
||||||
|
creation_date .word
|
||||||
|
creation_time .word
|
||||||
|
version .byte
|
||||||
|
min_version .byte
|
||||||
|
access .byte
|
||||||
|
entry_length .byte
|
||||||
|
entries_per_block .byte
|
||||||
|
file_count .word
|
||||||
|
;; same through here ---------
|
||||||
|
parent_pointer .word
|
||||||
|
parent_entry_number .byte
|
||||||
|
parent_entry_length .byte
|
||||||
|
.endstruct
|
||||||
|
.assert .sizeof(SubdirectoryHeader) = $2B, error, "incorrect struct size"
|
||||||
|
|
||||||
|
;; File Entry structure
|
||||||
|
.struct FileEntry
|
||||||
|
storage_type_name_length .byte
|
||||||
|
file_name .byte 15
|
||||||
|
file_type .byte
|
||||||
|
key_pointer .word
|
||||||
|
blocks_used .word
|
||||||
|
eof .faraddr
|
||||||
|
creation_date .word
|
||||||
|
creation_time .word
|
||||||
|
version .byte
|
||||||
|
min_version .byte
|
||||||
|
access .byte
|
||||||
|
aux_type .word
|
||||||
|
mod_date .word
|
||||||
|
mod_time .word
|
||||||
|
header_pointer .word
|
||||||
|
.endstruct
|
||||||
|
.assert .sizeof(FileEntry) = $27, error, "incorrect struct size"
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; ProDOS Driver Protocol
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
;;; Addresses for command parameters
|
||||||
|
DRIVER_COMMAND := $42
|
||||||
|
DRIVER_UNIT_NUMBER := $43
|
||||||
|
DRIVER_BUFFER := $44
|
||||||
|
DRIVER_BLOCK_NUMBER := $46
|
||||||
|
|
||||||
|
;;; Commands
|
||||||
|
DRIVER_COMMAND_STATUS = 0
|
||||||
|
DRIVER_COMMAND_READ = 1
|
||||||
|
DRIVER_COMMAND_WRITE = 2
|
||||||
|
DRIVER_COMMAND_FORMAT = 3
|
||||||
|
|
||||||
|
|
||||||
|
;;; ============================================================
|
||||||
|
;;; Macros
|
||||||
|
;;; ============================================================
|
||||||
|
|
||||||
|
.macro MLI_CALL op, addr
|
||||||
|
jsr MLI
|
||||||
|
.byte op
|
||||||
|
.addr addr
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_OPEN_PARAMS name, pn, io, rn
|
||||||
|
.if .xmatch(.string(pn), "pathname")
|
||||||
|
;; If 'pathname' is passed then expansion yields a circular reference.
|
||||||
|
.error "Can't pass 'pathname' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.if .xmatch(.string(io), "io_buffer")
|
||||||
|
.error "Can't pass 'io_buffer' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 3
|
||||||
|
pathname: .addr pn
|
||||||
|
io_buffer: .addr io
|
||||||
|
.ifnblank rn
|
||||||
|
ref_num: .byte rn
|
||||||
|
.else
|
||||||
|
ref_num: .byte 0
|
||||||
|
.endif
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_READ_PARAMS name, db, rc
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 4
|
||||||
|
ref_num: .byte 0
|
||||||
|
data_buffer: .addr db
|
||||||
|
request_count: .word rc
|
||||||
|
trans_count: .word 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_WRITE_PARAMS name, db, rc
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 4
|
||||||
|
ref_num: .byte 0
|
||||||
|
data_buffer: .addr db
|
||||||
|
request_count: .word rc
|
||||||
|
trans_count: .word 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_CLOSE_PARAMS name
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 1
|
||||||
|
ref_num: .byte 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_FLUSH_PARAMS name
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 1
|
||||||
|
ref_num: .byte 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_GET_FILE_INFO_PARAMS name, pn
|
||||||
|
.if .xmatch(.string(pn), "pathname")
|
||||||
|
;; If 'pathname' is passed then expansion yields a circular reference.
|
||||||
|
.error "Can't pass 'pathname' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.proc name
|
||||||
|
param_count: .byte $A
|
||||||
|
pathname: .addr pn
|
||||||
|
access: .byte 0
|
||||||
|
file_type: .byte 0
|
||||||
|
aux_type: .word 0
|
||||||
|
storage_type: .byte 0
|
||||||
|
blocks_used: .word 0
|
||||||
|
mod_date: .word 0
|
||||||
|
mod_time: .word 0
|
||||||
|
create_date: .word 0
|
||||||
|
create_time: .word 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_SET_MARK_PARAMS name, pos
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 2
|
||||||
|
ref_num: .byte 0
|
||||||
|
position: .faraddr pos
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_ON_LINE_PARAMS name, un, db
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 2
|
||||||
|
|
||||||
|
.ifnblank un
|
||||||
|
unit_num: .byte un
|
||||||
|
.else
|
||||||
|
unit_num: .byte 0
|
||||||
|
.endif
|
||||||
|
|
||||||
|
data_buffer: .addr db
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_READ_BLOCK_PARAMS name, db, bn
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 3
|
||||||
|
unit_num: .byte 0
|
||||||
|
data_buffer: .addr db
|
||||||
|
block_num: .word bn
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
|
||||||
|
.macro DEFINE_WRITE_BLOCK_PARAMS name, db, bn
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 3
|
||||||
|
unit_num: .byte 0
|
||||||
|
data_buffer: .addr db
|
||||||
|
block_num: .word bn
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_ALLOC_INTERRUPT_PARAMS name, ic
|
||||||
|
.proc alloc_interrupt_params
|
||||||
|
param_count: .byte 2
|
||||||
|
int_num: .byte 0
|
||||||
|
int_code: .addr ic
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_DEALLOC_INTERRUPT_PARAMS name
|
||||||
|
.proc dealloc_interrupt_params
|
||||||
|
param_count: .byte 1
|
||||||
|
int_num: .byte 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_QUIT_PARAMS name, ext, pathname
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 4
|
||||||
|
.ifnblank ext
|
||||||
|
.byte ext
|
||||||
|
.else
|
||||||
|
.byte 0
|
||||||
|
.endif
|
||||||
|
.ifnblank pathname
|
||||||
|
.word pathname
|
||||||
|
.else
|
||||||
|
.word 0
|
||||||
|
.endif
|
||||||
|
.byte 0
|
||||||
|
.word 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_SET_PREFIX_PARAMS name, pn
|
||||||
|
.if .xmatch(.string(pn), "pathname")
|
||||||
|
;; If 'pathname' is passed then expansion yields a circular reference.
|
||||||
|
.error "Can't pass 'pathname' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 1
|
||||||
|
pathname: .addr pn
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_GET_PREFIX_PARAMS name, pn
|
||||||
|
.if .xmatch(.string(pn), "pathname")
|
||||||
|
;; If 'pathname' is passed then expansion yields a circular reference.
|
||||||
|
.error "Can't pass 'pathname' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 1
|
||||||
|
pathname: .addr pn
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_DESTROY_PARAMS name, pn
|
||||||
|
.if .xmatch(.string(pn), "pathname")
|
||||||
|
;; If 'pathname' is passed then expansion yields a circular reference.
|
||||||
|
.error "Can't pass 'pathname' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 1
|
||||||
|
pathname: .addr pn
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_CREATE_PARAMS name, pn, ac, ft, at, st
|
||||||
|
.if .xmatch(.string(pn), "pathname")
|
||||||
|
;; If 'pathname' is passed then expansion yields a circular reference.
|
||||||
|
.error "Can't pass 'pathname' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 7
|
||||||
|
pathname: .addr pn
|
||||||
|
|
||||||
|
.ifnblank ac
|
||||||
|
access: .byte ac
|
||||||
|
.else
|
||||||
|
access: .byte 0
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.ifnblank ft
|
||||||
|
file_type: .byte ft
|
||||||
|
.else
|
||||||
|
file_type: .byte 0
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.ifnblank at
|
||||||
|
aux_type: .word at
|
||||||
|
.else
|
||||||
|
aux_type: .word 0
|
||||||
|
.endif
|
||||||
|
|
||||||
|
.ifnblank st
|
||||||
|
storage_type: .byte st
|
||||||
|
.else
|
||||||
|
storage_type: .byte 0
|
||||||
|
.endif
|
||||||
|
|
||||||
|
create_date: .word 0
|
||||||
|
create_time: .word 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_SET_EOF_PARAMS name, eo
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 2
|
||||||
|
ref_num: .byte 0
|
||||||
|
eof: .faraddr eo
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_GET_EOF_PARAMS name
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 2
|
||||||
|
ref_num: .byte 0
|
||||||
|
eof: .faraddr 0
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
.macro DEFINE_RENAME_PARAMS name, pn, np
|
||||||
|
.if .xmatch(.string(pn), "pathname")
|
||||||
|
;; If 'pathname' is passed then expansion yields a circular reference.
|
||||||
|
.error "Can't pass 'pathname' label to DEFINE_*_PARAMS"
|
||||||
|
.endif
|
||||||
|
.proc name
|
||||||
|
param_count: .byte 2
|
||||||
|
pathname: .addr pn
|
||||||
|
new_pathname: .addr np
|
||||||
|
.endproc
|
||||||
|
.endmacro
|
Loading…
Reference in New Issue
Block a user