From 8817199aa7cf27e4b2920f892c75fc82f564ffea Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 11 Nov 2017 20:44:15 -0800 Subject: [PATCH 01/34] Initial snapshot - mid-disassembly --- Makefile | 22 +++ b.s | 483 +++++++++++++++++++++++++++++++++++++++++++++++++++++ prodos.inc | 62 +++++++ 3 files changed, 567 insertions(+) create mode 100644 Makefile create mode 100644 b.s create mode 100644 prodos.inc diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c0427ae --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ + +CC65 = ~/dev/cc65/bin +CAFLAGS = --target apple2enh --list-bytes 0 +CCFLAGS = --config apple2-asm.cfg + +# ProDOS file type is $F1 ($ is pesky) +TARGETS = b.SYS + +.PHONY: clean all +all: $(TARGETS) + +HEADERS = $(wildcard *.inc) + +clean: + rm -f *.o + rm -f $(TARGETS) + +%.o: %.s $(HEADERS) + $(CC65)/ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< + +%.SYS: %.o + $(CC65)/ld65 $(CCFLAGS) -o $@ $< diff --git a/b.s b/b.s new file mode 100644 index 0000000..8578cfc --- /dev/null +++ b/b.s @@ -0,0 +1,483 @@ + + .setcpu "65C02" + .include "prodos.inc" + +L0060 := $0060 + +KBD := $C000 +RAMRDOFF := $C002 +RAMRDON := $C003 +RAMWRTOFF := $C004 +RAMWRTON := $C005 +ALTZPOFF := $C008 +ALTZPON := $C009 +KBDSTRB := $C010 +ROMIN := $C081 +ROMINNW := $C082 +ROMINWB1 := $C089 +LCBANK1 := $C08B +LC300 := $C300 + +MON_SETTXT := $FB39 +MON_TABV := $FB5B +SETPWRC := $FB6F +BELL1 := $FBDD +MON_HOME := $FC58 +COUT := $FDED +SETINV := $FE80 +SETNORM := $FE84 + + .org $2000 + +L2000: jmp install_and_quit + install_src := * + + .org $1000 +.proc bbb + cld + lda ROMINNW + stz $03F2 + lda #$10 + sta $03F3 + jsr SETPWRC + lda #$A0 + jsr LC300 + ldx #$17 +L1016: stz $BF58,x + dex + bpl L1016 + inc $BF6F + lda #$CF + sta $BF58 + lda #$02 + sta L0060 + ldx $BF31 + stx $65 + lda $BF30 + bne L1042 +L1032: ldx $65 + lda $BF32,x + cpx #$01 + bcs L103F + ldx $BF31 + inx +L103F: dex + stx $65 +L1042: sta on_line_params_unit + MLI_CALL ON_LINE, on_line_params + bcs L1032 + stz $6B + lda $0281 + and #$0F + beq L1032 + adc #$02 + tax +L1059: stx $0280 + lda #$2F + sta $0281 + sta $0280,x + stz $0281,x + MLI_CALL OPEN, open_params + bcc L107F + lda $6B + beq L1032 + jsr BELL1 + jsr L11DA + stx $0280 + jmp keyboard_loop + +L107F: inc $6B + stz $68 + lda open_params_ref_num + sta read_params_ref_num + sta $61 + lda #$2B + sta read_params_request + stz read_params_request+1 + jsr L12B4 + bcs L10B3 + ldx #$03 +L109A: lda $2023,x + sta $6E,x + dex + bpl L109A + sta read_params_request + lda #$01 + sta $72 + stz $63 + stz $64 + lda $70 + ora $71 + bne L10B5 +L10B3: bra L1129 +L10B5: bit $71 + bmi L10B3 +L10B9: lda $63 + and #$FE + sta $63 + ldy $72 + lda #$00 + cpy $6F + bcc L10CE + tay + sty $72 + inc $63 +L10CC: inc $63 +L10CE: dey + clc + bmi L10D8 + adc $6E + bcc L10CE + bcs L10CC +L10D8: adc #$04 + sta $62 + MLI_CALL SET_MARK, L0060 + bcs L10B3 + jsr L12B4 + bcs L10B3 + inc $72 + lda L2000 + and #$F0 + beq L10B9 + dec $70 + bne L10F8 + dec $71 +L10F8: ror $201E + bcc L10B5 + lda $2010 + cmp #$0F + beq L1108 + cmp #$FF + bne L10B5 +L1108: ldx $68 + cpx #$80 + bcs L1129 + sta $74,x + jsr L1258 + ldy #$0F +L1115: lda L2000,y + sta ($6C),y + dey + bpl L1115 + iny + and #$0F + sta ($6C),y + inc $68 + bne L10B5 +L1126: jmp L1032 + +L1129: MLI_CALL CLOSE, close_params + bcs L1126 + jsr MON_SETTXT + jsr MON_HOME + lda #$17 + jsr MON_TABV + ldy #$00 + lda #$14 + jsr L124A + jsr L12AD + ldx #$00 +L1148: lda $0281,x + beq L1153 + jsr L12AF + inx + bne L1148 +L1153: stz $67 + stz $73 + lda $68 + beq keyboard_loop + cmp #$15 + bcc L1161 + lda #$14 +L1161: sta $6A + lda #$02 + sta $22 + sta $20 + lda #$16 + sta $21 + sta $23 +L116F: jsr L1277 + inc $67 + dec $6A + bne L116F + stz $67 + beq L11AA + +on_up: jsr L1277 + ldx $67 + beq L11AA + dec $67 + lda $25 + cmp #$02 + bne L11AA + dec $73 + lda #$16 + bne L11A7 + +on_down: + jsr L1277 + ldx $67 + inx + cpx $68 + bcs L11AA + stx $67 + lda $25 + cmp #$15 + bne L11AA + inc $73 + lda #$17 + +L11A7: jsr COUT +L11AA: jsr SETINV + jsr L1277 + +keyboard_loop: + lda KBD + bpl keyboard_loop + sta KBDSTRB + jsr SETNORM + ldx $68 + beq L11CB + cmp #$8D ; Return + beq L11F4 + cmp #$8A ; Down Arrow + beq on_down + cmp #$8B ; Up Arrow + beq on_up +L11CB: cmp #$89 ; Tab + beq next_drive + cmp #$9B ; Esc + bne keyboard_loop + + jsr L11DA + dec $6B + bra L11F1 +L11DA: ldx $0280 +L11DD: dex + lda $0280,x + cmp #$2F + bne L11DD + cpx #$01 + bne L11EC + ldx $0280 +L11EC: rts + +next_drive: + jmp L1032 + +L11F0: inx +L11F1: jmp L1059 + +L11F4: MLI_CALL SET_PREFIX, set_prefix_params + bcs next_drive + ldx $67 + jsr L1258 + ldx $0280 +L1204: iny + lda ($6C),y + inx + sta $0280,x + cpy $69 + bcc L1204 + stx $0280 + ldy $67 + lda $74,y + bpl L11F0 + jsr MON_SETTXT + jsr MON_HOME + lda #$95 + jsr COUT + MLI_CALL OPEN, open_params + bcs next_drive + lda open_params_ref_num + sta read_params_ref_num + lda #$FF + sta read_params_request + sta read_params_request+1 + jsr L12B4 + php + MLI_CALL CLOSE, close_params + plp + bcs next_drive + jmp L2000 + +L124A: sta $24 +L124C: lda help_string,y + beq L1257 + jsr COUT + iny + bne L124C +L1257: rts + +L1258: stz $6D + txa + asl a + rol $6D + asl a + rol $6D + asl a + rol $6D + asl a + rol $6D + sta $6C + lda #$14 + clc + adc $6D + sta $6D + ldy #$00 + lda ($6C),y + sta $69 + rts + +L1277: lda #$02 + sta $057B + ldx $67 + txa + sec + sbc $73 + inc a + inc a + jsr MON_TABV + lda $74,x + bmi L1299 + stz $057B + lda $32 + pha + ldy #$2A + jsr L124C + pla + sta $32 +L1299: jsr L12A9 + jsr L1258 +L129F: iny + lda ($6C),y + jsr L12AF + cpy $69 + bcc L129F +L12A9: lda #$A0 + bne L12B1 +L12AD: lda #$99 +L12AF: ora #$80 +L12B1: jmp COUT + +L12B4: MLI_CALL READ, read_params + rts + + .macro HIASCII arg + .repeat .strlen(arg), i + .byte .strat(arg, i) | $80 + .endrep +.endmacro + +.proc help_string + HIASCII "RETURN: Select | TAB: Chg Vol | ESC: Back" + .byte 0 ; null terminated +.endproc + + ;; Mousetext sequence: Enable, folder left, folder right, disable +.proc folder_string + .byte $0F,$1B,$D8,$D9,$18,$0E + .byte 0 ; null terminated +.endproc + +.proc open_params +params: .byte 3 +path: .addr $0280 +buffer: .addr $1C00 +ref_num:.byte 0 +.endproc + open_params_ref_num := open_params::ref_num + +.proc close_params +params: .byte 1 +ref_num:.byte 0 +.endproc + +.proc on_line_params +params: .byte 2 +unit: .byte $60 +buffer: .addr $0281 +.endproc + on_line_params_unit := on_line_params::unit + +.proc set_prefix_params +params: .byte 1 +path: .addr $0280 +.endproc + +.proc read_params +params: .byte 4 +ref_num:.byte 1 +buffer: .word $2000 +request:.word 0 +trans: .word 0 +.endproc + read_params_ref_num := read_params::ref_num + read_params_request := read_params::request + + .res 192, 0 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$00,$00,$00,$00,$00,$00 + .byte $00,$00,$48,$AD + +.endproc + .assert .sizeof(bbb) = $3FF, error, "Expected size is $3FF" + .org $2402 + +install_and_quit: + jsr install + MLI_CALL QUIT, quit_params +.proc quit_params +params: .byte 4 +type: .byte 0 +res1: .word 0 +res2: .byte 0 +res3: .addr 0 +.endproc + +.proc install + src := install_src + end := install_src + .sizeof(bbb) + dst := $D100 ; Install location in ProDOS + + src_ptr := $19 + dst_ptr := $1B + + sta ALTZPOFF + lda ROMIN + lda ROMIN + lda #>src + sta src_ptr+1 + lda #dst + sta dst_ptr+1 + lda #end + bne loop + lda src_ptr + cmp # Date: Mon, 13 Nov 2017 07:57:57 -0800 Subject: [PATCH 02/34] Identifying data blocks --- b.s | 97 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 59 insertions(+), 38 deletions(-) diff --git a/b.s b/b.s index 8578cfc..8d348e0 100644 --- a/b.s +++ b/b.s @@ -27,6 +27,7 @@ COUT := $FDED SETINV := $FE80 SETNORM := $FE84 + .org $2000 L2000: jmp install_and_quit @@ -34,6 +35,12 @@ L2000: jmp install_and_quit .org $1000 .proc bbb + + prefix := $280 ; length-prefixed + ;; filenames at $1400 - each is length byte + 15 byte buffer + + read_buffer := $2000 ; Also, start location for launched SYS files + cld lda ROMINNW stz $03F2 @@ -67,26 +74,28 @@ L1042: sta on_line_params_unit MLI_CALL ON_LINE, on_line_params bcs L1032 stz $6B - lda $0281 + lda prefix+1 and #$0F beq L1032 adc #$02 tax -L1059: stx $0280 - lda #$2F - sta $0281 - sta $0280,x - stz $0281,x + +L1059: stx prefix ; truncate prefix to length x + lda #'/' + sta prefix+1 + sta prefix,x + stz prefix+1,x + MLI_CALL OPEN, open_params bcc L107F lda $6B beq L1032 jsr BELL1 jsr L11DA - stx $0280 + stx prefix jmp keyboard_loop -L107F: inc $6B +L107F: inc $6B ; ??? stz $68 lda open_params_ref_num sta read_params_ref_num @@ -94,7 +103,7 @@ L107F: inc $6B lda #$2B sta read_params_request stz read_params_request+1 - jsr L12B4 + jsr do_read bcs L10B3 ldx #$03 L109A: lda $2023,x @@ -133,10 +142,10 @@ L10D8: adc #$04 sta $62 MLI_CALL SET_MARK, L0060 bcs L10B3 - jsr L12B4 + jsr do_read bcs L10B3 inc $72 - lda L2000 + lda read_buffer and #$F0 beq L10B9 dec $70 @@ -155,7 +164,7 @@ L1108: ldx $68 sta $74,x jsr L1258 ldy #$0F -L1115: lda L2000,y +L1115: lda read_buffer,y sta ($6C),y dey bpl L1115 @@ -177,7 +186,7 @@ L1129: MLI_CALL CLOSE, close_params jsr L124A jsr L12AD ldx #$00 -L1148: lda $0281,x +L1148: lda prefix+1,x beq L1153 jsr L12AF inx @@ -239,7 +248,7 @@ keyboard_loop: ldx $68 beq L11CB cmp #$8D ; Return - beq L11F4 + beq on_return cmp #$8A ; Down Arrow beq on_down cmp #$8B ; Up Arrow @@ -252,14 +261,14 @@ L11CB: cmp #$89 ; Tab jsr L11DA dec $6B bra L11F1 -L11DA: ldx $0280 +L11DA: ldx prefix L11DD: dex - lda $0280,x - cmp #$2F + lda prefix,x + cmp #'/' bne L11DD cpx #$01 bne L11EC - ldx $0280 + ldx prefix L11EC: rts next_drive: @@ -268,45 +277,54 @@ next_drive: L11F0: inx L11F1: jmp L1059 -L11F4: MLI_CALL SET_PREFIX, set_prefix_params +on_return: + MLI_CALL SET_PREFIX, set_prefix_params bcs next_drive ldx $67 jsr L1258 - ldx $0280 -L1204: iny + + ldx prefix +: iny lda ($6C),y inx - sta $0280,x + sta prefix,x cpy $69 - bcc L1204 - stx $0280 + bcc :- + stx prefix + ldy $67 lda $74,y - bpl L11F0 + bpl L11F0 ; is directory??? + +.proc launch_sys_file jsr MON_SETTXT jsr MON_HOME - lda #$95 + lda #$95 ; Right arrow jsr COUT + MLI_CALL OPEN, open_params bcs next_drive lda open_params_ref_num sta read_params_ref_num - lda #$FF + lda #$FF ; Load up to $FFFF bytes sta read_params_request sta read_params_request+1 - jsr L12B4 + jsr do_read php MLI_CALL CLOSE, close_params plp bcs next_drive - jmp L2000 + jmp read_buffer ; Invoke the loaded code +.endproc L124A: sta $24 -L124C: lda help_string,y + +cout_string: + lda help_string,y beq L1257 jsr COUT iny - bne L124C + bne cout_string L1257: rts L1258: stz $6D @@ -343,8 +361,8 @@ L1277: lda #$02 stz $057B lda $32 pha - ldy #$2A - jsr L124C + ldy #(folder_string - string_start) ; Draw folder glyphs + jsr cout_string pla sta $32 L1299: jsr L12A9 @@ -360,8 +378,10 @@ L12AD: lda #$99 L12AF: ora #$80 L12B1: jmp COUT -L12B4: MLI_CALL READ, read_params +.proc do_read + MLI_CALL READ, read_params rts +.endproc .macro HIASCII arg .repeat .strlen(arg), i @@ -369,6 +389,7 @@ L12B4: MLI_CALL READ, read_params .endrep .endmacro + string_start := * .proc help_string HIASCII "RETURN: Select | TAB: Chg Vol | ESC: Back" .byte 0 ; null terminated @@ -382,7 +403,7 @@ L12B4: MLI_CALL READ, read_params .proc open_params params: .byte 3 -path: .addr $0280 +path: .addr prefix buffer: .addr $1C00 ref_num:.byte 0 .endproc @@ -396,19 +417,19 @@ ref_num:.byte 0 .proc on_line_params params: .byte 2 unit: .byte $60 -buffer: .addr $0281 +buffer: .addr prefix+1 .endproc on_line_params_unit := on_line_params::unit .proc set_prefix_params params: .byte 1 -path: .addr $0280 +path: .addr prefix .endproc .proc read_params params: .byte 4 ref_num:.byte 1 -buffer: .word $2000 +buffer: .word read_buffer request:.word 0 trans: .word 0 .endproc From e13d9f0e60629d09a91658aa6f11215106b31789 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Thu, 23 Nov 2017 08:31:12 -0800 Subject: [PATCH 03/34] Remove dead comment --- Makefile | 1 - 1 file changed, 1 deletion(-) diff --git a/Makefile b/Makefile index c0427ae..631a079 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,6 @@ CC65 = ~/dev/cc65/bin CAFLAGS = --target apple2enh --list-bytes 0 CCFLAGS = --config apple2-asm.cfg -# ProDOS file type is $F1 ($ is pesky) TARGETS = b.SYS .PHONY: clean all From 7042ad9901559bed59838df241ff19174506bc36 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 09:03:44 -0800 Subject: [PATCH 04/34] Identify states --- b.s | 191 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 126 insertions(+), 65 deletions(-) diff --git a/b.s b/b.s index 8d348e0..3eecdb9 100644 --- a/b.s +++ b/b.s @@ -1,21 +1,19 @@ +;;; Disassembly of BYE.SYSTEM (Bird's Better Bye) .setcpu "65C02" + .include "apple2.inc" .include "prodos.inc" L0060 := $0060 -KBD := $C000 RAMRDOFF := $C002 RAMRDON := $C003 RAMWRTOFF := $C004 RAMWRTON := $C005 ALTZPOFF := $C008 ALTZPON := $C009 -KBDSTRB := $C010 -ROMIN := $C081 ROMINNW := $C082 ROMINWB1 := $C089 -LCBANK1 := $C08B LC300 := $C300 MON_SETTXT := $FB39 @@ -27,6 +25,33 @@ COUT := $FDED SETINV := $FE80 SETNORM := $FE84 +ZP_HPOS := $24 + + +ASCII_TAB := $9 +ASCII_DOWN := $A +ASCII_UP := $B +ASCII_RETURN := $D +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 + +;;; ------------------------------------------------------------ + + ;; Loads at $2000 but executed at $1000. .org $2000 @@ -41,6 +66,12 @@ L2000: jmp install_and_quit read_buffer := $2000 ; Also, start location for launched SYS files + + current_entry := $67 + num_entries := $68 + rows_per_screen := 21 + current_line := $73 + cld lda ROMINNW stz $03F2 @@ -96,7 +127,7 @@ L1059: stx prefix ; truncate prefix to length x jmp keyboard_loop L107F: inc $6B ; ??? - stz $68 + stz num_entries lda open_params_ref_num sta read_params_ref_num sta $61 @@ -158,7 +189,7 @@ L10F8: ror $201E beq L1108 cmp #$FF bne L10B5 -L1108: ldx $68 +L1108: ldx num_entries cpx #$80 bcs L1129 sta $74,x @@ -171,31 +202,37 @@ L1115: lda read_buffer,y iny and #$0F sta ($6C),y - inc $68 + inc num_entries bne L10B5 L1126: jmp L1032 L1129: MLI_CALL CLOSE, close_params bcs L1126 + + ;; TEXT : HOME : VTAB 23 jsr MON_SETTXT jsr MON_HOME - lda #$17 + lda #23 ; line 23 jsr MON_TABV - ldy #$00 - lda #$14 - jsr L124A + + ;; Print help text + ldy #0 + lda #20 ; HTAB 20 + jsr cout_string_hpos + jsr L12AD - ldx #$00 -L1148: lda prefix+1,x + ldx #0 +: lda prefix+1,x beq L1153 jsr L12AF inx - bne L1148 -L1153: stz $67 - stz $73 - lda $68 + bne :- + +L1153: stz current_entry + stz current_line + lda num_entries beq keyboard_loop - cmp #$15 + cmp #rows_per_screen bcc L1161 lda #$14 L1161: sta $6A @@ -205,57 +242,68 @@ L1161: sta $6A lda #$16 sta $21 sta $23 -L116F: jsr L1277 - inc $67 +L116F: jsr draw_current_line + inc current_entry dec $6A bne L116F - stz $67 - beq L11AA + stz current_entry + beq draw_current_line_inv -on_up: jsr L1277 - ldx $67 - beq L11AA - dec $67 +.proc on_up + jsr draw_current_line ; show current line + ldx current_entry + beq draw_current_line_inv + dec current_entry lda $25 cmp #$02 - bne L11AA - dec $73 - lda #$16 - bne L11A7 + bne draw_current_line_inv + dec current_line + lda #$16 ; code output ??? + bne draw_current_line_with_char +.endproc -on_down: - jsr L1277 - ldx $67 +.proc on_down + jsr draw_current_line + ldx current_entry inx - cpx $68 - bcs L11AA - stx $67 + cpx num_entries + bcs draw_current_line_inv + stx current_entry lda $25 - cmp #$15 - bne L11AA - inc $73 - lda #$17 + cmp #rows_per_screen + bne draw_current_line_inv + inc current_line + lda #$17 ; code output ??? + ;; fall through +.endproc + +draw_current_line_with_char: + jsr COUT + +draw_current_line_inv: + jsr SETINV + jsr draw_current_line + ;; fall through + +;;; ------------------------------------------------------------ -L11A7: jsr COUT -L11AA: jsr SETINV - jsr L1277 keyboard_loop: lda KBD bpl keyboard_loop sta KBDSTRB jsr SETNORM - ldx $68 + ldx num_entries beq L11CB - cmp #$8D ; Return + cmp #HI(ASCII_RETURN) beq on_return - cmp #$8A ; Down Arrow + cmp #HI(ASCII_DOWN) beq on_down - cmp #$8B ; Up Arrow + cmp #HI(ASCII_UP) beq on_up -L11CB: cmp #$89 ; Tab +L11CB: cmp #HI(ASCII_TAB) beq next_drive - cmp #$9B ; Esc + cmp #HI(ASCII_ESCAPE) bne keyboard_loop jsr L11DA @@ -280,7 +328,7 @@ L11F1: jmp L1059 on_return: MLI_CALL SET_PREFIX, set_prefix_params bcs next_drive - ldx $67 + ldx current_entry jsr L1258 ldx prefix @@ -292,10 +340,12 @@ on_return: bcc :- stx prefix - ldy $67 + ldy current_entry lda $74,y bpl L11F0 ; is directory??? +;;; ------------------------------------------------------------ + .proc launch_sys_file jsr MON_SETTXT jsr MON_HOME @@ -317,7 +367,10 @@ on_return: jmp read_buffer ; Invoke the loaded code .endproc -L124A: sta $24 +;;; ------------------------------------------------------------ + +cout_string_hpos: + sta ZP_HPOS cout_string: lda help_string,y @@ -347,12 +400,13 @@ L1258: stz $6D sta $69 rts -L1277: lda #$02 +draw_current_line: + lda #$02 sta $057B - ldx $67 + ldx current_entry txa sec - sbc $73 + sbc current_line inc a inc a jsr MON_TABV @@ -378,21 +432,18 @@ L12AD: lda #$99 L12AF: ora #$80 L12B1: jmp COUT +;;; ------------------------------------------------------------ + .proc do_read MLI_CALL READ, read_params rts .endproc - .macro HIASCII arg - .repeat .strlen(arg), i - .byte .strat(arg, i) | $80 - .endrep -.endmacro +;;; ------------------------------------------------------------ string_start := * .proc help_string - HIASCII "RETURN: Select | TAB: Chg Vol | ESC: Back" - .byte 0 ; null terminated + HIASCIIZ "RETURN: Select | TAB: Chg Vol | ESC: Back" .endproc ;; Mousetext sequence: Enable, folder left, folder right, disable @@ -401,6 +452,8 @@ L12B1: jmp COUT .byte 0 ; null terminated .endproc +;;; ------------------------------------------------------------ + .proc open_params params: .byte 3 path: .addr prefix @@ -436,6 +489,8 @@ trans: .word 0 read_params_ref_num := read_params::ref_num read_params_request := read_params::request +;;; ------------------------------------------------------------ + .res 192, 0 .byte $00,$00,$00,$00,$00,$00,$00,$00 .byte $00,$00,$00,$00,$00,$00,$00,$00 @@ -450,16 +505,22 @@ trans: .word 0 .assert .sizeof(bbb) = $3FF, error, "Expected size is $3FF" .org $2402 -install_and_quit: +;;; ------------------------------------------------------------ + +.proc install_and_quit jsr install - MLI_CALL QUIT, quit_params -.proc quit_params + MLI_CALL QUIT, params + +.proc params params: .byte 4 type: .byte 0 res1: .word 0 res2: .byte 0 res3: .addr 0 .endproc +.endproc + +;;; ------------------------------------------------------------ .proc install src := install_src From ba96487609c376aee429486041c421d1f3ba0e5b Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 09:29:35 -0800 Subject: [PATCH 05/34] more identifications --- b.s | 102 +++++++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 70 insertions(+), 32 deletions(-) diff --git a/b.s b/b.s index 3eecdb9..f0da59e 100644 --- a/b.s +++ b/b.s @@ -26,6 +26,9 @@ SETINV := $FE80 SETNORM := $FE84 ZP_HPOS := $24 +ZP_TMASK := $32 + +COL80HPOS := $057B ASCII_TAB := $9 @@ -69,8 +72,10 @@ L2000: jmp install_and_quit current_entry := $67 num_entries := $68 - rows_per_screen := 21 - current_line := $73 + page_start := $73 + + top_row := 2 + bottom_row := 21 cld lda ROMINNW @@ -224,15 +229,15 @@ L1129: MLI_CALL CLOSE, close_params ldx #0 : lda prefix+1,x beq L1153 - jsr L12AF + jsr ascii_cout inx bne :- L1153: stz current_entry - stz current_line + stz page_start lda num_entries beq keyboard_loop - cmp #rows_per_screen + cmp #bottom_row bcc L1161 lda #$14 L1161: sta $6A @@ -249,19 +254,23 @@ L116F: jsr draw_current_line stz current_entry beq draw_current_line_inv +;;; ------------------------------------------------------------ + .proc on_up jsr draw_current_line ; show current line ldx current_entry - beq draw_current_line_inv - dec current_entry + beq draw_current_line_inv ; first one? just redraw + dec current_entry ; go to previous lda $25 - cmp #$02 + cmp #top_row bne draw_current_line_inv - dec current_line + dec page_start lda #$16 ; code output ??? bne draw_current_line_with_char .endproc +;;; ------------------------------------------------------------ + .proc on_down jsr draw_current_line ldx current_entry @@ -270,13 +279,15 @@ L116F: jsr draw_current_line bcs draw_current_line_inv stx current_entry lda $25 - cmp #rows_per_screen + cmp #bottom_row bne draw_current_line_inv - inc current_line + inc page_start lda #$17 ; code output ??? ;; fall through .endproc +;;; ------------------------------------------------------------ + draw_current_line_with_char: jsr COUT @@ -287,28 +298,38 @@ draw_current_line_inv: ;;; ------------------------------------------------------------ - -keyboard_loop: +.proc keyboard_loop lda KBD bpl keyboard_loop sta KBDSTRB jsr SETNORM ldx num_entries - beq L11CB + beq :+ ; no up/down/return if empty + cmp #HI(ASCII_RETURN) beq on_return cmp #HI(ASCII_DOWN) beq on_down cmp #HI(ASCII_UP) beq on_up -L11CB: cmp #HI(ASCII_TAB) + +: cmp #HI(ASCII_TAB) beq next_drive cmp #HI(ASCII_ESCAPE) bne keyboard_loop + ;; fall through +.endproc +;;; ------------------------------------------------------------ + +.proc on_escape jsr L11DA dec $6B bra L11F1 +.endproc + +;;; ------------------------------------------------------------ + L11DA: ldx prefix L11DD: dex lda prefix,x @@ -325,7 +346,9 @@ next_drive: L11F0: inx L11F1: jmp L1059 -on_return: +;;; ------------------------------------------------------------ + +.proc on_return MLI_CALL SET_PREFIX, set_prefix_params bcs next_drive ldx current_entry @@ -343,6 +366,10 @@ on_return: ldy current_entry lda $74,y bpl L11F0 ; is directory??? + ;; nope, system file, so... + + ;; fall through +.endproc ;;; ------------------------------------------------------------ @@ -372,14 +399,18 @@ on_return: cout_string_hpos: sta ZP_HPOS -cout_string: +.proc cout_string lda help_string,y - beq L1257 + beq done jsr COUT iny bne cout_string -L1257: rts +done: rts +.endproc +;;; ------------------------------------------------------------ + + ;; Compute offset to name in directory listing ??? L1258: stz $6D txa asl a @@ -400,37 +431,44 @@ L1258: stz $6D sta $69 rts +;;; ------------------------------------------------------------ + draw_current_line: - lda #$02 - sta $057B - ldx current_entry + lda #2 ; hpos = 2 + sta COL80HPOS + + ldx current_entry ; vpos = entry - page_start + 2 txa sec - sbc current_line + sbc page_start inc a inc a jsr MON_TABV + lda $74,x bmi L1299 - stz $057B - lda $32 + stz COL80HPOS + lda ZP_TMASK pha ldy #(folder_string - string_start) ; Draw folder glyphs jsr cout_string pla - sta $32 + sta ZP_TMASK L1299: jsr L12A9 jsr L1258 L129F: iny lda ($6C),y - jsr L12AF + jsr ascii_cout cpy $69 bcc L129F -L12A9: lda #$A0 - bne L12B1 -L12AD: lda #$99 -L12AF: ora #$80 -L12B1: jmp COUT +L12A9: lda #HI(' ') + bne cout ; implicit RTS +L12AD: lda #$99 ; Ctrl+Y ?? + + ;; Sets high bit before calling COUT +ascii_cout: + ora #$80 +cout: jmp COUT ;;; ------------------------------------------------------------ From 00a227534653da05e3efd7e9640f79a04000f073 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 13:00:27 -0800 Subject: [PATCH 06/34] more ids --- b.s | 189 ++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 113 insertions(+), 76 deletions(-) diff --git a/b.s b/b.s index f0da59e..1de6828 100644 --- a/b.s +++ b/b.s @@ -6,6 +6,8 @@ L0060 := $0060 +RESETVEC := $3F2 + RAMRDOFF := $C002 RAMRDON := $C003 RAMWRTOFF := $C004 @@ -25,16 +27,20 @@ COUT := $FDED SETINV := $FE80 SETNORM := $FE84 -ZP_HPOS := $24 -ZP_TMASK := $32 - COL80HPOS := $057B +;;; ProDOS +BITMAP := $BF58 +BITMAP_SIZE := $18 +;;; ASCII ASCII_TAB := $9 -ASCII_DOWN := $A -ASCII_UP := $B -ASCII_RETURN := $D +ASCII_DOWN := $A ; down arrow +ASCII_UP := $B ; up arrow +ASCII_CR := $D +ASCII_SYN := $16 ; scroll up +ASCII_ETB := $17 ; scroll down +ASCII_EM := $19 ; move cursor to upper left ASCII_ESCAPE := $1B ;;; ------------------------------------------------------------ @@ -52,6 +58,8 @@ ASCII_ESCAPE := $1B .byte 0 .endmacro +;;; ------------------------------------------------------------ +;;; Entry point ;;; ------------------------------------------------------------ ;; Loads at $2000 but executed at $1000. @@ -61,35 +69,50 @@ ASCII_ESCAPE := $1B L2000: jmp install_and_quit install_src := * +;;; ------------------------------------------------------------ +;;; Selector +;;; ------------------------------------------------------------ + .org $1000 .proc bbb - prefix := $280 ; length-prefixed - ;; filenames at $1400 - each is length byte + 15 byte buffer + prefix := $280 ; length-prefixed - read_buffer := $2000 ; Also, start location for launched SYS files + filenames := $1400 ; each is length + 15 bytes + read_buffer := $2000 ; Also, start location for launched SYS files + current_entry := $67 ; index of current entry + num_entries := $68 ; length of |filenames| - current_entry := $67 - num_entries := $68 - page_start := $73 + curr_len := $69 ; length of current entry name + curr_ptr := $6C ; address of current entry name (in |filenames|) - top_row := 2 - bottom_row := 21 + page_start := $73 ; index of first entry shown on screen + + top_row := 2 ; first row used on screen + bottom_row := 21 ; last row used on screen + +;;; ------------------------------------------------------------ + + cld ; ProDOS protocol for QUIT routine + lda ROMINNW ; Page in ROM for reads, writes ignored + + ;; Point reset vector at this routine + stz RESETVEC + lda #>bbb + sta RESETVEC+1 - cld - lda ROMINNW - stz $03F2 - lda #$10 - sta $03F3 jsr SETPWRC lda #$A0 - jsr LC300 - ldx #$17 -L1016: stz $BF58,x + jsr LC300 ; Activate 80-Column Firmware + + ;; Update system bitmap + ldx #BITMAP_SIZE-1 ; zero it all out +: stz BITMAP,x ; zero it all out... dex - bpl L1016 - inc $BF6F + bpl :- + inc BITMAP+BITMAP_SIZE-1 ; protect global page itself + lda #$CF sta $BF58 lda #$02 @@ -154,7 +177,7 @@ L109A: lda $2023,x lda $70 ora $71 bne L10B5 -L10B3: bra L1129 +L10B3: bra finish_read L10B5: bit $71 bmi L10B3 L10B9: lda $63 @@ -196,28 +219,29 @@ L10F8: ror $201E bne L10B5 L1108: ldx num_entries cpx #$80 - bcs L1129 + bcs finish_read sta $74,x - jsr L1258 + jsr update_curr_ptr ldy #$0F L1115: lda read_buffer,y - sta ($6C),y + sta (curr_ptr),y dey bpl L1115 iny and #$0F - sta ($6C),y + sta (curr_ptr),y inc num_entries bne L10B5 L1126: jmp L1032 -L1129: MLI_CALL CLOSE, close_params +finish_read: + MLI_CALL CLOSE, close_params bcs L1126 - ;; TEXT : HOME : VTAB 23 - jsr MON_SETTXT - jsr MON_HOME - lda #23 ; line 23 +draw_screen: + jsr MON_SETTXT ; TEXT + jsr MON_HOME ; HOME + lda #23 ; VTAB 23 jsr MON_TABV ;; Print help text @@ -225,7 +249,8 @@ L1129: MLI_CALL CLOSE, close_params lda #20 ; HTAB 20 jsr cout_string_hpos - jsr L12AD + ;; Draw prefix + jsr home ldx #0 : lda prefix+1,x beq L1153 @@ -257,32 +282,36 @@ L116F: jsr draw_current_line ;;; ------------------------------------------------------------ .proc on_up - jsr draw_current_line ; show current line + jsr draw_current_line ; clear inverse selection + ldx current_entry beq draw_current_line_inv ; first one? just redraw dec current_entry ; go to previous - lda $25 - cmp #top_row - bne draw_current_line_inv - dec page_start - lda #$16 ; code output ??? + + lda CV + cmp #top_row ; at the top? + bne draw_current_line_inv ; if not, just draw + dec page_start ; yes, adjust page and + lda #ASCII_SYN ; scroll screen up bne draw_current_line_with_char .endproc ;;; ------------------------------------------------------------ .proc on_down - jsr draw_current_line + jsr draw_current_line ; clear inverse selection + ldx current_entry inx - cpx num_entries - bcs draw_current_line_inv - stx current_entry - lda $25 - cmp #bottom_row - bne draw_current_line_inv - inc page_start - lda #$17 ; code output ??? + cpx num_entries ; past the limit? + bcs draw_current_line_inv ; yes, just redraw + stx current_entry ; go to next + + lda CV + cmp #bottom_row ; at the bottom? + bne draw_current_line_inv ; if not, just draw + inc page_start ; yes, adjust page and + lda #ASCII_ETB ; scroll screen down ;; fall through .endproc @@ -306,7 +335,7 @@ draw_current_line_inv: ldx num_entries beq :+ ; no up/down/return if empty - cmp #HI(ASCII_RETURN) + cmp #HI(ASCII_CR) beq on_return cmp #HI(ASCII_DOWN) beq on_down @@ -352,14 +381,14 @@ L11F1: jmp L1059 MLI_CALL SET_PREFIX, set_prefix_params bcs next_drive ldx current_entry - jsr L1258 + jsr update_curr_ptr ldx prefix : iny - lda ($6C),y + lda (curr_ptr),y inx sta prefix,x - cpy $69 + cpy curr_len bcc :- stx prefix @@ -397,7 +426,7 @@ L11F1: jmp L1059 ;;; ------------------------------------------------------------ cout_string_hpos: - sta ZP_HPOS + sta CH .proc cout_string lda help_string,y @@ -410,26 +439,30 @@ done: rts ;;; ------------------------------------------------------------ - ;; Compute offset to name in directory listing ??? -L1258: stz $6D +;; Compute address/length of curr_ptr/curr_len +;; Call with entry index in X. + +.proc update_curr_ptr + stz curr_ptr+1 txa asl a - rol $6D + rol curr_ptr+1 asl a - rol $6D + rol curr_ptr+1 asl a - rol $6D + rol curr_ptr+1 asl a - rol $6D - sta $6C - lda #$14 + rol curr_ptr+1 + sta curr_ptr + lda #>filenames clc - adc $6D - sta $6D - ldy #$00 - lda ($6C),y - sta $69 + adc curr_ptr+1 + sta curr_ptr+1 + ldy #0 + lda (curr_ptr),y + sta curr_len rts +.endproc ;;; ------------------------------------------------------------ @@ -448,22 +481,24 @@ draw_current_line: lda $74,x bmi L1299 stz COL80HPOS - lda ZP_TMASK + lda INVFLG pha ldy #(folder_string - string_start) ; Draw folder glyphs jsr cout_string pla - sta ZP_TMASK -L1299: jsr L12A9 - jsr L1258 + sta INVFLG +L1299: jsr space + jsr update_curr_ptr L129F: iny - lda ($6C),y + lda (curr_ptr),y jsr ascii_cout - cpy $69 + cpy curr_len bcc L129F -L12A9: lda #HI(' ') + +space: lda #HI(' ') bne cout ; implicit RTS -L12AD: lda #$99 ; Ctrl+Y ?? + +home: lda #HI(ASCII_EM) ; move cursor to top left ;; Sets high bit before calling COUT ascii_cout: @@ -544,6 +579,8 @@ trans: .word 0 .org $2402 ;;; ------------------------------------------------------------ +;;; Installer +;;; ------------------------------------------------------------ .proc install_and_quit jsr install From 1d974dcf3470cb087c45722dab00ac38aa350cd2 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 13:11:36 -0800 Subject: [PATCH 07/34] Make padding calc dynamic --- b.s | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/b.s b/b.s index 1de6828..2cf2ad8 100644 --- a/b.s +++ b/b.s @@ -564,24 +564,18 @@ trans: .word 0 ;;; ------------------------------------------------------------ - .res 192, 0 - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $00,$00,$00,$00,$00,$00,$00,$00 - .byte $00,$00,$48,$AD + .res $13FF-*-2, 0 + .byte $48,$AD ; 72, 173 ??? .endproc .assert .sizeof(bbb) = $3FF, error, "Expected size is $3FF" - .org $2402 ;;; ------------------------------------------------------------ ;;; Installer ;;; ------------------------------------------------------------ + .org $2402 + .proc install_and_quit jsr install MLI_CALL QUIT, params @@ -600,7 +594,7 @@ res3: .addr 0 .proc install src := install_src end := install_src + .sizeof(bbb) - dst := $D100 ; Install location in ProDOS + dst := $D100 ; Install location in ProDOS (bank 2) src_ptr := $19 dst_ptr := $1B From dd6a4b319eea459fd5581af9f5e013d2898805ab Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 14:11:29 -0800 Subject: [PATCH 08/34] prodos global page, devices --- b.s | 108 ++++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 39 deletions(-) diff --git a/b.s b/b.s index 2cf2ad8..fd69ca1 100644 --- a/b.s +++ b/b.s @@ -4,8 +4,6 @@ .include "apple2.inc" .include "prodos.inc" -L0060 := $0060 - RESETVEC := $3F2 RAMRDOFF := $C002 @@ -31,7 +29,10 @@ COL80HPOS := $057B ;;; ProDOS BITMAP := $BF58 -BITMAP_SIZE := $18 +BITMAP_SIZE := $18 ; Bits for pages $00 to $BF +DEVNUM := $BF30 ; Most recent accessed device +DEVCNT := $BF31 ; Number of on-line devices minus 1 +DEVLST := $BF32 ; Up to 14 units ;;; ASCII ASCII_TAB := $9 @@ -58,6 +59,16 @@ ASCII_ESCAPE := $1B .byte 0 .endmacro + +;;; ------------------------------------------------------------ + +;;; ProDOS Technical Reference Manual, 5.1.5.2: +;;; +;;; ProDOS MLI call $65, the QUIT call, moves addresses $D100 through +;;; $D3FF from the second 4K bank of RAM of the language card to +;;; $1000, and executes a JMP to $1000. What initially resides in that +;;; area is Apple's dispatcher code. + ;;; ------------------------------------------------------------ ;;; Entry point ;;; ------------------------------------------------------------ @@ -81,14 +92,24 @@ L2000: jmp install_and_quit filenames := $1400 ; each is length + 15 bytes read_buffer := $2000 ; Also, start location for launched SYS files + mark_params := $60 + mark_ref_num := $61 + mark_position := $62 ; 3-bytes + + next_device := $65 ; next device number to try + current_entry := $67 ; index of current entry num_entries := $68 ; length of |filenames| + curr_len := $69 ; length of current entry name curr_ptr := $6C ; address of current entry name (in |filenames|) page_start := $73 ; index of first entry shown on screen + max_entries := 128 ; max # of entries; more are ignored + types_table := $74 ; high bit clear = dir, set = sys + top_row := 2 ; first row used on screen bottom_row := 21 ; last row used on screen @@ -108,34 +129,39 @@ L2000: jmp install_and_quit ;; Update system bitmap ldx #BITMAP_SIZE-1 ; zero it all out -: stz BITMAP,x ; zero it all out... +: stz BITMAP,x dex bpl :- - inc BITMAP+BITMAP_SIZE-1 ; protect global page itself + inc BITMAP+BITMAP_SIZE-1 ; protect ProDOS global page + lda #%11001111 ; protect zp, stack, text page 1 + sta BITMAP - lda #$CF - sta $BF58 - lda #$02 - sta L0060 - ldx $BF31 - stx $65 - lda $BF30 + ;; Find device + lda #2 + sta $60 + ldx DEVCNT ; max device num + stx next_device + lda DEVNUM bne L1042 -L1032: ldx $65 - lda $BF32,x - cpx #$01 - bcs L103F - ldx $BF31 + +check_device: + ldx next_device + lda DEVLST,x + cpx #1 + bcs :+ + ldx DEVCNT inx -L103F: dex - stx $65 +: dex + stx next_device + L1042: sta on_line_params_unit MLI_CALL ON_LINE, on_line_params - bcs L1032 + bcs check_device + stz $6B lda prefix+1 and #$0F - beq L1032 + beq check_device adc #$02 tax @@ -148,7 +174,7 @@ L1059: stx prefix ; truncate prefix to length x MLI_CALL OPEN, open_params bcc L107F lda $6B - beq L1032 + beq check_device jsr BELL1 jsr L11DA stx prefix @@ -158,7 +184,7 @@ L107F: inc $6B ; ??? stz num_entries lda open_params_ref_num sta read_params_ref_num - sta $61 + sta mark_ref_num lda #$2B sta read_params_request stz read_params_request+1 @@ -172,25 +198,25 @@ L109A: lda $2023,x sta read_params_request lda #$01 sta $72 - stz $63 - stz $64 + stz mark_position+1 + stz mark_position+2 lda $70 ora $71 bne L10B5 L10B3: bra finish_read L10B5: bit $71 bmi L10B3 -L10B9: lda $63 +L10B9: lda mark_position+1 and #$FE - sta $63 + sta mark_position+1 ldy $72 lda #$00 cpy $6F bcc L10CE tay sty $72 - inc $63 -L10CC: inc $63 + inc mark+position+1 +L10CC: inc mark_position+1 L10CE: dey clc bmi L10D8 @@ -198,8 +224,8 @@ L10CE: dey bcc L10CE bcs L10CC L10D8: adc #$04 - sta $62 - MLI_CALL SET_MARK, L0060 + sta mark_position + MLI_CALL SET_MARK, mark_params bcs L10B3 jsr do_read bcs L10B3 @@ -218,9 +244,9 @@ L10F8: ror $201E cmp #$FF bne L10B5 L1108: ldx num_entries - cpx #$80 + cpx #max_entries bcs finish_read - sta $74,x + sta types_table,x jsr update_curr_ptr ldy #$0F L1115: lda read_buffer,y @@ -232,7 +258,7 @@ L1115: lda read_buffer,y sta (curr_ptr),y inc num_entries bne L10B5 -L1126: jmp L1032 +L1126: jmp check_device finish_read: MLI_CALL CLOSE, close_params @@ -370,7 +396,7 @@ L11DD: dex L11EC: rts next_drive: - jmp L1032 + jmp check_device L11F0: inx L11F1: jmp L1059 @@ -393,7 +419,7 @@ L11F1: jmp L1059 stx prefix ldy current_entry - lda $74,y + lda types_table,y bpl L11F0 ; is directory??? ;; nope, system file, so... @@ -478,8 +504,10 @@ draw_current_line: inc a jsr MON_TABV - lda $74,x - bmi L1299 + lda types_table,x + bmi name ; is sys file? + + ;; Draw folder glyph stz COL80HPOS lda INVFLG pha @@ -487,7 +515,9 @@ draw_current_line: jsr cout_string pla sta INVFLG -L1299: jsr space + + ;; Draw the name +name: jsr space jsr update_curr_ptr L129F: iny lda (curr_ptr),y From 714c796605fae324ab1f9c73b0757e7b9dd1d862 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 14:28:54 -0800 Subject: [PATCH 09/34] open and prefix --- b.s | 79 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 45 insertions(+), 34 deletions(-) diff --git a/b.s b/b.s index fd69ca1..d115174 100644 --- a/b.s +++ b/b.s @@ -96,17 +96,16 @@ L2000: jmp install_and_quit mark_ref_num := $61 mark_position := $62 ; 3-bytes - next_device := $65 ; next device number to try + next_device_num := $65 ; next device number to try current_entry := $67 ; index of current entry num_entries := $68 ; length of |filenames| - - curr_len := $69 ; length of current entry name curr_ptr := $6C ; address of current entry name (in |filenames|) - page_start := $73 ; index of first entry shown on screen + prefix_depth := $6B ; 0 = root + max_entries := 128 ; max # of entries; more are ignored types_table := $74 ; high bit clear = dir, set = sys @@ -140,47 +139,53 @@ L2000: jmp install_and_quit lda #2 sta $60 ldx DEVCNT ; max device num - stx next_device + stx next_device_num lda DEVNUM - bne L1042 + bne check_device -check_device: - ldx next_device +next_device: + ldx next_device_num lda DEVLST,x cpx #1 bcs :+ ldx DEVCNT inx : dex - stx next_device + stx next_device_num -L1042: sta on_line_params_unit +check_device: + sta on_line_params_unit MLI_CALL ON_LINE, on_line_params - bcs check_device + bcs next_device - stz $6B + stz prefix_depth lda prefix+1 and #$0F - beq check_device + beq next_device adc #$02 tax -L1059: stx prefix ; truncate prefix to length x + ;; Resize prefix to length x and open the directory for reading +resize_prefix_and_open: + stx prefix lda #'/' sta prefix+1 sta prefix,x stz prefix+1,x MLI_CALL OPEN, open_params - bcc L107F - lda $6B - beq check_device - jsr BELL1 - jsr L11DA + bcc :+ + + ;; Open failed + lda prefix_depth ; root? + beq next_device + jsr BELL1 ; no, but failed; beep + jsr pop_prefix ; and go up a level stx prefix jmp keyboard_loop -L107F: inc $6B ; ??? + ;; Open succeeded +: inc prefix_depth stz num_entries lda open_params_ref_num sta read_params_ref_num @@ -215,7 +220,7 @@ L10B9: lda mark_position+1 bcc L10CE tay sty $72 - inc mark+position+1 + inc mark_position+1 L10CC: inc mark_position+1 L10CE: dey clc @@ -258,7 +263,7 @@ L1115: lda read_buffer,y sta (curr_ptr),y inc num_entries bne L10B5 -L1126: jmp check_device +L1126: jmp next_device finish_read: MLI_CALL CLOSE, close_params @@ -378,28 +383,34 @@ draw_current_line_inv: ;;; ------------------------------------------------------------ .proc on_escape - jsr L11DA - dec $6B - bra L11F1 + jsr pop_prefix ; leaves length in X + dec prefix_depth + bra resize_prefix_and_open_jmp .endproc ;;; ------------------------------------------------------------ -L11DA: ldx prefix -L11DD: dex + ;; Remove level from prefix; returns new length in X +.proc pop_prefix + ldx prefix +loop: dex lda prefix,x cmp #'/' - bne L11DD + bne loop cpx #$01 - bne L11EC + bne done ldx prefix -L11EC: rts +done: rts +.endproc next_drive: - jmp check_device + jmp next_device -L11F0: inx -L11F1: jmp L1059 +dec_resize_prefix_and_open: + inx + +resize_prefix_and_open_jmp: + jmp resize_prefix_and_open ;;; ------------------------------------------------------------ @@ -420,7 +431,7 @@ L11F1: jmp L1059 ldy current_entry lda types_table,y - bpl L11F0 ; is directory??? + bpl dec_resize_prefix_and_open ; is directory??? ;; nope, system file, so... ;; fall through From 589bc096053690e1879c6ee969fc98c6616148bd Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 14:49:16 -0800 Subject: [PATCH 10/34] more labels --- b.s | 93 +++++++++++++++++++++++++++++++++++++------------------------ 1 file changed, 57 insertions(+), 36 deletions(-) diff --git a/b.s b/b.s index d115174..c34877b 100644 --- a/b.s +++ b/b.s @@ -14,7 +14,7 @@ ALTZPOFF := $C008 ALTZPON := $C009 ROMINNW := $C082 ROMINWB1 := $C089 -LC300 := $C300 +SLOT3 := $C300 MON_SETTXT := $FB39 MON_TABV := $FB5B @@ -39,6 +39,7 @@ ASCII_TAB := $9 ASCII_DOWN := $A ; down arrow ASCII_UP := $B ; up arrow ASCII_CR := $D +ASCII_RIGHT := $15 ; right arrow ASCII_SYN := $16 ; scroll up ASCII_ETB := $17 ; scroll down ASCII_EM := $19 ; move cursor to upper left @@ -77,7 +78,7 @@ ASCII_ESCAPE := $1B .org $2000 -L2000: jmp install_and_quit + jmp install_and_quit install_src := * ;;; ------------------------------------------------------------ @@ -124,7 +125,7 @@ L2000: jmp install_and_quit jsr SETPWRC lda #$A0 - jsr LC300 ; Activate 80-Column Firmware + jsr SLOT3 ; Activate 80-Column Firmware ;; Update system bitmap ldx #BITMAP_SIZE-1 ; zero it all out @@ -162,11 +163,11 @@ check_device: lda prefix+1 and #$0F beq next_device - adc #$02 + adc #2 tax ;; Resize prefix to length x and open the directory for reading -resize_prefix_and_open: +.proc resize_prefix_and_open stx prefix lda #'/' sta prefix+1 @@ -184,18 +185,22 @@ resize_prefix_and_open: stx prefix jmp keyboard_loop + + directory_header_size := $2B + ;; Open succeeded : inc prefix_depth stz num_entries lda open_params_ref_num sta read_params_ref_num sta mark_ref_num - lda #$2B + lda #directory_header_size sta read_params_request stz read_params_request+1 jsr do_read bcs L10B3 - ldx #$03 + + ldx #3 L109A: lda $2023,x sta $6E,x dex @@ -208,7 +213,9 @@ L109A: lda $2023,x lda $70 ora $71 bne L10B5 + L10B3: bra finish_read + L10B5: bit $71 bmi L10B3 L10B9: lda mark_position+1 @@ -253,23 +260,29 @@ L1108: ldx num_entries bcs finish_read sta types_table,x jsr update_curr_ptr - ldy #$0F -L1115: lda read_buffer,y + + ldy #$0F ; name length +: lda read_buffer,y sta (curr_ptr),y dey - bpl L1115 - iny + bpl :- + + iny ; Y = 0 and #$0F - sta (curr_ptr),y + sta (curr_ptr),y ; store length inc num_entries bne L10B5 -L1126: jmp next_device +next: jmp next_device finish_read: MLI_CALL CLOSE, close_params - bcs L1126 + bcs next + ;; fall through +.endproc -draw_screen: +;;; ------------------------------------------------------------ + +.proc draw_screen jsr MON_SETTXT ; TEXT jsr MON_HOME ; HOME lda #23 ; VTAB 23 @@ -284,31 +297,35 @@ draw_screen: jsr home ldx #0 : lda prefix+1,x - beq L1153 + beq :+ jsr ascii_cout inx bne :- -L1153: stz current_entry +: stz current_entry stz page_start lda num_entries - beq keyboard_loop - cmp #bottom_row - bcc L1161 - lda #$14 -L1161: sta $6A - lda #$02 - sta $22 - sta $20 - lda #$16 - sta $21 - sta $23 -L116F: jsr draw_current_line + beq keyboard_loop ; no entries (empty directory) + + row_count := $6A + + cmp #bottom_row ; more entries than fit? + bcc :+ + lda #(bottom_row - top_row + 1) +: sta row_count + lda #2 + sta WNDTOP + sta WNDLFT + lda #22 + sta WNDWDTH + sta WNDBTM +loop: jsr draw_current_line inc current_entry - dec $6A - bne L116F + dec row_count + bne loop stz current_entry beq draw_current_line_inv +.endproc ;;; ------------------------------------------------------------ @@ -397,12 +414,14 @@ loop: dex lda prefix,x cmp #'/' bne loop - cpx #$01 + cpx #1 bne done ldx prefix done: rts .endproc +;;; ------------------------------------------------------------ + next_drive: jmp next_device @@ -442,7 +461,7 @@ resize_prefix_and_open_jmp: .proc launch_sys_file jsr MON_SETTXT jsr MON_HOME - lda #$95 ; Right arrow + lda #HI(ASCII_RIGHT) ; Right arrow jsr COUT MLI_CALL OPEN, open_params @@ -503,7 +522,7 @@ done: rts ;;; ------------------------------------------------------------ -draw_current_line: +.proc draw_current_line lda #2 ; hpos = 2 sta COL80HPOS @@ -530,14 +549,16 @@ draw_current_line: ;; Draw the name name: jsr space jsr update_curr_ptr -L129F: iny +loop: iny lda (curr_ptr),y jsr ascii_cout cpy curr_len - bcc L129F + bcc loop space: lda #HI(' ') bne cout ; implicit RTS + ;; fall through +.endproc home: lda #HI(ASCII_EM) ; move cursor to top left From ece57e671c756261106e344deaad7243ef27c06a Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 16:06:31 -0800 Subject: [PATCH 11/34] read routines --- b.s | 123 +++++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 81 insertions(+), 42 deletions(-) diff --git a/b.s b/b.s index c34877b..edcb4c9 100644 --- a/b.s +++ b/b.s @@ -34,6 +34,27 @@ DEVNUM := $BF30 ; Most recent accessed device DEVCNT := $BF31 ; Number of on-line devices minus 1 DEVLST := $BF32 ; Up to 14 units +.scope DirectoryHeader + entry_length := $23 + entries_per_block := $24 + file_count := $25 + + size := $2B +.endscope + +.scope FileEntry + storage_type := $00 ; high nibble + name_length := $00 ; low nibble + file_name := $01 + file_type := $10 + access := $1E +.endscope + +.scope FileType + Directory := $0F + System := $FF +.endscope + ;;; ASCII ASCII_TAB := $9 ASCII_DOWN := $A ; down arrow @@ -107,6 +128,10 @@ ASCII_ESCAPE := $1B prefix_depth := $6B ; 0 = root + entry_length := $6E + entries_per_block := $6F + file_count := $70 ; 2 bytes + max_entries := 128 ; max # of entries; more are ignored types_table := $74 ; high bit clear = dir, set = sys @@ -186,44 +211,47 @@ check_device: jmp keyboard_loop - directory_header_size := $2B - ;; Open succeeded : inc prefix_depth stz num_entries lda open_params_ref_num sta read_params_ref_num sta mark_ref_num - lda #directory_header_size + lda #DirectoryHeader::size sta read_params_request stz read_params_request+1 jsr do_read - bcs L10B3 + bcs finish_read2 + ;; Store entry_length/entries_per_block/file_count ldx #3 -L109A: lda $2023,x - sta $6E,x +: lda read_buffer + DirectoryHeader::entry_length,x + sta entry_length,x dex - bpl L109A + bpl :- + sta read_params_request - lda #$01 - sta $72 + lda #1 + sta $72 ; ??? stz mark_position+1 stz mark_position+2 - lda $70 - ora $71 - bne L10B5 -L10B3: bra finish_read + lda file_count + ora file_count+1 + bne next_file_entry ; any files? -L10B5: bit $71 - bmi L10B3 -L10B9: lda mark_position+1 +finish_read2: + bra finish_read + +next_file_entry: + bit file_count+1 + bmi finish_read2 +floop: lda mark_position+1 and #$FE sta mark_position+1 ldy $72 - lda #$00 - cpy $6F + lda #0 + cpy entries_per_block bcc L10CE tay sty $72 @@ -232,46 +260,57 @@ L10CC: inc mark_position+1 L10CE: dey clc bmi L10D8 - adc $6E + adc entry_length bcc L10CE bcs L10CC -L10D8: adc #$04 +L10D8: adc #4 sta mark_position MLI_CALL SET_MARK, mark_params - bcs L10B3 + bcs finish_read2 jsr do_read - bcs L10B3 + bcs finish_read2 inc $72 - lda read_buffer - and #$F0 - beq L10B9 - dec $70 - bne L10F8 - dec $71 -L10F8: ror $201E - bcc L10B5 - lda $2010 - cmp #$0F - beq L1108 - cmp #$FF - bne L10B5 -L1108: ldx num_entries + lda read_buffer + FileEntry::storage_type + and #$F0 ; mask off storage_type + beq floop ; inactive file entry + dec file_count + bne :+ + dec file_count+1 + + ;; Check read access +: ror read_buffer + FileEntry::access + bcc next_file_entry + + ;; Check file type + lda read_buffer + FileEntry::file_type + cmp #FileType::Directory + beq :+ + cmp #FileType::System + bne next_file_entry + + ;; Check to see if we have room +: ldx num_entries cpx #max_entries bcs finish_read - sta types_table,x - jsr update_curr_ptr - ldy #$0F ; name length + ;; Store type + sta types_table,x + + ;; Copy name + jsr update_curr_ptr + ldy #$0F ; name length + 1 (includes length byte) : lda read_buffer,y sta (curr_ptr),y dey bpl :- - iny ; Y = 0 - and #$0F + and #$0F ; mask off name length (remove storage_type) sta (curr_ptr),y ; store length + + ;; Next inc num_entries - bne L10B5 + bne next_file_entry + next: jmp next_device finish_read: From 6a0a6c5ad936e99647353aff7f79e35bf74fd3cf Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 16:17:29 -0800 Subject: [PATCH 12/34] Finish labels --- b.s | 32 ++++++++++++++++++++------------ 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/b.s b/b.s index edcb4c9..2eed2b2 100644 --- a/b.s +++ b/b.s @@ -132,6 +132,8 @@ ASCII_ESCAPE := $1B entries_per_block := $6F file_count := $70 ; 2 bytes + entry_num := $72 + max_entries := 128 ; max # of entries; more are ignored types_table := $74 ; high bit clear = dir, set = sys @@ -232,7 +234,7 @@ check_device: sta read_params_request lda #1 - sta $72 ; ??? + sta entry_num ; ??? stz mark_position+1 stz mark_position+2 @@ -244,32 +246,38 @@ finish_read2: bra finish_read next_file_entry: - bit file_count+1 + bit file_count+1 ; wrap around? bmi finish_read2 + + + ;; TODO: The math here is mysterious; understand and document floop: lda mark_position+1 and #$FE sta mark_position+1 - ldy $72 + ldy entry_num lda #0 cpy entries_per_block - bcc L10CE + bcc :+ tay - sty $72 + sty entry_num + inc mark_position+1 -L10CC: inc mark_position+1 -L10CE: dey +carry: inc mark_position+1 +: dey clc - bmi L10D8 + bmi :+ adc entry_length - bcc L10CE - bcs L10CC -L10D8: adc #4 + bcc :- + bcs carry + +: adc #4 sta mark_position MLI_CALL SET_MARK, mark_params bcs finish_read2 jsr do_read bcs finish_read2 - inc $72 + + inc entry_num lda read_buffer + FileEntry::storage_type and #$F0 ; mask off storage_type beq floop ; inactive file entry From b7074e04f7835c2713951d5b93f862cf49bc3cfb Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 16:29:06 -0800 Subject: [PATCH 13/34] Move prodos defs to inc --- b.s | 79 ++++++++++++++++++++---------------------------------- prodos.inc | 60 ++++++++++++++++++++++++++++++++++------- 2 files changed, 79 insertions(+), 60 deletions(-) diff --git a/b.s b/b.s index 2eed2b2..0e3a1b9 100644 --- a/b.s +++ b/b.s @@ -4,65 +4,44 @@ .include "apple2.inc" .include "prodos.inc" +;;; Miscellaneous + RESETVEC := $3F2 -RAMRDOFF := $C002 -RAMRDON := $C003 -RAMWRTOFF := $C004 -RAMWRTON := $C005 -ALTZPOFF := $C008 -ALTZPON := $C009 -ROMINNW := $C082 -ROMINWB1 := $C089 +COL80HPOS := $57B + +;;; 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 +ROMINWB1 := $C089 ; Read ROM; write RAM bank 1 + SLOT3 := $C300 -MON_SETTXT := $FB39 -MON_TABV := $FB5B +;;; Monitor + +SETTXT := $FB39 +TABV := $FB5B SETPWRC := $FB6F BELL1 := $FBDD -MON_HOME := $FC58 +HOME := $FC58 COUT := $FDED SETINV := $FE80 SETNORM := $FE84 -COL80HPOS := $057B - -;;; ProDOS -BITMAP := $BF58 -BITMAP_SIZE := $18 ; Bits for pages $00 to $BF -DEVNUM := $BF30 ; Most recent accessed device -DEVCNT := $BF31 ; Number of on-line devices minus 1 -DEVLST := $BF32 ; Up to 14 units - -.scope DirectoryHeader - entry_length := $23 - entries_per_block := $24 - file_count := $25 - - size := $2B -.endscope - -.scope FileEntry - storage_type := $00 ; high nibble - name_length := $00 ; low nibble - file_name := $01 - file_type := $10 - access := $1E -.endscope - -.scope FileType - Directory := $0F - System := $FF -.endscope - -;;; ASCII +;;; ASCII/Key codes ASCII_TAB := $9 ASCII_DOWN := $A ; down arrow ASCII_UP := $B ; up arrow ASCII_CR := $D ASCII_RIGHT := $15 ; right arrow -ASCII_SYN := $16 ; scroll up -ASCII_ETB := $17 ; scroll down +ASCII_SYN := $16 ; scroll text window up +ASCII_ETB := $17 ; scroll text window down ASCII_EM := $19 ; move cursor to upper left ASCII_ESCAPE := $1B @@ -330,10 +309,10 @@ finish_read: ;;; ------------------------------------------------------------ .proc draw_screen - jsr MON_SETTXT ; TEXT - jsr MON_HOME ; HOME + jsr SETTXT ; TEXT + jsr HOME ; HOME lda #23 ; VTAB 23 - jsr MON_TABV + jsr TABV ;; Print help text ldy #0 @@ -506,8 +485,8 @@ resize_prefix_and_open_jmp: ;;; ------------------------------------------------------------ .proc launch_sys_file - jsr MON_SETTXT - jsr MON_HOME + jsr SETTXT + jsr HOME lda #HI(ASCII_RIGHT) ; Right arrow jsr COUT @@ -579,7 +558,7 @@ done: rts sbc page_start inc a inc a - jsr MON_TABV + jsr TABV lda types_table,x bmi name ; is sys file? diff --git a/prodos.inc b/prodos.inc index c5a3c42..49b4344 100644 --- a/prodos.inc +++ b/prodos.inc @@ -1,15 +1,24 @@ -;;; ------------------------------ +;;; ------------------------------------------------------------ ;;; ProDOS MLI -;;; ------------------------------ +;;; ------------------------------------------------------------ -;;; Entry point -MLI := $BF00 +;;; ------------------------------------------------------------ +;;; ProDOS Global Page -;;; Date/Time -DATELO := $BF90 -DATEHI := $BF91 -TIMELO := $BF92 -TIMEHI := $BF93 +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 +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 + + +;;; ------------------------------------------------------------ +;;; MLI Calls ;;; Housekeeping Calls CREATE := $C0 @@ -20,6 +29,7 @@ GET_FILE_INFO := $C4 ON_LINE := $C5 SET_PREFIX := $C6 GET_PREFIX := $C7 + ;;; Filing Calls OPEN := $C8 NEWLINE := $C9 @@ -33,16 +43,20 @@ 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 := $71 +;;; ------------------------------------------------------------ ;;; File Types + FT_TYPELESS := $00 FT_BAD := $01 FT_TEXT := $04 @@ -53,10 +67,36 @@ FT_BASIC := $FC FT_SYSTEM := $FF - +;;; ------------------------------------------------------------ ;;; Macros + .macro MLI_CALL op, addr jsr MLI .byte op .addr addr .endmacro + + +;;; ------------------------------------------------------------ +;;; Structures + +.scope DirectoryHeader + entry_length := $23 + entries_per_block := $24 + file_count := $25 + + size := $2B +.endscope + +.scope FileEntry + storage_type := $00 ; high nibble + name_length := $00 ; low nibble + file_name := $01 + file_type := $10 + access := $1E +.endscope + +.scope FileType + Directory := $0F + System := $FF +.endscope From 6df79416177a4dcef56be345cd764b51d20864eb Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 16:46:45 -0800 Subject: [PATCH 14/34] Rename to bbb --- .gitignore | 3 +++ Makefile | 2 +- b.s => bbb.s | 0 3 files changed, 4 insertions(+), 1 deletion(-) create mode 100644 .gitignore rename b.s => bbb.s (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..33b8f3f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +# Generated files +*.list +*.SYS \ No newline at end of file diff --git a/Makefile b/Makefile index 631a079..01399bf 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC65 = ~/dev/cc65/bin CAFLAGS = --target apple2enh --list-bytes 0 CCFLAGS = --config apple2-asm.cfg -TARGETS = b.SYS +TARGETS = bbb.SYS .PHONY: clean all all: $(TARGETS) diff --git a/b.s b/bbb.s similarity index 100% rename from b.s rename to bbb.s From 5e3d46373e157282a7a2a232938f71b730797288 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sat, 9 Dec 2017 16:50:35 -0800 Subject: [PATCH 15/34] Stamp SYS files with AuxType --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index 01399bf..a934e1a 100644 --- a/Makefile +++ b/Makefile @@ -19,3 +19,4 @@ clean: %.SYS: %.o $(CC65)/ld65 $(CCFLAGS) -o $@ $< + xattr -wx prodos.AuxType '00 20' $@ From 6eb9613a28541db95de86a233d9d6e3dac724f7b Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sun, 10 Dec 2017 20:22:34 -0800 Subject: [PATCH 16/34] More tidying, size assert --- Makefile | 2 +- bbb.s => bbb.system.s | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) rename bbb.s => bbb.system.s (98%) diff --git a/Makefile b/Makefile index a934e1a..30b08a1 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC65 = ~/dev/cc65/bin CAFLAGS = --target apple2enh --list-bytes 0 CCFLAGS = --config apple2-asm.cfg -TARGETS = bbb.SYS +TARGETS = bbb.system.SYS bbb2.system.SYS .PHONY: clean all all: $(TARGETS) diff --git a/bbb.s b/bbb.system.s similarity index 98% rename from bbb.s rename to bbb.system.s index 0e3a1b9..93e18db 100644 --- a/bbb.s +++ b/bbb.system.s @@ -103,15 +103,14 @@ ASCII_ESCAPE := $1B num_entries := $68 ; length of |filenames| curr_len := $69 ; length of current entry name curr_ptr := $6C ; address of current entry name (in |filenames|) - page_start := $73 ; index of first entry shown on screen prefix_depth := $6B ; 0 = root entry_length := $6E entries_per_block := $6F file_count := $70 ; 2 bytes - entry_num := $72 + page_start := $73 ; index of first entry shown on screen max_entries := 128 ; max # of entries; more are ignored types_table := $74 ; high bit clear = dir, set = sys @@ -128,8 +127,8 @@ ASCII_ESCAPE := $1B stz RESETVEC lda #>bbb sta RESETVEC+1 + jsr SETPWRC ; update validity check byte - jsr SETPWRC lda #$A0 jsr SLOT3 ; Activate 80-Column Firmware @@ -144,7 +143,7 @@ ASCII_ESCAPE := $1B ;; Find device lda #2 - sta $60 + sta mark_params ldx DEVCNT ; max device num stx next_device_num lda DEVNUM @@ -213,7 +212,7 @@ check_device: sta read_params_request lda #1 - sta entry_num ; ??? + sta entry_num stz mark_position+1 stz mark_position+2 @@ -451,7 +450,7 @@ done: rts next_drive: jmp next_device -dec_resize_prefix_and_open: +inc_resize_prefix_and_open: inx resize_prefix_and_open_jmp: @@ -476,7 +475,7 @@ resize_prefix_and_open_jmp: ldy current_entry lda types_table,y - bpl dec_resize_prefix_and_open ; is directory??? + bpl inc_resize_prefix_and_open ; is directory??? ;; nope, system file, so... ;; fall through @@ -511,11 +510,11 @@ cout_string_hpos: sta CH .proc cout_string - lda help_string,y +loop: lda help_string,y beq done jsr COUT iny - bne cout_string + bne loop done: rts .endproc @@ -650,6 +649,8 @@ trans: .word 0 read_params_ref_num := read_params::ref_num read_params_request := read_params::request + .assert read_params::request - bbb <= $300, error, "Must fit in $300 bytes" + ;;; ------------------------------------------------------------ .res $13FF-*-2, 0 From d74dec19b213415d275f30b431bc04dd3d5aa09d Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Mon, 11 Dec 2017 20:15:51 -0800 Subject: [PATCH 17/34] WIP variant --- bbb2.system.s | 740 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 740 insertions(+) create mode 100644 bbb2.system.s diff --git a/bbb2.system.s b/bbb2.system.s new file mode 100644 index 0000000..98fb2e6 --- /dev/null +++ b/bbb2.system.s @@ -0,0 +1,740 @@ +;;; Disassembly of BYE.SYSTEM (Bird's Better Bye) +;;; Additions by Joshua Bell inexorabletash@gmail.com + + .setcpu "65C02" + .include "apple2.inc" + .include "prodos.inc" + + .feature c_comments + +;;; Miscellaneous + +COL80HPOS := $57B + +;;; 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 +ROMINWB1 := $C089 ; Read ROM; write RAM bank 1 + +SLOT3 := $C300 + +;;; Monitor + +SETTXT := $FB39 +TABV := $FB5B +SETPWRC := $FB6F +BELL1 := $FBDD +HOME := $FC58 +COUT := $FDED +SETINV := $FE80 +SETNORM := $FE84 + +;;; ASCII/Key codes +ASCII_TAB := $9 +ASCII_DOWN := $A ; down arrow +ASCII_UP := $B ; up arrow +ASCII_CR := $D +ASCII_RIGHT := $15 ; right arrow +ASCII_SYN := $16 ; scroll text window up +ASCII_ETB := $17 ; scroll text window down +ASCII_EM := $19 ; move cursor to upper left +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 + + +;;; ------------------------------------------------------------ + +;;; ProDOS Technical Reference Manual, 5.1.5.2: +;;; +;;; ProDOS MLI call $65, the QUIT call, moves addresses $D100 through +;;; $D3FF from the second 4K bank of RAM of the language card to +;;; $1000, and executes a JMP to $1000. What initially resides in that +;;; area is Apple's dispatcher code. + +;;; ------------------------------------------------------------ +;;; Entry point +;;; ------------------------------------------------------------ + + ;; Loads at $2000 but executed at $1000. + .org $2000 + + jmp install_and_quit + install_src := * + +;;; ------------------------------------------------------------ +;;; Selector +;;; ------------------------------------------------------------ + + .org $1000 +.proc bbb + + prefix := $280 ; length-prefixed + + filenames := $1400 ; each is length + 15 bytes + read_buffer := $2000 ; Also, start location for launched SYS files + + mark_params := $60 + mark_ref_num := $61 + mark_position := $62 ; 3-bytes + next_device_num := $65 ; next device number to try + + current_entry := $67 ; index of current entry + num_entries := $68 ; length of |filenames| + curr_len := $69 ; length of current entry name + curr_ptr := $6C ; address of current entry name (in |filenames|) + + prefix_depth := $6B ; 0 = root + + entry_length := $6E + entries_per_block := $6F + file_count := $70 ; 2 bytes + + entry_num := $72 + page_start := $73 ; index of first entry shown on screen + + max_entries := 128 ; max # of entries; more are ignored + types_table := $74 ; high bit clear = dir, set = sys + + top_row := 2 ; first row used on screen + bottom_row := 21 ; last row used on screen + +;;; ------------------------------------------------------------ + + cld ; ProDOS protocol for QUIT routine + lda ROMINNW ; Page in ROM for reads, writes ignored + + lda #$A0 + jsr SLOT3 ; Activate 80-Column Firmware + + ;; Update system bitmap + ldx #BITMAP_SIZE-1 ; zero it all out +: stz BITMAP,x + dex + bpl :- + inc BITMAP+BITMAP_SIZE-1 ; protect ProDOS global page + lda #%11001111 ; protect zp, stack, text page 1 + sta BITMAP + + ;; Find device + lda #2 + sta mark_params + ldx DEVCNT ; max device num + stx next_device_num + lda DEVNUM + bne check_device + +next_device: + ldx next_device_num + lda DEVLST,x + cpx #1 + bcs :+ + ldx DEVCNT + inx +: dex + stx next_device_num + +check_device: + sta on_line_params_unit + MLI_CALL ON_LINE, on_line_params + bcs next_device + + stz prefix_depth + lda prefix+1 + and #$0F + beq next_device + adc #2 + tax + + ;; Resize prefix to length x and open the directory for reading +.proc resize_prefix_and_open + stx prefix + lda #'/' + sta prefix+1 + sta prefix,x + stz prefix+1,x + + jsr do_open + bcc :+ + + ;; Open failed + lda prefix_depth ; root? + beq next_device + jsr pop_prefix ; no, but failed; go up a level + stx prefix + jmp keyboard_loop + + ;; Open succeeded +: inc prefix_depth + stz num_entries + lda #DirectoryHeader::size + sta read_params_request + stz read_params_request+1 + jsr do_read + bcs finish_read2 + + ;; Store entry_length/entries_per_block/file_count + ldx #3 +: lda read_buffer + DirectoryHeader::entry_length,x + sta entry_length,x + dex + bpl :- + + sta read_params_request + lda #1 + sta entry_num + stz mark_position+1 + stz mark_position+2 + + lda file_count + ora file_count+1 + bne next_file_entry ; any files? + +finish_read2: + bra finish_read + +next_file_entry: + bit file_count+1 ; wrap around? + bmi finish_read2 + + + ;; TODO: The math here is mysterious; understand and document +floop: lda mark_position+1 + and #$FE + sta mark_position+1 + ldy entry_num + lda #0 + cpy entries_per_block + bcc :+ + tay + sty entry_num + + inc mark_position+1 +carry: inc mark_position+1 +: dey + clc + bmi :+ + adc entry_length + bcc :- + bcs carry + +: adc #4 + sta mark_position + MLI_CALL SET_MARK, mark_params + bcs finish_read2 + jsr do_read + bcs finish_read2 + + inc entry_num + lda read_buffer + FileEntry::storage_type + and #$F0 ; mask off storage_type + beq floop ; inactive file entry + dec file_count + bne :+ + dec file_count+1 + + ;; Check read access +: ror read_buffer + FileEntry::access + bcc next_file_entry + + ;; Check file type + lda read_buffer + FileEntry::file_type + cmp #FileType::Directory + beq :+ + cmp #FileType::System + bne next_file_entry + + ;; Check to see if we have room +: ldx num_entries + cpx #max_entries + bcs finish_read + + ;; Store type + sta types_table,x + + ;; Copy name + jsr update_curr_ptr + ldy #$0F ; name length + 1 (includes length byte) +: lda read_buffer,y + sta (curr_ptr),y + dey + bpl :- + iny ; Y = 0 + and #$0F ; mask off name length (remove storage_type) + sta (curr_ptr),y ; store length + + ;; Next + inc num_entries + bne next_file_entry + +next: jmp next_device + +finish_read: + MLI_CALL CLOSE, close_params + ;; fall through +.endproc + +;;; ------------------------------------------------------------ + +.proc draw_screen + jsr SETTXT ; TEXT + jsr HOME ; HOME + lda #23 ; VTAB 23 + jsr TABV + + ;; Print help text + lda #20 ; HTAB 20 + sta CH + ldy #0 ; index into string buffer + jsr cout_string + + ;; Draw prefix + jsr home + ldx #0 +: lda prefix+1,x + beq :+ + jsr ascii_cout + inx + bne :- + +: stz current_entry + stz page_start + lda num_entries + beq keyboard_loop ; no entries (empty directory) + + row_count := $6A + + cmp #bottom_row ; more entries than fit? + bcc :+ + lda #(bottom_row - top_row + 1) +: sta row_count + lda #2 + sta WNDTOP + sta WNDLFT + lda #22 + sta WNDWDTH + sta WNDBTM +loop: jsr draw_current_line + inc current_entry + dec row_count + bne loop + stz current_entry + beq draw_current_line_inv +.endproc + +;;; ------------------------------------------------------------ + + ;; Remove level from prefix; returns new length in X +.proc pop_prefix + ldx prefix +loop: dex + lda prefix,x + cmp #'/' + bne loop + cpx #1 + bne done + ldx prefix +done: + ;; Fall through... +.endproc + +handy_rts: + rts + +;;; ------------------------------------------------------------ + +.proc down_common + lda current_entry + inc a + cmp num_entries ; past the limit? + bcs handy_rts ; yes, just redraw + sta current_entry ; go to next + + lda CV + cmp #bottom_row ; at the bottom? + bne handy_rts + inc page_start ; yes, adjust page and + lda #ASCII_ETB ; scroll screen down + jmp COUT ; implicit rts +.endproc + +.proc on_down + jsr down_common + bra draw_current_line_inv +.endproc + +;;; ------------------------------------------------------------ + +.proc on_up + ldx current_entry + beq draw_current_line_inv ; first one? just redraw + dec current_entry ; go to previous + + lda CV + cmp #top_row ; at the top? + bne draw_current_line_inv ; if not, just draw + dec page_start ; yes, adjust page and + lda #ASCII_SYN ; scroll screen up + jsr cout + ;; fall through +.endproc + +;;; ------------------------------------------------------------ + +.proc on_alpha +loop: lda KBD + and #$5F ; make ASCII and uppercase + ldy #1 + cmp (curr_ptr),y ; key < first char ? + bcc draw_current_line_inv + + jsr down_common + bra loop +.endproc + +;;; ------------------------------------------------------------ + +draw_current_line_inv: + jsr SETINV + jsr draw_current_line + ;; fall through + +;;; ------------------------------------------------------------ + +.proc keyboard_loop + lda KBD + bpl keyboard_loop + sta KBDSTRB + jsr SETNORM + ldx num_entries + beq :+ ; no up/down/return if empty + + ;; BUG: overwrites A + pha + jsr draw_current_line + pla + + cmp #HI(ASCII_CR) + beq on_return + cmp #HI(ASCII_DOWN) + beq on_down + cmp #HI(ASCII_UP) + beq on_up + + cmp #HI('A') + bcs on_alpha + +: cmp #HI(ASCII_TAB) + beq next_drive + cmp #HI(ASCII_ESCAPE) + bne keyboard_loop + ;; fall through +.endproc + +;;; ------------------------------------------------------------ + +.proc on_escape + jsr pop_prefix ; leaves length in X + dec prefix_depth + bra resize_prefix_and_open_jmp +.endproc + +;;; ------------------------------------------------------------ + +next_drive: + jmp next_device + +inc_resize_prefix_and_open: + inx + +resize_prefix_and_open_jmp: + jmp resize_prefix_and_open + +;;; ------------------------------------------------------------ + +.proc on_return + MLI_CALL SET_PREFIX, set_prefix_params + bcs next_drive + ldx current_entry + jsr update_curr_ptr + + ldx prefix +: iny + lda (curr_ptr),y + inx + sta prefix,x + cpy curr_len + bcc :- + stx prefix + + ldy current_entry + lda types_table,y + bpl inc_resize_prefix_and_open ; is directory??? + ;; nope, system file, so... + + ;; fall through +.endproc + +;;; ------------------------------------------------------------ + +.proc launch_sys_file + jsr SETTXT + jsr HOME + lda #HI(ASCII_RIGHT) ; Right arrow ??? + jsr COUT + + jsr do_open + bcs next_drive + lda #$FF ; Load up to $FFFF bytes + sta read_params_request + sta read_params_request+1 + jsr do_read + php + MLI_CALL CLOSE, close_params + plp + bcs next_drive + jmp read_buffer ; Invoke the loaded code +.endproc + +;;; ------------------------------------------------------------ + +.proc cout_string +loop: lda help_string,y + beq handy_rts2 + jsr COUT + iny + bra loop +.endproc + +;;; ------------------------------------------------------------ + +;; Compute address/length of curr_ptr/curr_len +;; Call with entry index in X. Returns with Y = 0 + +.proc update_curr_ptr + stz curr_ptr+1 + txa + asl a + rol curr_ptr+1 + asl a + rol curr_ptr+1 + asl a + rol curr_ptr+1 + asl a + rol curr_ptr+1 + sta curr_ptr + lda #>filenames + clc + adc curr_ptr+1 + sta curr_ptr+1 + ldy #0 + lda (curr_ptr),y + sta curr_len +.endproc + +handy_rts2: + rts + +;;; ------------------------------------------------------------ + +.proc draw_current_line + lda #2 ; hpos = 2 + sta COL80HPOS + + ldx current_entry ; vpos = entry - page_start + 2 + txa + sec + sbc page_start + inc a + inc a + jsr TABV + + lda types_table,x + bmi name ; is sys file? + + ;; Draw folder glyph + stz COL80HPOS + lda INVFLG + pha + ldy #(folder_string - string_start) ; Draw folder glyphs + jsr cout_string + pla + sta INVFLG + + ;; Draw the name +name: jsr space + jsr update_curr_ptr +loop: iny + lda (curr_ptr),y + jsr ascii_cout + cpy curr_len + bcc loop + +space: lda #HI(' ') + bne cout ; implicit RTS +.endproc + +home: lda #HI(ASCII_EM) ; move cursor to top left + + ;; Sets high bit before calling COUT +ascii_cout: + ora #$80 +cout: jmp COUT + +;;; ------------------------------------------------------------ + +.proc do_open + MLI_CALL OPEN, open_params + lda open_params_ref_num + sta read_params_ref_num + sta mark_ref_num + rts +.endproc + +.proc do_read + MLI_CALL READ, read_params + rts +.endproc + +;;; ------------------------------------------------------------ + + string_start := * +.proc help_string + HIASCIIZ "RETURN: Select | TAB: Chg Vol | ESC: Back" +.endproc + + ;; Mousetext sequence: Enable, folder left, folder right, disable +.proc folder_string + .byte $0F,$1B,$D8,$D9,$18,$0E + .byte 0 ; null terminated +.endproc + +;;; ------------------------------------------------------------ + +.proc open_params +params: .byte 3 +path: .addr prefix +buffer: .addr $1C00 +ref_num:.byte 0 +.endproc + open_params_ref_num := open_params::ref_num + +.proc close_params +params: .byte 1 +ref_num:.byte 0 +.endproc + +.proc on_line_params +params: .byte 2 +unit: .byte $60 +buffer: .addr prefix+1 +.endproc + on_line_params_unit := on_line_params::unit + +.proc set_prefix_params +params: .byte 1 +path: .addr prefix +.endproc + +.proc read_params +params: .byte 4 +ref_num:.byte 1 +buffer: .word read_buffer +request:.word 0 +trans: .word 0 +.endproc + read_params_ref_num := read_params::ref_num + read_params_request := read_params::request + +;;; ------------------------------------------------------------ + + .assert read_params::request - bbb <= $300, error, "Must fit in $300 bytes" + + .res $13FF-*-2, 0 + .byte $48,$AD ; 72, 173 ??? +.endproc + + + .assert .sizeof(bbb) = $3FF, error, "Expected size is $3FF" + +;;; ------------------------------------------------------------ +;;; Installer +;;; ------------------------------------------------------------ + + .org $2402 + +.proc install_and_quit + jsr install + MLI_CALL QUIT, params + +.proc params +params: .byte 4 +type: .byte 0 +res1: .word 0 +res2: .byte 0 +res3: .addr 0 +.endproc +.endproc + +;;; ------------------------------------------------------------ + +.proc install + src := install_src + end := install_src + .sizeof(bbb) + dst := $D100 ; Install location in ProDOS (bank 2) + + src_ptr := $19 + dst_ptr := $1B + + sta ALTZPOFF + lda ROMIN + lda ROMIN + lda #>src + sta src_ptr+1 + lda #dst + sta dst_ptr+1 + lda #end + bne loop + lda src_ptr + cmp # Date: Tue, 12 Dec 2017 04:45:28 -0800 Subject: [PATCH 18/34] works --- bbb2.system.s | 216 ++++++++++++++++++++++++++++++-------------------- 1 file changed, 129 insertions(+), 87 deletions(-) diff --git a/bbb2.system.s b/bbb2.system.s index 98fb2e6..54fc2cb 100644 --- a/bbb2.system.s +++ b/bbb2.system.s @@ -76,6 +76,7 @@ ASCII_ESCAPE := $1B ;;; ------------------------------------------------------------ ;; Loads at $2000 but executed at $1000. + .org $2000 jmp install_and_quit @@ -93,9 +94,10 @@ ASCII_ESCAPE := $1B filenames := $1400 ; each is length + 15 bytes read_buffer := $2000 ; Also, start location for launched SYS files - mark_params := $60 - mark_ref_num := $61 - mark_position := $62 ; 3-bytes + entry_pointer := $60 ; 2 bytes + block_entries := $62 + active_entries := $63 ; 2 bytes + next_device_num := $65 ; next device number to try current_entry := $67 ; index of current entry @@ -136,10 +138,8 @@ ASCII_ESCAPE := $1B sta BITMAP ;; Find device - lda #2 - sta mark_params - ldx DEVCNT ; max device num - stx next_device_num + lda DEVCNT ; max device num + sta next_device_num lda DEVNUM bne check_device @@ -169,126 +169,168 @@ check_device: .proc resize_prefix_and_open stx prefix lda #'/' - sta prefix+1 - sta prefix,x - stz prefix+1,x + sta prefix+1 ; ensure prefix is at least '/' + sta prefix,x ; and ends with '/' + stz prefix+1,x ; and is null terminated + + stz num_entries + +;;; From ProDOS Technical Reference Manual B.2.5 +;;; +;;; Open(DirPathname, Refnum); {Get reference number } jsr do_open bcc :+ ;; Open failed - lda prefix_depth ; root? +fail: lda prefix_depth ; root? beq next_device - jsr pop_prefix ; no, but failed; go up a level - stx prefix - jmp keyboard_loop + jsr pop_prefix ; and go up a level + bra resize_prefix_and_open ;; Open succeeded : inc prefix_depth - stz num_entries - lda #DirectoryHeader::size - sta read_params_request - stz read_params_request+1 - jsr do_read - bcs finish_read2 - ;; Store entry_length/entries_per_block/file_count +;;; ThisBlock := Read512Bytes(RefNum); {Read a block into buffer} + + stz read_params_request + lda #2 + sta read_params_request+1 + jsr do_read + bcs fail + +;;; EntryLength := ThisBlock[$23]; {Get directory info } +;;; EntriesPerBlock := ThisBlock[$24]; +;;; FileCount := ThisBlock[$25] + (256 * ThisBlock[$26]) ; + + ;; Store entry_length (byte), entries_per_block (byte), file_count (word) ldx #3 : lda read_buffer + DirectoryHeader::entry_length,x sta entry_length,x dex bpl :- - sta read_params_request - lda #1 - sta entry_num - stz mark_position+1 - stz mark_position+2 +;;; EntryPoint := EntryLength + $04; {Skip header entry} + clc + lda #<(read_buffer+4) + adc entry_length + sta entry_pointer + lda #>(read_buffer+4) + adc #0 ; TODO: Can skip this if entry_length << 256 + sta entry_pointer+1 +;;; BlockEntries := $02; {Prepare to process entry two} + lda #2 + sta block_entries + +;;; ActiveEntries := $00; {No active entries found yet } + ;; just decrement file_count + +;;; while ActiveEntries < FileCount do begin lda file_count ora file_count+1 - bne next_file_entry ; any files? + beq close_dir -finish_read2: - bra finish_read +while_loop: -next_file_entry: - bit file_count+1 ; wrap around? - bmi finish_read2 +;;; if ThisBlock[EntryPointer] <> $00 then begin {Active entry} + lda (entry_pointer) + beq done_entry - ;; TODO: The math here is mysterious; understand and document -floop: lda mark_position+1 - and #$FE - sta mark_position+1 - ldy entry_num - lda #0 - cpy entries_per_block - bcc :+ - tay - sty entry_num - - inc mark_position+1 -carry: inc mark_position+1 -: dey - clc - bmi :+ - adc entry_length - bcc :- - bcs carry - -: adc #4 - sta mark_position - MLI_CALL SET_MARK, mark_params - bcs finish_read2 - jsr do_read - bcs finish_read2 - - inc entry_num - lda read_buffer + FileEntry::storage_type - and #$F0 ; mask off storage_type - beq floop ; inactive file entry - dec file_count - bne :+ - dec file_count+1 - - ;; Check read access -: ror read_buffer + FileEntry::access - bcc next_file_entry +;;; ProcessEntry(ThisBlock[EntryPointer]); ;; Check file type - lda read_buffer + FileEntry::file_type + ldy #FileEntry::file_type + lda (entry_pointer),y cmp #FileType::Directory beq :+ cmp #FileType::System - bne next_file_entry - - ;; Check to see if we have room -: ldx num_entries - cpx #max_entries - bcs finish_read + bne finish_entry +: ;; Store type + ldx num_entries sta types_table,x ;; Copy name jsr update_curr_ptr - ldy #$0F ; name length + 1 (includes length byte) -: lda read_buffer,y + ldy #15 ; name length (length byte copied too) +: lda (entry_pointer),y sta (curr_ptr),y dey bpl :- iny ; Y = 0 - and #$0F ; mask off name length (remove storage_type) + and #%00001111 ; mask off name length (remove storage_type) sta (curr_ptr),y ; store length - ;; Next inc num_entries - bne next_file_entry -next: jmp next_device +;;; ActiveEntries := ActiveEntries + $01 +finish_entry: + dec file_count + bpl :+ + dec file_count+1 +: -finish_read: +;;; end; + +done_entry: + +;;; if ActiveEntries < FileCount then {More entries to process} + lda file_count + ora file_count+1 + beq close_dir + +;;; if BlockEntries = EntriesPerBlock + lda block_entries + cmp entries_per_block + bne next_in_block + +;;; then begin {ThisBlock done. Do next one} +;;; ThisBlock := Read512Bytes(RefNum); + jsr do_read + bcs fail + +;;; BlockEntries := $01; + lda #1 + sta block_entries + +;;; EntryPointer := $04 + lda #<(read_buffer+4) + sta entry_pointer + lda #>(read_buffer+4) + sta entry_pointer+1 + +;;; end + bra end_while + +;;; else begin {Do next entry in ThisBlock } +next_in_block: + +;;; EntryPointer := EntryPointer + EntryLength; + clc + lda entry_pointer + adc entry_length + sta entry_pointer + lda entry_pointer+1 + adc #0 + sta entry_pointer+1 + +;;; BlockEntries := BlockEntries + $01 + inc block_entries + +;;; end + +end_while: + ;; Check to see if we have room + bit num_entries ; max is 128 + bpl while_loop + +;;; end; + +close_dir: +;;; Close(RefNum); MLI_CALL CLOSE, close_params ;; fall through .endproc @@ -403,11 +445,13 @@ handy_rts: .proc on_alpha loop: lda KBD and #$5F ; make ASCII and uppercase + dec a ldy #1 cmp (curr_ptr),y ; key < first char ? bcc draw_current_line_inv jsr down_common + jsr draw_current_line bra loop .endproc @@ -428,7 +472,6 @@ draw_current_line_inv: ldx num_entries beq :+ ; no up/down/return if empty - ;; BUG: overwrites A pha jsr draw_current_line pla @@ -606,7 +649,6 @@ cout: jmp COUT MLI_CALL OPEN, open_params lda open_params_ref_num sta read_params_ref_num - sta mark_ref_num rts .endproc @@ -671,8 +713,8 @@ trans: .word 0 .res $13FF-*-2, 0 .byte $48,$AD ; 72, 173 ??? -.endproc +.endproc .assert .sizeof(bbb) = $3FF, error, "Expected size is $3FF" From 5e28639a4e13516efdbc6787c7342feb83831ed0 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 05:00:29 -0800 Subject: [PATCH 19/34] alpha works, but esc crashes --- bbb2.system.s | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/bbb2.system.s b/bbb2.system.s index 54fc2cb..2576120 100644 --- a/bbb2.system.s +++ b/bbb2.system.s @@ -404,21 +404,6 @@ handy_rts: ;;; ------------------------------------------------------------ -.proc down_common - lda current_entry - inc a - cmp num_entries ; past the limit? - bcs handy_rts ; yes, just redraw - sta current_entry ; go to next - - lda CV - cmp #bottom_row ; at the bottom? - bne handy_rts - inc page_start ; yes, adjust page and - lda #ASCII_ETB ; scroll screen down - jmp COUT ; implicit rts -.endproc - .proc on_down jsr down_common bra draw_current_line_inv @@ -443,14 +428,12 @@ handy_rts: ;;; ------------------------------------------------------------ .proc on_alpha -loop: lda KBD +loop: jsr down_common + lda KBD and #$5F ; make ASCII and uppercase - dec a ldy #1 cmp (curr_ptr),y ; key < first char ? - bcc draw_current_line_inv - - jsr down_common + beq draw_current_line_inv jsr draw_current_line bra loop .endproc @@ -493,6 +476,25 @@ draw_current_line_inv: ;; fall through .endproc +.proc down_common + lda current_entry + inc a + cmp num_entries ; past the limit? + bcc :+ + pla ; yes - abort subroutine + pla + bra draw_current_line_inv + +: sta current_entry ; go to next + + lda CV + cmp #bottom_row ; at the bottom? + bne handy_rts + inc page_start ; yes, adjust page and + lda #ASCII_ETB ; scroll screen down + jmp COUT ; implicit rts +.endproc + ;;; ------------------------------------------------------------ .proc on_escape From 72b8859222abfab86a0c7d824e72c86837acf086 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 05:17:39 -0800 Subject: [PATCH 20/34] works --- bbb2.system.s | 44 +++++++++++++++++++++++--------------------- 1 file changed, 23 insertions(+), 21 deletions(-) diff --git a/bbb2.system.s b/bbb2.system.s index 2576120..4d51973 100644 --- a/bbb2.system.s +++ b/bbb2.system.s @@ -411,6 +411,19 @@ handy_rts: ;;; ------------------------------------------------------------ +.proc on_alpha +loop: jsr down_common + jsr draw_current_line + lda KBD + and #$5F ; make ASCII and uppercase + ldy #1 + cmp (curr_ptr),y ; key = first char ? + beq draw_current_line_inv + bra loop +.endproc + +;;; ------------------------------------------------------------ + .proc on_up ldx current_entry beq draw_current_line_inv ; first one? just redraw @@ -427,19 +440,6 @@ handy_rts: ;;; ------------------------------------------------------------ -.proc on_alpha -loop: jsr down_common - lda KBD - and #$5F ; make ASCII and uppercase - ldy #1 - cmp (curr_ptr),y ; key < first char ? - beq draw_current_line_inv - jsr draw_current_line - bra loop -.endproc - -;;; ------------------------------------------------------------ - draw_current_line_inv: jsr SETINV jsr draw_current_line @@ -476,6 +476,16 @@ draw_current_line_inv: ;; fall through .endproc +;;; ------------------------------------------------------------ + +.proc on_escape + jsr pop_prefix ; leaves length in X + dec prefix_depth + bra resize_prefix_and_open_jmp +.endproc + +;;; ------------------------------------------------------------ + .proc down_common lda current_entry inc a @@ -497,14 +507,6 @@ draw_current_line_inv: ;;; ------------------------------------------------------------ -.proc on_escape - jsr pop_prefix ; leaves length in X - dec prefix_depth - bra resize_prefix_and_open_jmp -.endproc - -;;; ------------------------------------------------------------ - next_drive: jmp next_device From 1acc9e594626505501bd5ff97163ae3707d5adee Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 10:52:01 -0800 Subject: [PATCH 21/34] Clean up comments --- bbb2.system.s | 93 +++++++++++++++++++-------------------------------- 1 file changed, 34 insertions(+), 59 deletions(-) diff --git a/bbb2.system.s b/bbb2.system.s index 4d51973..f443225 100644 --- a/bbb2.system.s +++ b/bbb2.system.s @@ -1,5 +1,7 @@ ;;; Disassembly of BYE.SYSTEM (Bird's Better Bye) -;;; Additions by Joshua Bell inexorabletash@gmail.com +;;; Modifications by Joshua Bell inexorabletash@gmail.com +;;; * alpha key advances to next matching filename +;;; * replaced directory enumeration (smaller, per PDTRM) .setcpu "65C02" .include "apple2.inc" @@ -175,10 +177,10 @@ check_device: stz num_entries -;;; From ProDOS Technical Reference Manual B.2.5 -;;; -;;; Open(DirPathname, Refnum); {Get reference number } +;;; Enumerate directory +;;; Algorithm from ProDOS Technical Reference Manual B.2.5 + ;; Open the directory jsr do_open bcc :+ @@ -191,18 +193,13 @@ fail: lda prefix_depth ; root? ;; Open succeeded : inc prefix_depth -;;; ThisBlock := Read512Bytes(RefNum); {Read a block into buffer} - + ;; Read a block (512 bytes) into buffer stz read_params_request lda #2 sta read_params_request+1 jsr do_read bcs fail -;;; EntryLength := ThisBlock[$23]; {Get directory info } -;;; EntriesPerBlock := ThisBlock[$24]; -;;; FileCount := ThisBlock[$25] + (256 * ThisBlock[$26]) ; - ;; Store entry_length (byte), entries_per_block (byte), file_count (word) ldx #3 : lda read_buffer + DirectoryHeader::entry_length,x @@ -210,105 +207,89 @@ fail: lda prefix_depth ; root? dex bpl :- -;;; EntryPoint := EntryLength + $04; {Skip header entry} + ;; Any entries? + lda file_count + ora file_count+1 + beq close_dir + + ;; Skip header entry clc - lda #<(read_buffer+4) + lda #<(read_buffer+4) ; 4 bytes for prev/next pointers adc entry_length sta entry_pointer lda #>(read_buffer+4) adc #0 ; TODO: Can skip this if entry_length << 256 sta entry_pointer+1 -;;; BlockEntries := $02; {Prepare to process entry two} + ;; Prepare to process entry two (first "entry" is header) lda #2 sta block_entries -;;; ActiveEntries := $00; {No active entries found yet } - ;; just decrement file_count - -;;; while ActiveEntries < FileCount do begin - lda file_count - ora file_count+1 - beq close_dir - while_loop: - -;;; if ThisBlock[EntryPointer] <> $00 then begin {Active entry} - + ;; Check if entry is active lda (entry_pointer) beq done_entry -;;; ProcessEntry(ThisBlock[EntryPointer]); - ;; Check file type ldy #FileEntry::file_type lda (entry_pointer),y cmp #FileType::Directory - beq :+ + beq good_entry cmp #FileType::System - bne finish_entry -: + bne done_active_entry +good_entry: ;; Store type ldx num_entries sta types_table,x - ;; Copy name - jsr update_curr_ptr - ldy #15 ; name length (length byte copied too) + ;; Copy name into |filenames| + jsr update_curr_ptr ; current entry in X + ldy #15 ; max name length (length byte copied too) : lda (entry_pointer),y sta (curr_ptr),y dey bpl :- - iny ; Y = 0 - and #%00001111 ; mask off name length (remove storage_type) + iny ; Y = 0; storage_type/name_length in A + and #%00001111 ; mask off name_length (remove storage_type) sta (curr_ptr),y ; store length inc num_entries -;;; ActiveEntries := ActiveEntries + $01 -finish_entry: +done_active_entry: dec file_count bpl :+ dec file_count+1 : -;;; end; - done_entry: - -;;; if ActiveEntries < FileCount then {More entries to process} + ;; Seen all active entries? lda file_count ora file_count+1 beq close_dir -;;; if BlockEntries = EntriesPerBlock + ;; Seen all entries in this block? lda block_entries cmp entries_per_block bne next_in_block -;;; then begin {ThisBlock done. Do next one} -;;; ThisBlock := Read512Bytes(RefNum); - jsr do_read + ;; Grab next block +next_block: + jsr do_read ; read another block bcs fail -;;; BlockEntries := $01; - lda #1 + lda #1 ; first entry in non-key block sta block_entries -;;; EntryPointer := $04 - lda #<(read_buffer+4) + lda #<(read_buffer+4) ; 4 bytes for prev/next pointers sta entry_pointer lda #>(read_buffer+4) sta entry_pointer+1 -;;; end bra end_while -;;; else begin {Do next entry in ThisBlock } + ;; Next entry in current block next_in_block: - -;;; EntryPointer := EntryPointer + EntryLength; clc lda entry_pointer adc entry_length @@ -317,20 +298,14 @@ next_in_block: adc #0 sta entry_pointer+1 -;;; BlockEntries := BlockEntries + $01 inc block_entries -;;; end - end_while: ;; Check to see if we have room bit num_entries ; max is 128 bpl while_loop -;;; end; - close_dir: -;;; Close(RefNum); MLI_CALL CLOSE, close_params ;; fall through .endproc @@ -705,7 +680,7 @@ path: .addr prefix params: .byte 4 ref_num:.byte 1 buffer: .word read_buffer -request:.word 0 +request:.word 0 ; This can be beyond $12FF - MARKER trans: .word 0 .endproc read_params_ref_num := read_params::ref_num From f0ceec0aea27bee623a804ee62f00c93445ff709 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 10:58:22 -0800 Subject: [PATCH 22/34] Reorder ZP uses --- bbb2.system.s | 33 ++++++++++++++++----------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/bbb2.system.s b/bbb2.system.s index f443225..3aa558e 100644 --- a/bbb2.system.s +++ b/bbb2.system.s @@ -96,32 +96,33 @@ ASCII_ESCAPE := $1B filenames := $1400 ; each is length + 15 bytes read_buffer := $2000 ; Also, start location for launched SYS files + ;; Device/Prefix enumeration + next_device_num := $65 ; next device number to try + prefix_depth := $6B ; 0 = root + + ;; Directory enumeration entry_pointer := $60 ; 2 bytes block_entries := $62 active_entries := $63 ; 2 bytes - next_device_num := $65 ; next device number to try - - current_entry := $67 ; index of current entry - num_entries := $68 ; length of |filenames| - curr_len := $69 ; length of current entry name - curr_ptr := $6C ; address of current entry name (in |filenames|) - - prefix_depth := $6B ; 0 = root - entry_length := $6E entries_per_block := $6F file_count := $70 ; 2 bytes - entry_num := $72 - page_start := $73 ; index of first entry shown on screen - - max_entries := 128 ; max # of entries; more are ignored + ;; Found entries + current_entry := $67 ; index of current entry + num_entries := $68 ; length of |filenames| (max 128) + curr_len := $69 ; length of current entry name + curr_ptr := $6C ; address of current entry name (in |filenames|) types_table := $74 ; high bit clear = dir, set = sys + ;; Entry display + page_start := $73 ; index of first entry shown on screen + row_count := $6A ; number of rows in this page top_row := 2 ; first row used on screen bottom_row := 21 ; last row used on screen + ;;; ------------------------------------------------------------ cld ; ProDOS protocol for QUIT routine @@ -338,16 +339,14 @@ close_dir: lda num_entries beq keyboard_loop ; no entries (empty directory) - row_count := $6A - cmp #bottom_row ; more entries than fit? bcc :+ lda #(bottom_row - top_row + 1) : sta row_count - lda #2 + lda #top_row sta WNDTOP sta WNDLFT - lda #22 + lda #bottom_row+1 sta WNDWDTH sta WNDBTM loop: jsr draw_current_line From 4cc70803fd1f502199eaccca53d4ede0c2f562ca Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 14:54:27 -0800 Subject: [PATCH 23/34] Tweak installer --- Makefile | 2 +- bbb2.system.s => buhbye.system.s | 43 ++++++++++++++++++-------------- bbb.system.s => bye.system.s | 0 3 files changed, 25 insertions(+), 20 deletions(-) rename bbb2.system.s => buhbye.system.s (95%) rename bbb.system.s => bye.system.s (100%) diff --git a/Makefile b/Makefile index 30b08a1..9105681 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CC65 = ~/dev/cc65/bin CAFLAGS = --target apple2enh --list-bytes 0 CCFLAGS = --config apple2-asm.cfg -TARGETS = bbb.system.SYS bbb2.system.SYS +TARGETS = bye.system.SYS buhbye.system.SYS .PHONY: clean all all: $(TARGETS) diff --git a/bbb2.system.s b/buhbye.system.s similarity index 95% rename from bbb2.system.s rename to buhbye.system.s index 3aa558e..5c1d5f4 100644 --- a/bbb2.system.s +++ b/buhbye.system.s @@ -1,14 +1,14 @@ ;;; Disassembly of BYE.SYSTEM (Bird's Better Bye) ;;; Modifications by Joshua Bell inexorabletash@gmail.com +;;; (so this is Bell's Better Bird's Better Bye - Buh-Bye) ;;; * alpha key advances to next matching filename ;;; * replaced directory enumeration (smaller, per PDTRM) +;;; * rearranged zero page usage .setcpu "65C02" .include "apple2.inc" .include "prodos.inc" - .feature c_comments - ;;; Miscellaneous COL80HPOS := $57B @@ -84,12 +84,15 @@ ASCII_ESCAPE := $1B jmp install_and_quit install_src := * + install_size := $300 ; must fit in $D100...$D3FF = $300 + padded_size := $400 ; but some struct members can spill past end + ;;; ------------------------------------------------------------ ;;; Selector ;;; ------------------------------------------------------------ .org $1000 -.proc bbb +.proc selector prefix := $280 ; length-prefixed @@ -399,6 +402,8 @@ loop: jsr down_common ;;; ------------------------------------------------------------ .proc on_up + jsr draw_current_line + ldx current_entry beq draw_current_line_inv ; first one? just redraw dec current_entry ; go to previous @@ -429,10 +434,6 @@ draw_current_line_inv: ldx num_entries beq :+ ; no up/down/return if empty - pha - jsr draw_current_line - pla - cmp #HI(ASCII_CR) beq on_return cmp #HI(ASCII_DOWN) @@ -461,6 +462,7 @@ draw_current_line_inv: ;;; ------------------------------------------------------------ .proc down_common + jsr draw_current_line lda current_entry inc a cmp num_entries ; past the limit? @@ -687,20 +689,19 @@ trans: .word 0 ;;; ------------------------------------------------------------ - .assert read_params::request - bbb <= $300, error, "Must fit in $300 bytes" + .assert read_params::request - selector <= install_size, error, "Must fit in $300 bytes" - .res $13FF-*-2, 0 - .byte $48,$AD ; 72, 173 ??? + .res ($1000 + $400) - *, 0 ; (selector + install_size) - * .endproc - .assert .sizeof(bbb) = $3FF, error, "Expected size is $3FF" + .assert .sizeof(selector) = padded_size, error, "Expected size is $400" ;;; ------------------------------------------------------------ ;;; Installer ;;; ------------------------------------------------------------ - .org $2402 + .org $2403 ; $2000 + JMP to here .proc install_and_quit jsr install @@ -719,19 +720,21 @@ res3: .addr 0 .proc install src := install_src - end := install_src + .sizeof(bbb) + end := install_src + install_size dst := $D100 ; Install location in ProDOS (bank 2) src_ptr := $19 dst_ptr := $1B sta ALTZPOFF + lda ROMIN ; write bank 2 lda ROMIN - lda ROMIN + lda #>src sta src_ptr+1 lda #dst sta dst_ptr+1 lda #end bne loop lda src_ptr cmp # Date: Tue, 12 Dec 2017 14:55:23 -0800 Subject: [PATCH 24/34] comment --- buhbye.system.s | 1 - 1 file changed, 1 deletion(-) diff --git a/buhbye.system.s b/buhbye.system.s index 5c1d5f4..1ffceaa 100644 --- a/buhbye.system.s +++ b/buhbye.system.s @@ -3,7 +3,6 @@ ;;; (so this is Bell's Better Bird's Better Bye - Buh-Bye) ;;; * alpha key advances to next matching filename ;;; * replaced directory enumeration (smaller, per PDTRM) -;;; * rearranged zero page usage .setcpu "65C02" .include "apple2.inc" From c0c9cc01dd91abd11811bfcf26f2d918a3677000 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 15:55:32 -0800 Subject: [PATCH 25/34] Shave off a few bytes by making alpha default --- buhbye.system.s | 62 ++++++++++++++++++++++++------------------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/buhbye.system.s b/buhbye.system.s index 1ffceaa..7190ef1 100644 --- a/buhbye.system.s +++ b/buhbye.system.s @@ -324,7 +324,7 @@ close_dir: ;; Print help text lda #20 ; HTAB 20 sta CH - ldy #0 ; index into string buffer + ldy #(help_string - text_resources) jsr cout_string ;; Draw prefix @@ -387,22 +387,7 @@ handy_rts: ;;; ------------------------------------------------------------ -.proc on_alpha -loop: jsr down_common - jsr draw_current_line - lda KBD - and #$5F ; make ASCII and uppercase - ldy #1 - cmp (curr_ptr),y ; key = first char ? - beq draw_current_line_inv - bra loop -.endproc - -;;; ------------------------------------------------------------ - .proc on_up - jsr draw_current_line - ldx current_entry beq draw_current_line_inv ; first one? just redraw dec current_entry ; go to previous @@ -412,7 +397,7 @@ loop: jsr down_common bne draw_current_line_inv ; if not, just draw dec page_start ; yes, adjust page and lda #ASCII_SYN ; scroll screen up - jsr cout + jsr COUT ;; fall through .endproc @@ -430,8 +415,18 @@ draw_current_line_inv: bpl keyboard_loop sta KBDSTRB jsr SETNORM + + cmp #HI(ASCII_TAB) + beq next_drive + cmp #HI(ASCII_ESCAPE) + beq on_escape + ldx num_entries - beq :+ ; no up/down/return if empty + beq keyboard_loop ; if empty, no navigation + + pha + jsr draw_current_line + pla cmp #HI(ASCII_CR) beq on_return @@ -439,19 +434,24 @@ draw_current_line_inv: beq on_down cmp #HI(ASCII_UP) beq on_up - - cmp #HI('A') - bcs on_alpha - -: cmp #HI(ASCII_TAB) - beq next_drive - cmp #HI(ASCII_ESCAPE) - bne keyboard_loop ;; fall through .endproc ;;; ------------------------------------------------------------ +.proc on_alpha +loop: jsr down_common + jsr draw_current_line + lda KBD + and #$5F ; make ASCII and uppercase + ldy #1 + cmp (curr_ptr),y ; key = first char ? + beq draw_current_line_inv + bra loop +.endproc + +;;; ------------------------------------------------------------ + .proc on_escape jsr pop_prefix ; leaves length in X dec prefix_depth @@ -459,9 +459,7 @@ draw_current_line_inv: .endproc ;;; ------------------------------------------------------------ - .proc down_common - jsr draw_current_line lda current_entry inc a cmp num_entries ; past the limit? @@ -482,7 +480,7 @@ draw_current_line_inv: ;;; ------------------------------------------------------------ -next_drive: +next_drive: ; relay for branches jmp next_device inc_resize_prefix_and_open: @@ -571,6 +569,7 @@ loop: lda help_string,y ldy #0 lda (curr_ptr),y sta curr_len + ;; fall through .endproc handy_rts2: @@ -597,7 +596,7 @@ handy_rts2: stz COL80HPOS lda INVFLG pha - ldy #(folder_string - string_start) ; Draw folder glyphs + ldy #(folder_string - text_resources) ; Draw folder glyphs jsr cout_string pla sta INVFLG @@ -638,7 +637,8 @@ cout: jmp COUT ;;; ------------------------------------------------------------ - string_start := * + text_resources := * + .proc help_string HIASCIIZ "RETURN: Select | TAB: Chg Vol | ESC: Back" .endproc From 37597de535801c4a0ac81061a6123bf6e9172688 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 20:40:31 -0800 Subject: [PATCH 26/34] Add readme --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++ buhbye.system.s | 31 ++++++++++++------------- 2 files changed, 76 insertions(+), 16 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..684a620 --- /dev/null +++ b/README.md @@ -0,0 +1,61 @@ +# Bird's Better Bye - Diassembly (and improvements) + +The ProDOS operating system for the Apple II personal computer line +supported a quit routine (invoked from BASIC with the `BYE` command) +allowing the user to type the name of a system file to invoke once +the previous system file had exited. + +[Alan Bird](https://alanlbird.wordpress.com/products/) wrote a +replacement called **Bird's Better Bye** that would patch itself into +ProDOS, fitting into a tight 768 bytes. It provides a menu system, +allowing selection of system files (with the arrow keys), directories +(with the return key to enter and escape key to exit), and devices +(with the tab key), with a minimal and stylish 80-column display using +MouseText folder glyphs. + +Later official versions of ProDOS replaced the previous quit routine +with _Bird's Better Bye_. + +## ProDOS 2.4 / Bitsy Bye + +The new (unofficial) releases of +[ProDOS 2.4](http://www.callapple.org/uncategorized/announcing-prodos-2-4-for-all-apple-ii-computers/) +by John Brooks include a replacement quit routine called Bitsy Bye. +This new quit routine is far more powerful, allowing access to BASIC +and binary files (and more), drive selection, type-down, more entries, +and so on. It runs on older hardware than _Bird's Better Bye_ so +uses only 40 columns, and does not require a 65C02 processor. + +Impressed though I am with the power of Bitsy Bye, I am not a fan of +its aesthetics - the display is "cluttered" to my eye. + +## BYE.SYSTEM + +Aeons ago, Dave Cotter created BYE.SYSTEM which would patch _Bird's +Better Bye_ back into ProDOS if it had been replaced. It can be found +at: + +http://www.lazilong.com/apple_ii/bye.sys/bye.html + +Since I really liked the look of _Bird's Better Bye_ I used this as +the boot system for my virtual hard drive (occuring after some [clock +drivers](https://github.com/inexorabletash/cricket)). + +## Buh-Bye + +But... I really wanted a way to quickly scroll through my games list. +So I set out to improve _Bird's Better Bye_ by disassembling it (and +the `BYE.SYSTEM` installer), thus ending up with "Bell's Better Bird's +Better Bye" or "Buh-Bye" for short. + +The changes are so far pretty minimal since my 6502 skills are not, +in fact, mad, and there are only 768 bytes to play with. + +I replaced the directory enumeration logic with tighter code as +outlined in the ProDOS Technical Reference Manual, and along with +other optimizations I made enough room to add seeking if an +alphabetical key is typed (hit 'C' and the list will scroll to the +next file starting with 'C'). + +There are a few spare bytes to play with and more can be squeezed +out, so perhaps further improvements can be made. diff --git a/buhbye.system.s b/buhbye.system.s index 7190ef1..116838e 100644 --- a/buhbye.system.s +++ b/buhbye.system.s @@ -237,11 +237,11 @@ while_loop: ldy #FileEntry::file_type lda (entry_pointer),y cmp #FileType::Directory - beq good_entry + beq store_entry cmp #FileType::System bne done_active_entry -good_entry: +store_entry: ;; Store type ldx num_entries sta types_table,x @@ -339,8 +339,9 @@ close_dir: : stz current_entry stz page_start lda num_entries - beq keyboard_loop ; no entries (empty directory) + beq selection_loop_keyboard_loop ; no entries (empty directory) + ;; Draw entries cmp #bottom_row ; more entries than fit? bcc :+ lda #(bottom_row - top_row + 1) @@ -356,7 +357,7 @@ loop: jsr draw_current_line dec row_count bne loop stz current_entry - beq draw_current_line_inv + beq selection_loop .endproc ;;; ------------------------------------------------------------ @@ -382,19 +383,19 @@ handy_rts: .proc on_down jsr down_common - bra draw_current_line_inv + bra selection_loop .endproc ;;; ------------------------------------------------------------ .proc on_up - ldx current_entry - beq draw_current_line_inv ; first one? just redraw - dec current_entry ; go to previous + ldx current_entry ; first one? + beq selection_loop + dec current_entry ; go to previous lda CV cmp #top_row ; at the top? - bne draw_current_line_inv ; if not, just draw + bne selection_loop dec page_start ; yes, adjust page and lda #ASCII_SYN ; scroll screen up jsr COUT @@ -403,14 +404,11 @@ handy_rts: ;;; ------------------------------------------------------------ -draw_current_line_inv: +.proc selection_loop jsr SETINV jsr draw_current_line - ;; fall through -;;; ------------------------------------------------------------ - -.proc keyboard_loop +keyboard_loop: lda KBD bpl keyboard_loop sta KBDSTRB @@ -436,6 +434,7 @@ draw_current_line_inv: beq on_up ;; fall through .endproc + selection_loop_keyboard_loop := selection_loop::keyboard_loop ;;; ------------------------------------------------------------ @@ -446,7 +445,7 @@ loop: jsr down_common and #$5F ; make ASCII and uppercase ldy #1 cmp (curr_ptr),y ; key = first char ? - beq draw_current_line_inv + beq selection_loop bra loop .endproc @@ -466,7 +465,7 @@ loop: jsr down_common bcc :+ pla ; yes - abort subroutine pla - bra draw_current_line_inv + bra selection_loop : sta current_entry ; go to next From c11c49a03bc88fb9737bad5f8494ef88b4262535 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 20:41:06 -0800 Subject: [PATCH 27/34] Fix typo in title --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 684a620..55cb5e1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Bird's Better Bye - Diassembly (and improvements) +# Bird's Better Bye - Disassembly (and improvements) The ProDOS operating system for the Apple II personal computer line supported a quit routine (invoked from BASIC with the `BYE` command) From b064242a7a481eec32db6539a919ab0bd9ec328f Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 12 Dec 2017 20:56:51 -0800 Subject: [PATCH 28/34] Consolidate installer --- buhbye.system.s | 141 +++++++++++++++++++++--------------------------- 1 file changed, 62 insertions(+), 79 deletions(-) diff --git a/buhbye.system.s b/buhbye.system.s index 116838e..ab569e1 100644 --- a/buhbye.system.s +++ b/buhbye.system.s @@ -73,18 +73,72 @@ ASCII_ESCAPE := $1B ;;; area is Apple's dispatcher code. ;;; ------------------------------------------------------------ -;;; Entry point +;;; Installer ;;; ------------------------------------------------------------ - ;; Loads at $2000 but executed at $1000. - .org $2000 - jmp install_and_quit - install_src := * - install_size := $300 ; must fit in $D100...$D3FF = $300 - padded_size := $400 ; but some struct members can spill past end + +.proc install + src := install_src + end := install_src + install_size + dst := $D100 ; Install location in ProDOS (bank 2) + + src_ptr := $19 + dst_ptr := $1B + + sta ALTZPOFF + lda ROMIN ; write bank 2 + lda ROMIN + + lda #src + sta src_ptr+1 + + lda #dst + sta dst_ptr+1 + +loop: lda (src_ptr) ; *src_ptr = *dst_ptr + sta (dst_ptr) + + inc src_ptr ; src_ptr++ + bne :+ + inc src_ptr+1 + +: inc dst_ptr ; dst_ptr++ + bne :+ + inc dst_ptr+1 + +: lda src_ptr+1 ; src_ptr == end ? + cmp #>end + bne loop + lda src_ptr + cmp #src - sta src_ptr+1 - lda #dst - sta dst_ptr+1 - lda #end - bne loop - lda src_ptr - cmp # Date: Wed, 13 Dec 2017 08:49:43 -0800 Subject: [PATCH 29/34] adjust credits --- README.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 55cb5e1..c464301 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,12 @@ with _Bird's Better Bye_. The new (unofficial) releases of [ProDOS 2.4](http://www.callapple.org/uncategorized/announcing-prodos-2-4-for-all-apple-ii-computers/) -by John Brooks include a replacement quit routine called Bitsy Bye. -This new quit routine is far more powerful, allowing access to BASIC -and binary files (and more), drive selection, type-down, more entries, -and so on. It runs on older hardware than _Bird's Better Bye_ so -uses only 40 columns, and does not require a 65C02 processor. +by John Brooks include a replacement quit routine called Bitsy Bye, +a collaboration with Peter Ferrie. This new quit routine is far more +powerful, allowing access to BASIC and binary files (and more), drive +selection, type-down, more entries, and so on. It runs on older +hardware than _Bird's Better Bye_ so uses only 40 columns, and does +not require a 65C02 processor. Impressed though I am with the power of Bitsy Bye, I am not a fan of its aesthetics - the display is "cluttered" to my eye. From 16599fc4b995523e63e3869c037c59afdd059496 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sun, 22 Sep 2019 21:34:47 -0700 Subject: [PATCH 30/34] Build: Use cc65's make avail --- Makefile | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index 9105681..1767cc9 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,6 @@ -CC65 = ~/dev/cc65/bin CAFLAGS = --target apple2enh --list-bytes 0 -CCFLAGS = --config apple2-asm.cfg +LDFLAGS = --config apple2-asm.cfg TARGETS = bye.system.SYS buhbye.system.SYS @@ -15,8 +14,8 @@ clean: rm -f $(TARGETS) %.o: %.s $(HEADERS) - $(CC65)/ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< + ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< %.SYS: %.o - $(CC65)/ld65 $(CCFLAGS) -o $@ $< + ld65 $(LDFLAGS) -o $@ $< xattr -wx prodos.AuxType '00 20' $@ From cfb8cab3b2f1fb0cedfe48c083e29d0080b5030c Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 1 Oct 2019 21:14:34 -0700 Subject: [PATCH 31/34] Add QUIT.SYSTEM --- .travis.yml | 11 +++++++++++ Makefile | 2 +- README.md | 5 +++++ quit.system.s | 35 +++++++++++++++++++++++++++++++++++ 4 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 .travis.yml create mode 100644 quit.system.s diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5650818 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,11 @@ +sudo: enabled +os: osx +language: c + +install: +- git clone https://github.com/cc65/cc65 /tmp/cc65 && + sudo make -C /tmp/cc65 ca65 ld65 avail && + ca65 --version + +script: + - make diff --git a/Makefile b/Makefile index 1767cc9..deb43b7 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ CAFLAGS = --target apple2enh --list-bytes 0 LDFLAGS = --config apple2-asm.cfg -TARGETS = bye.system.SYS buhbye.system.SYS +TARGETS = bye.system.SYS buhbye.system.SYS quit.system.SYS .PHONY: clean all all: $(TARGETS) diff --git a/README.md b/README.md index c464301..6ccf5ed 100644 --- a/README.md +++ b/README.md @@ -60,3 +60,8 @@ next file starting with 'C'). There are a few spare bytes to play with and more can be squeezed out, so perhaps further improvements can be made. + +## QUIT.SYSTEM + +This just invokes the ProDOS quit handler immediately. It can +be used as the last in a chain of "driver" installers. diff --git a/quit.system.s b/quit.system.s new file mode 100644 index 0000000..efb4231 --- /dev/null +++ b/quit.system.s @@ -0,0 +1,35 @@ + + .setcpu "6502" + .include "apple2.inc" + .include "prodos.inc" + + .org $2000 + +CLR80VID := $C00C +ROMIN2 := $C082 +SETVID := $FE93 +SETKBD := $FE89 +INIT := $FB2F +HOME := $FC58 +SETNORM := $FE84 + + cld + bit ROMIN2 + sta CLR80VID + sta CLRALTCHAR + sta CLR80COL + jsr SETVID + jsr SETKBD + jsr SETNORM + jsr INIT + jsr HOME + + MLI_CALL QUIT, quit_params + brk + +quit_params: + .byte 4 + .byte 0 + .word 0 + .byte 0 + .word 0 From eb3ca7e7e2a4cb7bed85994f4d13568d498cd479 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 1 Oct 2019 21:15:49 -0700 Subject: [PATCH 32/34] Update README link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6ccf5ed..1b0b308 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,7 @@ http://www.lazilong.com/apple_ii/bye.sys/bye.html Since I really liked the look of _Bird's Better Bye_ I used this as the boot system for my virtual hard drive (occuring after some [clock -drivers](https://github.com/inexorabletash/cricket)). +drivers](https://github.com/a2stuff/cricket)). ## Buh-Bye From 2769d1d7a68c2bd10059a4f26771d56330dedf09 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 1 Oct 2019 21:17:42 -0700 Subject: [PATCH 33/34] Add Travis-CI build status indicator --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 1b0b308..2a7f22d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # Bird's Better Bye - Disassembly (and improvements) +[![Build Status](https://travis-ci.org/a2stuff/bbb.svg?branch=master)](https://travis-ci.org/a2stuff/bbb) + The ProDOS operating system for the Apple II personal computer line supported a quit routine (invoked from BASIC with the `BYE` command) allowing the user to type the name of a system file to invoke once From db977835ac0f27b61443985d0c782b11a45216f0 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 1 Oct 2019 22:08:21 -0700 Subject: [PATCH 34/34] Use common driver chain logic --- Makefile | 8 +- buhbye.system.s | 112 ++++------ driver_postamble.inc | 3 + driver_preamble.inc | 458 +++++++++++++++++++++++++++++++++++++++++ inc/apple2.inc | 54 +++++ inc/macros.inc | 123 +++++++++++ inc/prodos.inc | 477 +++++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1158 insertions(+), 77 deletions(-) create mode 100644 driver_postamble.inc create mode 100644 driver_preamble.inc create mode 100644 inc/apple2.inc create mode 100644 inc/macros.inc create mode 100644 inc/prodos.inc diff --git a/Makefile b/Makefile index deb43b7..9320ac4 100644 --- a/Makefile +++ b/Makefile @@ -4,6 +4,12 @@ LDFLAGS = --config apple2-asm.cfg 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 all: $(TARGETS) @@ -14,7 +20,7 @@ clean: rm -f $(TARGETS) %.o: %.s $(HEADERS) - ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< + ca65 $(CAFLAGS) $(DEFINES) --listing $(basename $@).list -o $@ $< %.SYS: %.o ld65 $(LDFLAGS) -o $@ $< diff --git a/buhbye.system.s b/buhbye.system.s index ab569e1..14e8662 100644 --- a/buhbye.system.s +++ b/buhbye.system.s @@ -3,10 +3,18 @@ ;;; (so this is Bell's Better Bird's Better Bye - Buh-Bye) ;;; * alpha key advances to next matching filename ;;; * replaced directory enumeration (smaller, per PDTRM) +;;; * installs, then chains to next .SYSTEM file .setcpu "65C02" + .linecont + + .feature string_escapes + .include "apple2.inc" - .include "prodos.inc" + .include "apple2.mac" + + .include "inc/apple2.inc" + .include "inc/macros.inc" + .include "inc/prodos.inc" ;;; Miscellaneous @@ -14,12 +22,6 @@ COL80HPOS := $57B ;;; 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 ROMINWB1 := $C089 ; Read ROM; write RAM bank 1 @@ -31,10 +33,7 @@ SETTXT := $FB39 TABV := $FB5B SETPWRC := $FB6F BELL1 := $FBDD -HOME := $FC58 -COUT := $FDED SETINV := $FE80 -SETNORM := $FE84 ;;; ASCII/Key codes ASCII_TAB := $9 @@ -47,21 +46,10 @@ ASCII_ETB := $17 ; scroll text window down ASCII_EM := $19 ; move cursor to upper left 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 ;;; ------------------------------------------------------------ - .org $2000 - install_size := $300 ; must fit in $D100...$D3FF = $300 -.proc install +.proc maybe_install_driver + src := install_src end := install_src + install_size dst := $D100 ; Install location in ProDOS (bank 2) @@ -123,28 +110,17 @@ loop: lda (src_ptr) ; *src_ptr = *dst_ptr sta ALTZPOFF sta ROMINWB1 sta ROMINWB1 - ;; fall through -.endproc -.proc quit - MLI_CALL QUIT, params - -.proc params -params: .byte 4 -type: .byte 0 -res1: .word 0 -res2: .byte 0 -res3: .addr 0 + rts .endproc -.endproc - - install_src := * ;;; ------------------------------------------------------------ ;;; Selector ;;; ------------------------------------------------------------ - .org $1000 + install_src := * + + pushorg $1000 .proc selector prefix := $280 ; length-prefixed @@ -259,7 +235,7 @@ fail: lda prefix_depth ; root? ;; Store entry_length (byte), entries_per_block (byte), file_count (word) ldx #3 -: lda read_buffer + DirectoryHeader::entry_length,x +: lda read_buffer + SubdirectoryHeader::entry_length,x sta entry_length,x dex bpl :- @@ -290,9 +266,9 @@ while_loop: ;; Check file type ldy #FileEntry::file_type lda (entry_pointer),y - cmp #FileType::Directory + cmp #FT_DIRECTORY beq store_entry - cmp #FileType::System + cmp #FT_SYSTEM bne done_active_entry store_entry: @@ -693,7 +669,8 @@ cout: jmp COUT text_resources := * .proc help_string - HIASCIIZ "RETURN: Select | TAB: Chg Vol | ESC: Back" + scrcode "RETURN: Select | TAB: Chg Vol | ESC: Back" + .byte 0 .endproc ;; Mousetext sequence: Enable, folder left, folder right, disable @@ -704,43 +681,26 @@ cout: jmp COUT ;;; ------------------------------------------------------------ -.proc open_params -params: .byte 3 -path: .addr prefix -buffer: .addr $1C00 -ref_num:.byte 0 -.endproc + DEFINE_OPEN_PARAMS open_params, prefix, $1C00 open_params_ref_num := open_params::ref_num -.proc close_params -params: .byte 1 -ref_num:.byte 0 -.endproc + DEFINE_CLOSE_PARAMS close_params -.proc on_line_params -params: .byte 2 -unit: .byte $60 -buffer: .addr prefix+1 -.endproc - on_line_params_unit := on_line_params::unit + DEFINE_ON_LINE_PARAMS on_line_params, $60, prefix+1 + on_line_params_unit := on_line_params::unit_num -.proc set_prefix_params -params: .byte 1 -path: .addr prefix -.endproc + DEFINE_SET_PREFIX_PARAMS set_prefix_params, prefix -.proc read_params -params: .byte 4 -ref_num:.byte 1 -buffer: .word read_buffer -request:.word 0 ; This can be beyond $12FF - MARKER -trans: .word 0 -.endproc + DEFINE_READ_PARAMS read_params, read_buffer, 0 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 + .assert .sizeof(selector) <= install_size, error, "Must fit in $300 bytes" + poporg + +;;; ************************************************************ + .include "driver_postamble.inc" +;;; ************************************************************ diff --git a/driver_postamble.inc b/driver_postamble.inc new file mode 100644 index 0000000..95e7ebd --- /dev/null +++ b/driver_postamble.inc @@ -0,0 +1,3 @@ + + poporg + reloc_end := * diff --git a/driver_preamble.inc b/driver_preamble.inc new file mode 100644 index 0000000..88ff901 --- /dev/null +++ b/driver_preamble.inc @@ -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 $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 diff --git a/inc/apple2.inc b/inc/apple2.inc new file mode 100644 index 0000000..a66c24e --- /dev/null +++ b/inc/apple2.inc @@ -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 diff --git a/inc/macros.inc b/inc/macros.inc new file mode 100644 index 0000000..9610987 --- /dev/null +++ b/inc/macros.inc @@ -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) diff --git a/inc/prodos.inc b/inc/prodos.inc new file mode 100644 index 0000000..637e44e --- /dev/null +++ b/inc/prodos.inc @@ -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