prodos-path/path.s

517 lines
12 KiB
ArmAsm
Raw Normal View History

2019-01-07 00:44:54 +00:00
;;; ============================================================
;;;
2019-01-07 01:23:56 +00:00
;;; PATH
2019-01-07 00:44:54 +00:00
;;;
;;; Build with: ca65 - https://cc65.github.io/doc/ca65.html
;;;
;;; ============================================================
.org $2000
2019-01-07 04:26:58 +00:00
.include "apple2.inc"
2021-03-07 23:29:51 +00:00
.include "more_apple2.inc"
2019-01-07 01:23:56 +00:00
.include "prodos.inc"
2019-01-08 03:36:25 +00:00
;;; ============================================================
2019-01-07 00:44:54 +00:00
2019-01-07 06:56:45 +00:00
cmd_load_addr := $4000
max_cmd_size = $2000
2019-01-07 04:26:58 +00:00
CASE_MASK = $DF
2019-01-07 00:44:54 +00:00
;;; ============================================================
2019-01-07 04:26:58 +00:00
;;; Install the new command
2019-01-07 06:56:45 +00:00
.proc installer
ptr := $06
2019-01-07 00:44:54 +00:00
;; Save previous external command address
lda EXTRNCMD+1
sta next_command
lda EXTRNCMD+2
sta next_command+1
2019-01-08 07:06:57 +00:00
;; Request a buffer for handler.
lda #handler_pages
2019-01-07 00:44:54 +00:00
jsr GETBUFR
bcc :+
2021-04-16 02:47:41 +00:00
lda #BI_ERR_NO_BUFFERS_AVAILABLE
2019-01-07 00:44:54 +00:00
rts
2019-01-07 04:26:58 +00:00
: sta new_page ; A = MSB of new page
2019-01-08 07:06:57 +00:00
;; Reserve buffer permanently.
;; ProDOS Technical Note #9: Buffer Management Using BASIC.SYSTEM
lda RSHIMEM
sec
sbc #handler_pages
sta RSHIMEM
2019-01-07 04:26:58 +00:00
;; Compute move delta in pages
2019-01-08 07:06:57 +00:00
lda new_page
2019-01-07 04:26:58 +00:00
sec
2019-01-08 05:15:54 +00:00
sbc #>handler
2019-01-07 04:26:58 +00:00
sta page_delta
;; Relocatable routine is aligned to page boundary so only MSB changes
2019-01-07 06:56:45 +00:00
ldx #0
: txa
asl
tay
lda relocation_table+1,y
sta ptr
lda relocation_table+2,y
sta ptr+1
2019-01-08 05:15:54 +00:00
lda (ptr)
2019-01-07 04:26:58 +00:00
clc
adc page_delta
2019-01-08 05:15:54 +00:00
sta (ptr)
2019-01-07 06:56:45 +00:00
inx
cpx relocation_table
bne :-
2019-01-07 00:44:54 +00:00
2019-01-07 04:26:58 +00:00
;; Relocate
lda #<handler
sta MOVE_SRC
lda #>handler
sta MOVE_SRC+1
lda #<handler_end
sta MOVE_END
lda #>handler_end
sta MOVE_END+1
lda #0
sta MOVE_DST
lda new_page
sta MOVE_DST+1
ldy #0
jsr MOVE
2019-01-07 00:44:54 +00:00
;; Install new address in external command address
2019-01-07 04:26:58 +00:00
lda new_page
2019-01-07 00:44:54 +00:00
sta EXTRNCMD+2
lda #0
sta EXTRNCMD+1
;; Complete
rts
2019-01-10 04:41:33 +00:00
new_page:
.byte 0
page_delta:
.byte 0
2019-01-07 06:56:45 +00:00
.endproc
2019-01-07 00:44:54 +00:00
;;; ============================================================
2019-01-10 04:41:33 +00:00
;;;
;;; Relocatable Section
;;;
2019-01-07 00:44:54 +00:00
;;; ============================================================
2019-01-10 04:41:33 +00:00
;;; Use `reloc_counter ADDR` anywhere that needs the page updated
;;;
;;; Examples:
;;;
;;; reloc_point *+2 ; update MSB of following JSR
;;; jsr routine
;;;
;;; reloc_point *+1 ; update MSB used in following LDA
;;; lda #>routine
::reloc_counter .set 0
.macro reloc_point addr
::.ident (.sprintf ("RL%04X", ::reloc_counter)) := addr
::reloc_counter .set ::reloc_counter + 1
.endmacro
;;; Align handler to page boundary for easier relocation
2019-01-07 00:44:54 +00:00
.res $2100 - *, 0
2019-01-10 04:41:33 +00:00
;;; ============================================================
;;; Command Handler
;;; ============================================================
2019-01-07 00:44:54 +00:00
.proc handler
2019-01-10 01:17:16 +00:00
ptr := $06 ; pointer into VPATH
2021-04-14 02:12:07 +00:00
tptr := $08 ; pointer into TOKTABL
2019-01-10 01:17:16 +00:00
lda VPATH1
sta ptr
lda VPATH1+1
sta ptr+1
2019-01-07 00:44:54 +00:00
;; Check for this command, character by character.
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
jsr SkipLeadingSpaces
2019-01-07 00:44:54 +00:00
ldy #0 ; position in command string
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
nxtchr: jsr ToUpperASCII
2019-01-07 00:44:54 +00:00
2019-01-10 04:41:33 +00:00
reloc_point *+2
cmp command_string,y
2019-01-07 04:26:58 +00:00
bne check_if_token
2019-01-07 00:44:54 +00:00
inx
iny
cpy #command_length
2019-01-07 00:44:54 +00:00
bne nxtchr
;; A match - indicate end of command string for BI's parser.
dey
sty XLEN
2019-01-07 00:44:54 +00:00
;; Point BI's parser at the command execution routine.
lda #<execute
sta XTRNADDR
2019-01-10 04:41:33 +00:00
reloc_point *+1
2019-01-07 00:44:54 +00:00
lda #>execute
sta XTRNADDR+1
2019-01-08 15:59:00 +00:00
;; Set accepted parameter flags (optional name)
lda #PBitsFlags::FNOPT | PBitsFlags::FN1
2019-01-07 00:44:54 +00:00
sta PBITS
2019-01-08 15:59:00 +00:00
lda #0
2019-01-07 00:44:54 +00:00
sta PBITS+1
2024-01-02 05:43:55 +00:00
;; Mark command as external (zero).
sta XCNUM ; A=0 from above
2019-01-07 00:44:54 +00:00
clc ; Success (so far)
rts ; Return to BASIC.SYSTEM
;;; ============================================================
2019-01-07 04:26:58 +00:00
check_if_token:
2019-01-07 06:56:45 +00:00
;; Is a PATH set?
2019-01-10 04:41:33 +00:00
reloc_point *+2
2019-01-07 06:56:45 +00:00
lda path_buffer
beq not_ours
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
jsr SkipLeadingSpaces
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
jsr ToUpperASCII
2019-01-07 01:23:56 +00:00
2019-01-08 05:45:39 +00:00
cmp #'A'
2019-01-07 04:26:58 +00:00
bcc not_ours
2019-01-08 05:45:39 +00:00
cmp #'Z'+1
2019-01-07 04:26:58 +00:00
bcs not_ours
;; Check if it's a BASIC token. Based on the AppleSoft BASIC source.
2021-04-14 02:12:07 +00:00
;; Point tptr at TOKTABL less one page (will advance below)
lda #<(TOKTABL-$100)
2019-01-10 01:17:16 +00:00
sta tptr
2021-04-14 02:12:07 +00:00
lda #>(TOKTABL-$100)
2019-01-10 01:17:16 +00:00
sta tptr+1
2019-01-07 04:26:58 +00:00
2019-01-10 00:57:32 +00:00
;; These are immediately incremented
dex
2021-04-14 02:12:07 +00:00
ldy #$FF ; (tptr),y offset TOKTABL
2019-01-07 04:26:58 +00:00
;; Match loop
mloop: iny ; Advance through token table
bne :+
2019-01-10 01:17:16 +00:00
inc tptr+1
2019-01-07 04:26:58 +00:00
: inx
;; Check for match
next_char:
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
jsr ToUpperASCII ; Next character
2019-01-07 04:26:58 +00:00
;; NOTE: Does not skip over spaces, unlike BASIC tokenizer
sec ; Compare by subtraction..
2019-01-10 01:17:16 +00:00
sbc (tptr),Y
2019-01-07 04:26:58 +00:00
beq mloop
cmp #$80 ; If only difference was the high bit
2020-06-07 15:02:08 +00:00
bne next_token ; then it's end-of-token -- and a match!
;; Only if next command char is not alpha.
;; This allows 'ON' as a prefix (e.g. 'ONLINE'),
;; without preventing 'RUN100' from being typed.
inx
reloc_point *+2
2021-04-16 02:47:41 +00:00
jsr ToUpperASCII
2020-06-07 15:02:08 +00:00
cmp #'A'
bcc not_ours
cmp #'Z'+1
bcs not_ours
2019-01-07 04:26:58 +00:00
;; Otherwise, advance to next token
next_token:
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
jsr SkipLeadingSpaces
2019-01-10 01:17:16 +00:00
sloop: lda (tptr),y ; Scan table looking for a high bit set
2019-01-07 04:26:58 +00:00
iny
bne :+
2019-01-10 01:17:16 +00:00
inc tptr+1
2019-01-07 04:26:58 +00:00
: asl
2019-01-08 16:02:16 +00:00
bcc sloop ; High bit clear, keep looking
lda (tptr),y ; End of table?
2019-01-07 04:26:58 +00:00
bne next_char ; Nope, check for a match
2019-01-07 06:56:45 +00:00
beq maybe_invoke
2019-01-07 01:23:56 +00:00
2019-01-07 00:44:54 +00:00
not_ours:
2020-06-07 15:02:08 +00:00
fail_invoke:
2019-01-07 00:44:54 +00:00
sec ; Signal failure...
next_command := *+1
jmp $ffff ; Execute next command in chain
2019-01-07 04:26:58 +00:00
2019-01-08 15:48:13 +00:00
;;; ============================================================
2019-01-07 06:56:45 +00:00
maybe_invoke:
2019-01-10 05:20:16 +00:00
ppos := $D6 ; position into path_buffer
lda #0
sta ppos
2019-01-07 06:56:45 +00:00
;; Compose path
2019-01-10 05:20:16 +00:00
compose:
ldx ppos
2019-01-10 04:41:33 +00:00
reloc_point *+2
2019-01-10 05:20:16 +00:00
cpx path_buffer
beq fail_invoke
;; Entry from path list
ldy #1
2019-01-10 04:41:33 +00:00
reloc_point *+2
2019-01-10 05:20:16 +00:00
: lda path_buffer+1,x
inx
cmp #':' ; separator
beq :+
sta (ptr),y
iny
2019-01-10 05:20:16 +00:00
reloc_point *+2
cpx path_buffer
2019-01-07 06:56:45 +00:00
bne :-
2019-01-10 05:20:16 +00:00
;; Slash separator
: stx ppos
2019-01-07 06:56:45 +00:00
lda #'/'
sta (ptr),y
iny
2019-01-07 06:56:45 +00:00
2019-01-10 05:20:16 +00:00
;; Name from command line
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
jsr SkipLeadingSpaces
2019-01-10 04:41:33 +00:00
reloc_point *+2
2021-04-16 02:47:41 +00:00
: jsr ToUpperASCII
2019-01-08 05:15:54 +00:00
cmp #'.'
beq ok
2019-01-07 06:56:45 +00:00
cmp #'0'
2019-01-08 05:15:54 +00:00
bcc notok
2019-01-07 06:56:45 +00:00
cmp #'9'+1
2019-01-08 05:15:54 +00:00
bcc ok
2019-01-07 06:56:45 +00:00
cmp #'A'
2019-01-08 05:15:54 +00:00
bcc notok
2019-01-07 06:56:45 +00:00
cmp #'Z'+1
2019-01-08 05:15:54 +00:00
bcs notok
2019-01-07 06:56:45 +00:00
ok: sta (ptr),y
2019-01-07 06:56:45 +00:00
iny
2019-01-08 15:48:13 +00:00
inx
cpx #65 ; Maximum path length+1
bcc :-
2019-01-10 05:20:16 +00:00
bcs compose
2019-01-07 06:56:45 +00:00
notok: dey
tya
ldy #0
sta (ptr),y
2019-01-07 06:56:45 +00:00
2021-03-07 23:29:51 +00:00
;; Indicate end of command string for BI's parser (if command uses it)
dex
2024-01-03 06:17:14 +00:00
stx xlen ; assigned to `XLEN` later
2021-03-07 23:29:51 +00:00
2019-01-08 15:48:13 +00:00
;; Check to see if path exists.
lda #$A ; param length
sta SSGINFO
lda #GET_FILE_INFO
jsr GOSYSTEM
2019-01-10 05:20:16 +00:00
bne compose ; no such file - try next path directory
2019-01-07 06:56:45 +00:00
2019-01-08 15:48:13 +00:00
;; Check to see if type is CMD.
2019-09-23 04:34:34 +00:00
lda FIFILID
2021-04-16 02:47:41 +00:00
cmp #FT_CMD
2019-01-10 05:20:16 +00:00
bne compose ; wrong type - try next path directory
2019-01-07 06:56:45 +00:00
;; Tell BASIC.SYSTEM it was handled.
2024-01-03 06:17:14 +00:00
ldx #xtrnaddr_len - 1
: lda xtrnaddr,x
sta XTRNADDR,x
dex
bpl :-
2019-01-07 06:56:45 +00:00
2021-03-07 23:29:51 +00:00
;; MLI/BI trashes part of INBUF (clock driver?), so stash it in upper half.
ldx #$7F
: lda INBUF,x
sta INBUF+$80,x
dex
bpl :-
;; Use BI general purpose buffer for I/O (page aligned)
lda HIMEM+1
sta OSYSBUF+1
2019-01-08 07:06:57 +00:00
2019-01-07 06:56:45 +00:00
;; Now try to open/read/close and invoke it
lda #OPEN
jsr GOSYSTEM
bcs fail_load
2019-01-07 06:56:45 +00:00
lda OREFNUM
sta RWREFNUM
sta CFREFNUM
2024-01-03 06:17:14 +00:00
;; Assign `RWDATA` and `RWCOUNT`
ldx #rwdata_len - 1
: lda rwdata,x
sta RWDATA,x
dex
bpl :-
2019-01-08 15:50:43 +00:00
lda #READ
jsr GOSYSTEM
php ; save C in case it signals failure
pha ; if so, A has error code
2019-01-07 06:56:45 +00:00
lda #CLOSE ; always close
jsr GOSYSTEM
pla
plp
bcs fail_load
2019-01-07 06:56:45 +00:00
;; Restore INBUF now that MLI/BI work is done.
2019-01-09 06:55:06 +00:00
ldx #$7F
: lda INBUF+$80,x
sta INBUF,x
dex
bpl :-
;; Invoke command, allow it to return to BASIC.SYSTEM
jmp cmd_load_addr
2019-01-07 06:56:45 +00:00
2019-01-08 15:55:09 +00:00
fail_load:
rts
2019-01-08 15:55:09 +00:00
2024-01-03 06:17:14 +00:00
;;; Assigned to `XTRNADDR`, `XLEN`, `XCNUM`, and `PBITS`
xtrnaddr:
.addr XRETURN ; assigned to `XTRNADDR`
xlen: .byte 0 ; assigned to `XLEN`
.byte 0 ; assigned to `XCNUM`
.word 0 ; assigned to `PBITS`
xtrnaddr_len = * - xtrnaddr
;;; Assigned to `RWDATA` and `RWCOUNT`
rwdata:
.addr cmd_load_addr ; assigned to `RWDATA`
.word max_cmd_size ; assigned to `RWCOUNT`
rwdata_len = * - rwdata
2019-01-07 04:26:58 +00:00
;;; ============================================================
2019-01-07 00:44:54 +00:00
execute:
;; Verify required arguments
lda FBITS
and #PBitsFlags::FN1 ; Filename?
2019-01-07 01:23:56 +00:00
bne set_path
2019-01-07 00:44:54 +00:00
;;; --------------------------------------------------
2019-01-07 01:23:56 +00:00
;; Show current path
2019-01-07 00:44:54 +00:00
2019-01-07 01:23:56 +00:00
ldx #0
2019-01-10 04:41:33 +00:00
reloc_point *+2
2019-01-07 01:23:56 +00:00
: cpx path_buffer
beq done
2019-01-10 04:41:33 +00:00
reloc_point *+2
2019-01-07 01:23:56 +00:00
lda path_buffer+1,x
ora #$80
2019-01-07 00:44:54 +00:00
jsr COUT
2019-01-07 01:23:56 +00:00
inx
bpl :-
2019-01-07 00:44:54 +00:00
jsr CROUT
2019-01-07 01:23:56 +00:00
done: clc
rts
2019-01-07 00:44:54 +00:00
2019-01-07 01:23:56 +00:00
;;; --------------------------------------------------
;; Set path
set_path:
ldy #0
lda (ptr),y
tay
: lda (ptr),y
2019-01-10 04:41:33 +00:00
reloc_point *+2
2019-01-07 01:23:56 +00:00
sta path_buffer,y
dey
bpl :-
2019-01-07 00:44:54 +00:00
clc
rts
2019-01-07 04:26:58 +00:00
;;; ============================================================
;;; Helpers
2019-01-10 00:36:42 +00:00
;;; Returns INBUF,x with high bit stripped and up-cased
;;; (also converts {|}~DEL to [\]^_ but that's okay)
2021-04-16 02:47:41 +00:00
.proc ToUpperASCII
2019-01-10 00:36:42 +00:00
lda INBUF,x
2019-01-08 05:45:39 +00:00
and #$7F
cmp #'a'
2019-01-07 04:26:58 +00:00
bcc skip
and #CASE_MASK
skip: rts
.endproc
2019-01-10 00:23:19 +00:00
;;; Returns with X pointing at first non-space in INBUF,
;;; and that character loaded in A.
2021-04-16 02:47:41 +00:00
.proc SkipLeadingSpaces
2019-01-10 00:23:19 +00:00
ldx #$FF
: inx
lda INBUF,x
cmp #' '|$80
beq :-
rts
.endproc
2019-01-07 00:44:54 +00:00
;;; ============================================================
;;; Data
command_string:
2019-01-08 05:45:39 +00:00
.byte "PATH"
2019-01-07 00:44:54 +00:00
command_length = *-command_string
2019-01-07 01:23:56 +00:00
path_buffer:
.res 65, 0
2019-01-07 00:44:54 +00:00
.endproc
2019-01-07 04:26:58 +00:00
handler_end := *-1
2019-01-08 07:06:57 +00:00
handler_pages = (.sizeof(handler) + $FF) / $100
2019-01-07 00:44:54 +00:00
next_command := handler::next_command
2019-01-07 01:23:56 +00:00
2019-01-10 00:36:42 +00:00
;;; ============================================================
2019-01-10 04:41:33 +00:00
;;;
;;; Relocation Table
;;;
;;; ============================================================
2019-01-07 04:26:58 +00:00
2019-01-07 01:23:56 +00:00
relocation_table:
2019-01-10 04:41:33 +00:00
.byte ::reloc_counter
.repeat ::reloc_counter, rc
.addr ::.ident (.sprintf ("RL%04X", rc))
.endrepeat
;;; ============================================================