2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
|
|
|
;;;
|
2017-08-29 15:07:02 +00:00
|
|
|
;;; ProDOS MLI
|
2018-02-27 04:13:18 +00:00
|
|
|
;;;
|
|
|
|
;;; ============================================================
|
2017-08-29 15:07:02 +00:00
|
|
|
|
2018-01-05 07:23:06 +00:00
|
|
|
;;; Entry point / Global Page
|
2018-01-06 05:03:10 +00:00
|
|
|
MLI := $BF00 ; Entry point
|
|
|
|
DEVNUM := $BF30 ; Most recent accessed device
|
|
|
|
DEVCNT := $BF31 ; Number of on-line devices minus 1
|
|
|
|
DEVLST := $BF32 ; Up to 14 units
|
|
|
|
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
|
2018-03-04 05:33:40 +00:00
|
|
|
LEVEL := $BF94 ; File level
|
2018-01-06 05:03:10 +00:00
|
|
|
MACHID := $BF98 ; Machine ID
|
2018-04-06 04:29:25 +00:00
|
|
|
SLTBYT := $BF99 ; '1' bits indicate rom in slot (bit#)
|
2018-04-04 04:26:13 +00:00
|
|
|
IVERSION := $BFFD ; Interpreter Version
|
|
|
|
KVERSION := $BFFF ; ProDOS Kernel Version
|
2017-09-13 15:09:33 +00:00
|
|
|
|
2018-01-05 17:42:32 +00:00
|
|
|
;;; Patch Locations
|
|
|
|
SELECTOR := $D100
|
|
|
|
|
2018-03-07 16:12:30 +00:00
|
|
|
BLOCK_SIZE := $200
|
|
|
|
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-06 05:03:10 +00:00
|
|
|
;;; MLI Calls
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-06 05:03:10 +00:00
|
|
|
|
2017-08-29 15:07:02 +00:00
|
|
|
;;; 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
|
2018-01-06 05:03:10 +00:00
|
|
|
|
2017-08-29 15:07:02 +00:00
|
|
|
;;; 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
|
2018-01-06 05:03:10 +00:00
|
|
|
|
2017-08-29 15:07:02 +00:00
|
|
|
;;; System Calls
|
|
|
|
GET_TIME := $82
|
|
|
|
ALLOC_INTERRUPT := $40
|
|
|
|
DEALLOC_INTERRUPT := $41
|
2018-01-06 05:03:10 +00:00
|
|
|
QUIT := $65
|
|
|
|
|
2017-08-29 15:07:02 +00:00
|
|
|
;;; Direct Disk Access Commands
|
|
|
|
READ_BLOCK := $80
|
2018-01-17 04:16:31 +00:00
|
|
|
WRITE_BLOCK := $81
|
2017-08-29 15:07:02 +00:00
|
|
|
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-18 17:32:25 +00:00
|
|
|
;;; Device Types (low nibble of unit number in DEVLST)
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-06 05:03:10 +00:00
|
|
|
|
|
|
|
DT_DISKII := $0
|
|
|
|
DT_PROFILE := $4
|
|
|
|
DT_RAM := $F
|
|
|
|
|
2018-01-18 17:32:25 +00:00
|
|
|
;;; See ProDOS Tech Note #21 - other than the above types, there
|
|
|
|
;;; is not an "ID nibble". The nibble is a copy of $CnFE's high
|
|
|
|
;;; nibble, with this meaning:
|
|
|
|
;;; bit 3 = removable
|
|
|
|
;;; bit 2 = interruptable
|
|
|
|
;;; bit 1-0 = number of volumes (0-1)
|
|
|
|
;;; "You should ignore the low nibble in the unit number..."
|
|
|
|
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2017-09-28 15:45:05 +00:00
|
|
|
;;; File Types
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-06 05:03:10 +00:00
|
|
|
|
2017-09-28 15:45:05 +00:00
|
|
|
FT_TYPELESS := $00
|
|
|
|
FT_BAD := $01
|
|
|
|
FT_TEXT := $04
|
|
|
|
FT_BINARY := $06
|
|
|
|
FT_DIRECTORY := $0F
|
2018-01-05 19:16:47 +00:00
|
|
|
FT_SRC := $B0 ; IIgs system type; re-used?
|
|
|
|
FT_S16 := $B3 ; IIgs Application Program
|
2017-09-28 15:45:05 +00:00
|
|
|
FT_BASIC := $FC
|
|
|
|
FT_SYSTEM := $FF
|
|
|
|
|
2018-03-06 05:27:41 +00:00
|
|
|
;;; ============================================================
|
|
|
|
;;; Access
|
|
|
|
;;; ============================================================
|
|
|
|
|
|
|
|
ACCESS_DEFAULT := %11000011
|
|
|
|
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-20 03:41:20 +00:00
|
|
|
;;; Storage Types
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-20 03:41:20 +00:00
|
|
|
|
|
|
|
ST_STANDARD_FILE := $01
|
|
|
|
ST_LINKED_DIRECTORY := $0D
|
|
|
|
ST_VOLUME_DIRECTORY := $0F
|
|
|
|
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-02-13 05:14:23 +00:00
|
|
|
;;; Errors
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-02-13 05:14:23 +00:00
|
|
|
|
2018-03-06 05:20:00 +00:00
|
|
|
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
|
2018-02-13 05:14:23 +00:00
|
|
|
|
2018-04-21 04:58:15 +00:00
|
|
|
;;; ============================================================
|
|
|
|
;;; 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"
|
|
|
|
|
|
|
|
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2017-08-29 15:07:02 +00:00
|
|
|
;;; Macros
|
2018-02-27 04:13:18 +00:00
|
|
|
;;; ============================================================
|
2018-01-06 05:03:10 +00:00
|
|
|
|
2017-08-29 15:07:02 +00:00
|
|
|
.macro MLI_CALL op, addr
|
|
|
|
jsr MLI
|
|
|
|
.byte op
|
|
|
|
.addr addr
|
|
|
|
.endmacro
|
2018-01-05 05:57:50 +00:00
|
|
|
|
2018-02-28 02:38:18 +00:00
|
|
|
.macro DEFINE_OPEN_PARAMS name, pn, io, rn
|
2018-02-26 04:28:23 +00:00
|
|
|
.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
|
2018-03-07 18:39:36 +00:00
|
|
|
.if .xmatch(.string(io), "io_buffer")
|
|
|
|
.error "Can't pass 'io_buffer' label to DEFINE_*_PARAMS"
|
|
|
|
.endif
|
2018-02-26 04:28:23 +00:00
|
|
|
.proc name
|
|
|
|
param_count: .byte 3
|
|
|
|
pathname: .addr pn
|
|
|
|
io_buffer: .addr io
|
2018-02-28 02:38:18 +00:00
|
|
|
.ifnblank rn
|
|
|
|
ref_num: .byte rn
|
|
|
|
.else
|
2018-02-26 04:28:23 +00:00
|
|
|
ref_num: .byte 0
|
2018-02-28 02:38:18 +00:00
|
|
|
.endif
|
2018-02-26 04:28:23 +00:00
|
|
|
.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
|
|
|
|
|
2018-02-26 05:03:58 +00:00
|
|
|
.macro DEFINE_GET_FILE_INFO_PARAMS name, pn
|
2018-02-26 04:28:23 +00:00
|
|
|
.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
|
2018-02-26 05:03:58 +00:00
|
|
|
pathname: .addr pn
|
2018-02-26 04:28:23 +00:00
|
|
|
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
|
|
|
|
|
2018-02-26 05:03:58 +00:00
|
|
|
.macro DEFINE_ON_LINE_PARAMS name, un, db
|
2018-02-26 04:28:23 +00:00
|
|
|
.proc name
|
|
|
|
param_count: .byte 2
|
2018-02-26 05:03:58 +00:00
|
|
|
|
|
|
|
.ifnblank un
|
|
|
|
unit_num: .byte un
|
|
|
|
.else
|
2018-02-26 04:28:23 +00:00
|
|
|
unit_num: .byte 0
|
2018-02-26 05:03:58 +00:00
|
|
|
.endif
|
|
|
|
|
2018-02-26 04:28:23 +00:00
|
|
|
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
|
|
|
|
|
2018-05-14 07:10:39 +00:00
|
|
|
.macro DEFINE_QUIT_PARAMS name, ext, pathname
|
2018-02-26 04:28:23 +00:00
|
|
|
.proc name
|
2018-02-28 02:38:18 +00:00
|
|
|
param_count: .byte 4
|
2018-05-14 07:10:39 +00:00
|
|
|
.ifnblank ext
|
|
|
|
.byte ext
|
2018-02-28 02:38:18 +00:00
|
|
|
.else
|
|
|
|
.byte 0
|
|
|
|
.endif
|
2018-05-14 07:10:39 +00:00
|
|
|
.ifnblank pathname
|
|
|
|
.word pathname
|
2018-02-28 02:38:18 +00:00
|
|
|
.else
|
|
|
|
.word 0
|
|
|
|
.endif
|
|
|
|
.byte 0
|
|
|
|
.word 0
|
2018-02-26 04:28:23 +00:00
|
|
|
.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
|
2018-02-26 05:03:58 +00:00
|
|
|
.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
|
2018-02-26 04:28:23 +00:00
|
|
|
param_count: .byte 1
|
|
|
|
pathname: .addr pn
|
|
|
|
.endproc
|
|
|
|
.endmacro
|
2018-02-26 05:03:58 +00:00
|
|
|
|
|
|
|
.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
|
|
|
|
|
2018-02-27 04:51:23 +00:00
|
|
|
.macro DEFINE_GET_EOF_PARAMS name
|
|
|
|
.proc name
|
|
|
|
param_count: .byte 2
|
|
|
|
ref_num: .byte 0
|
|
|
|
eof: .faraddr 0
|
|
|
|
.endproc
|
|
|
|
.endmacro
|
|
|
|
|
2018-02-26 05:03:58 +00:00
|
|
|
.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
|
2018-02-27 04:13:18 +00:00
|
|
|
.endmacro
|