Rejiggered the selectors, added actual 40-column Bird's Better Bye.

I discovered that Bird's Better Bye and the ProDOS 1.9 selector are different.
Documentation updated with the history to the best of my knowledge.
This commit is contained in:
Joshua Bell 2020-12-23 14:35:08 -08:00
parent 1312b3f386
commit ace258d862
11 changed files with 661 additions and 122 deletions

View File

@ -11,9 +11,9 @@ The ProDOS operating system for the Apple II executes the first `.SYSTEM` file f
* RAM Disk drivers (e.g. RamWorks)
* In ProDOS 1.x, 2.0 and 2.4 only a 64K driver for /RAM is built-in.
* Quit dispatcher/selector (`BYE` routines)
* In ProDOS 1.0 through 1.7 a simple [selector](selector) prompting `ENTER PREFIX (PRESS "RETURN" TO ACCEPT)` asked for a path.
* In ProDOS 1.9 and 2.0 [Bird's Better Bye](bbb) is built-in.
* In ProDOS 2.4 [Bitsy Bye](https://prodos8.com/bitsy-bye/) is built-in.
* In ProDOS 1.0 and later, a 40-column friendly [selector](selector) prompts for a prefix then a path `ENTER PREFIX (PRESS "RETURN" TO ACCEPT)`
* In ProDOS 1.9 and 2.0.x, on 80-column systems, a menu-driven selector is installed instead.
* In ProDOS 2.4.x [Bitsy Bye](https://prodos8.com/bitsy-bye/) is built-in.
Early versions of these drivers would often invoke a specific file on completion, sometimes user-configurable. The best versions of these drivers simply execute the following `.SYSTEM` file, although this is non-trivial code and often did not work with network drives.
@ -30,9 +30,10 @@ This repo includes The following drivers/modifications:
* RAM Disk drivers
* RAMWorks Driver by Glen E. Bredon
* Quit dispatcher/selector (`BYE` routines)
* Selector (from ProDOS 1.x)
* Bird's Better Bye (from ProDOS 2.0)
* Buh-Bye (an enhanced version of Bird's Better Bye)
* 40-column Selector (from ProDOS)
* 80-column menu-driven Selector (from ProDOS 1.9 and 2.x)
* Bird's Better Bye (a 40-column menu-driven selector)
* Buh-Bye (an enhanced version of the ProDOS 80-column, menu-driven selector)
In addition, `QUIT.SYSTEM` is present which isn't a driver but which immediately invokes the QUIT handler (a.k.a. program selector).

View File

@ -1,64 +0,0 @@
# 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)
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,
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.
## BBB.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/a2stuff/cricket)).
This is a modified version that chains to the next `.SYSTEM` file instead of immediately launching the selector. You can follow it with `QUIT.SYSTEM` in your driver sequence if you want to show the selector on startup.
## BUHBYE.SYSTEM
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.

View File

@ -64,6 +64,7 @@ GETLN2 := $FD6F ; no prompt character
CROUT := $FD8E
PRBYTE := $FDDA
COUT := $FDED
COUT1 := $FDF0
SETINV := $FE80
SETNORM := $FE84
SETKBD := $FE89

View File

@ -1,34 +0,0 @@
CAFLAGS = --target apple2enh --list-bytes 0
LDFLAGS = --config apple2-asm.cfg
OUTDIR = out
HEADERS = $(wildcard *.inc) $(wildcard ../inc/*.inc)
TARGETS = \
$(OUTDIR)/selector.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: $(OUTDIR) $(TARGETS)
$(OUTDIR):
mkdir -p $(OUTDIR)
clean:
rm -f $(OUTDIR)/*.o
rm -f $(OUTDIR)/*.list
rm -f $(TARGETS)
$(OUTDIR)/%.o: %.s $(HEADERS)
ca65 $(CAFLAGS) $(DEFINES) --listing $(basename $@).list -o $@ $<
$(OUTDIR)/%.SYS: $(OUTDIR)/%.o
ld65 $(LDFLAGS) -o $@ $<
xattr -wx prodos.AuxType '00 20' $@

View File

@ -1,10 +0,0 @@
# Selector - Disassembly
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 next prefix and name of a system file to invoke once the previous system file had exited.
* `ENTER PREFIX (PRESS "RETURN" TO ACCEPT)"`
* `ENTER PATHNAME OF NEXT APPLICATION`
This was replaced in later versions of ProDOS with much improved selector showing a list of files and allowing navigation of the file system with the keyboard.
But... maybe you are feeling retro? This `SELECTOR.SYSTEM` patches the old version of the selector back in. Like the other drivers here, it is intended to be placed on your boot volume to run on startup, and will chain to the next `.SYSTEM` file found. You can follow it with `QUIT.SYSTEM` in your driver sequence if you want to show the selector on startup.

View File

@ -7,6 +7,8 @@ OUTDIR = out
HEADERS = $(wildcard *.inc) $(wildcard ../inc/*.inc)
TARGETS = \
$(OUTDIR)/selector.system.SYS \
$(OUTDIR)/bye.system.SYS \
$(OUTDIR)/bbb.system.SYS \
$(OUTDIR)/buhbye.system.SYS

46
selectors/README.md Normal file
View File

@ -0,0 +1,46 @@
# ProDOS Program Selectors ("BYE" commands)
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 launch a new system file once previous system file had exited.
This selector code evolved over time, and the memory location that the routine was stored at was documented, allowing users to install customized versions coded to fit within a mere 768 bytes.
## ProDOS 1.0 through 1.8 - Selector
The earliest versions of ProDOS supported a simple 40-column-friendly selector prompting:
* `ENTER PREFIX (PRESS "RETURN" TO ACCEPT)"`
* `ENTER PATHNAME OF NEXT APPLICATION`
This was not particularly user friendly.
If you want to use this selector with any version of ProDOS, add the `SELECTOR.SYSTEM` file to your boot sequence. You can follow it with `QUIT.SYSTEM` in your driver sequence to show the selector on startup.
## Bird's Better Bye
[Alan Bird](https://alanlbird.wordpress.com/products/) wrote a replacement called **Bird's Better Bye** that would patch itself into ProDOS. Directories and system files could be selected with arrows keys and the Return key, Escape would back up a directory level, Tab would change drives. This also functioned in 40 column mode.
If you want to use this selector with any version of ProDOS, add the `BBB.SYSTEM` file to your boot sequence. You can follow it with `QUIT.SYSTEM` in your driver sequence to show the selector on startup.
## ProDOS 1.9 and 2.0.x - 80-column Selector
ProDOS 1.9 introduced a much improved menu-driven selector showing a list of files and allowing navigation of the file system with the keyboard. Directories and system files could be selected with arrows keys and the Return key, Escape would back up a directory level, Tab would change drives. This required 80 columns and a 65C02 processor, and took advantage of the [MouseText characters](https://en.wikipedia.org/wiki/MouseText) to show folder glyphs for directories.
If these versions of ProDOS were started on systems without 40 column support, the previous version of the selector would be loaded instead (both were present in the PRODOS system file.)
If you want to use this selector with any version of ProDOS, add the `BYE.SYSTEM` file to your boot sequence. You can follow it with `QUIT.SYSTEM` in your driver sequence to show the selector on startup.
This was inspired by the work of Dave Cotter who created a similarly named file to patch the selector back in. It can be found at: http://www.lazilong.com/apple_ii/bye.sys/bye.html
## 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, 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 uses only 40 columns, and does not require a 65C02 processor.
If you want to use this selector, use a version of ProDOS 2.4 from https://prodos8.com/
## Buh-Bye - Enhanced 80-column selector
Since I prefered the look of the ProDOS 80-column selector to Bitsy Bye, but missed the type-down ability, I modified the 80-column selector to tighten up the code added seeking if an alphabetical key is typed. Hit 'C' and the list will scroll to the next file starting with 'C'.
I erroneously thought that the ProDOS 80-column selector was _Bird's Better Bye_ and named this "Bell's Better Bird's Better Bye" or "Buh-Bye".
If you want to use this selector with any version of ProDOS, add the `BUHBYE.SYSTEM` file to your boot sequence. You can follow it with `QUIT.SYSTEM` in your driver sequence to show the selector on startup.

592
selectors/bbb.system.s Normal file
View File

@ -0,0 +1,592 @@
;;; Disassembly of Bird's Better Bye, 40 column program selector
;;; (Found in a copy of ProDOS 1.8, but not believed to be original?)
;;;
;;; Installer wrapper added by Joshua Bell inexorabletash@gmail.com
.setcpu "65C02"
.linecont +
.feature string_escapes
.include "apple2.inc"
.include "apple2.mac"
.include "../inc/apple2.inc"
.include "../inc/macros.inc"
.include "../inc/prodos.inc"
.include "../inc/ascii.inc"
;;; ************************************************************
.include "../inc/driver_preamble.inc"
;;; ************************************************************
;;; ------------------------------------------------------------
;;; 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.
;;; ------------------------------------------------------------
;;; Installer
;;; ------------------------------------------------------------
max_size = $300
.proc maybe_install_driver
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
lda ROMIN
lda #>src
sta src_ptr+1
lda #<src
sta src_ptr
lda #>dst
sta dst_ptr+1
lda #<dst
sta dst_ptr
loop: lda (src_ptr)
sta (dst_ptr)
inc src_ptr
bne :+
inc src_ptr+1
: inc dst_ptr
bne :+
inc dst_ptr+1
: lda src_ptr+1
cmp #>end
bne loop
lda src_ptr
cmp #<end
bne loop
lda (src_ptr)
sta (dst_ptr)
sta ALTZPOFF
sta ROMINWB1
sta ROMINWB1
rts
.endproc
;;; ------------------------------------------------------------
;;; Selector
;;; ------------------------------------------------------------
install_src := *
pushorg $1000
.proc bbb
PREFIX := $280
kMaxFilesDisplayed = 16
filename_table := $1700
device := $6 ; current device index (in DEVLST)
name_len := $8
index := $9 ; current displayed file index
name_ptr := $D
num_files := $F ; number of displayed files
type_table := $10 ; one entry per line, high bit set if SYS
;; Copied from directory header
entry_length := $A5
entries_per_block := $A6
file_count := $A7
entry_index := $A9 ; within "block"
dir_buf := SYS_ADDR
;;; ============================================================
;;; Code
;;; ============================================================
;; Signal to ProDOS that this is modified.
cld
inc $03F4 ; ???
;; Page in normal banks, reset screen to 40 columns.
lda ROMIN2
jsr SETTXT
jsr SETVID
jsr SETKBD
jsr SETNORM
sta CLR80VID
sta CLRALTCHAR
sta CLR80COL
;; Clear system bitmap.
lda #$01
sta BITMAP+BITMAP_SIZE-1
lda #$00
ldx #BITMAP_SIZE-2
: sta BITMAP,x
dex
bpl :-
lda #$CF
sta BITMAP
lda default_devnum
beq :+ ; always?
sta DEVNUM
: ldx DEVCNT
: stx device
lda DEVLST,x
and #$F0
cmp DEVNUM
beq set_devnum
dex
bpl :-
next_drive:
ldx device
cpx DEVCNT
bcc :+
ldx #$FF
: inx
stx device
lda DEVLST,x
set_devnum:
sta on_line_unit_num
sta DEVNUM
jsr HOME
MLI_CALL ON_LINE, on_line_params
bcs error_relay
lda PREFIX+1
and #$0F
beq error_relay
adc #$02
sta PREFIX
tax
set_prefix_length:
lda #'/'
sta PREFIX+1
sta PREFIX,x
lda #0
sta PREFIX+1,x
sta index
sta read_request_count+1
sta set_mark_position+1
sta set_mark_position+2
ldx #msg_select_drive
lda #10 ; HTAB
jsr ShowMessage
ldx #msg_select_file
lda #9 ; HTAB
jsr ShowMessage
;; Show current prefix
ldx #0
: lda PREFIX+1,x
beq :+
jsr Cout
inx
bne :-
: MLI_CALL OPEN, open_params
error_relay:
bcs next_drive_on_error
jsr AssignRefNum
lda #.sizeof(SubdirectoryHeader)
sta read_request_count
MLI_CALL READ, read_params
bcs next_drive_on_error
ldx #3
: lda dir_buf + SubdirectoryHeader::entry_length,x
sta entry_length,x
dex
bpl :-
sta read_request_count
lda #1
sta entry_index
lda file_count ; empty?
ora file_count+1
bne next_file
: jmp finish_dir ; empty!
;; Loop over file entries
next_file:
bit file_count+1 ; negative?
bmi :-
skip: lda set_mark_position+1
and #$FE
sta set_mark_position+1
ldy entry_index
lda #0
cpy entries_per_block
bcc next_entry_in_block
tay
sty entry_index
inc set_mark_position+1 ; next block - two pages
: inc set_mark_position+1
next_entry_in_block:
dey
clc
bmi next_block
adc entry_length
bcc next_entry_in_block
bcs :- ; always
next_block:
adc #4 ; skip prev/next block pointers
sta set_mark_position
MLI_CALL SET_MARK, get_eof_params
next_drive_on_error:
bcs do_next_drive
MLI_CALL READ, read_params
bcs do_next_drive
inc entry_index
lda dir_buf
beq skip ; deleted entry
and #NAME_LENGTH_MASK
sta dir_buf
dec file_count
bne :+
dec file_count+1
: ror dir_buf + FileEntry::access ; check low bit
bcc next_file
lda dir_buf + FileEntry::file_type
cmp #FT_DIRECTORY
beq :+
cmp #FT_SYSTEM
bne next_file
: ldx index
cpx #kMaxFilesDisplayed
bcs finish_dir
sta type_table,x
jsr SetNamePtrAndLen
ldy #$0F ; max name length
: lda dir_buf,y
sta (name_ptr),y
dey
bpl :-
jsr DisplayFilename
inc index
jmp next_file
;;; ============================================================
do_next_drive:
jmp next_drive
up_dir:
ldx PREFIX
: dex
beq input_loop
lda PREFIX,x
cmp #'/'
bne :-
dex
beq input_loop
stx PREFIX
set_new_prefix:
inc PREFIX
jsr HOME
ldx PREFIX
jmp set_prefix_length
select_next_file:
jsr DisplayFilename
ldx index
inx
cpx num_files
bcc set_index
ldx #0
beq set_index ; always
select_prev_file:
jsr DisplayFilename
ldx index
bne :+
ldx num_files
: dex
set_index:
stx index
jmp redisplay_selection
finish_dir:
MLI_CALL CLOSE, close_params
next_drive_relay:
bcs do_next_drive
lda index
beq do_next_drive
sta num_files
lda #0
sta index
redisplay_selection:
jsr SETINV
jsr DisplayFilename
jsr SETNORM
;; fall through
;;; ============================================================
input_loop:
lda KBD
bpl input_loop
sta KBDSTRB
cmp #HI(ASCII_TAB)
beq do_next_drive
cmp #HI(ASCII_LEFT)
beq select_prev_file
cmp #HI(ASCII_UP)
beq select_prev_file
cmp #HI(ASCII_RIGHT)
beq select_next_file
cmp #HI(ASCII_DOWN)
beq select_next_file
cmp #HI(ASCII_ESCAPE)
beq up_dir
cmp #HI(ASCII_CR)
bne input_loop
lda BUTN0
bpl SelectFile
lda ROMIN
lda ROMIN
lda DEVNUM
sta $D3A6
lda ROMIN2
jmp input_loop
;;; ============================================================
.proc SelectFile
MLI_CALL SET_PREFIX, set_prefix_params
bcs next_drive_relay
jsr SetNamePtrAndLen
ldx PREFIX
: iny
lda (name_ptr),y
inx
sta PREFIX,x
cpy name_len
bcc :-
stx PREFIX
ldy index
lda type_table,y
bmi InvokeSystemFile
jmp set_new_prefix
.endproc
;;; ============================================================
.proc InvokeSystemFile
MLI_CALL OPEN, open_params
: bcs next_drive_relay
jsr AssignRefNum
MLI_CALL GET_EOF, get_eof_params
bcs :-
lda get_eof_eof
sta read_request_count
lda get_eof_eof+1
sta read_request_count+1
MLI_CALL READ, read_params
php
MLI_CALL CLOSE, close_params
bcc :+
pla
err: jmp do_next_drive
: plp
bcs err
jmp SYS_ADDR
.endproc
;;; ============================================================
;;; Call with HTAB in A, message table offset in X
.proc ShowMessage
sta CH
: lda message_table,x
beq done
jsr Cout
inx
bne :-
done: rts
.endproc
;;; ============================================================
.proc Cout
ora #$80
jmp COUT1
.endproc
;;; ============================================================
.proc SetNamePtrAndLen
lda index
asl a ; * 16 (name length)
asl a
asl a
asl a
sta name_ptr
lda #>filename_table
sta name_ptr+1
ldy #$00
lda (name_ptr),y
sta name_len
rts
.endproc
;;; ============================================================
.proc DisplayFilename
lda #5
sta CH
lda index
clc
adc #$05
jsr TABV
jsr space
ldx index
lda type_table,x ; folder?
bmi :+ ; nope
lda #HI('/') ; yes - suffix with '/'
jsr Cout
: jsr SetNamePtrAndLen
: iny
lda (name_ptr),y
jsr Cout
cpy name_len
bcc :-
space: lda #HI(' ')
jmp Cout
.endproc
;;; ============================================================
.proc AssignRefNum
lda open_ref_num
sta read_ref_num
sta get_eof_ref_num ; also set_mark_position
rts
.endproc
;;; ============================================================
default_devnum:
.byte 0
;;; ============================================================
;;; Messages
;;; ============================================================
message_table:
msg_select_drive := * - message_table
scrcode "TAB: SELECT DRIVE\r"
.byte 0
msg_select_file := * - message_table
scrcode "RETURN: SELECT FILE\r\r"
.byte 0
;;; ============================================================
;;; Parameter Blocks
;;; ============================================================
;;; OPEN params
open_params:
.byte 3
open_pathname:
.addr PREFIX
open_io_buffer:
.addr $1800
open_ref_num:
.byte 0
;;; CLOSE params
close_params:
.byte 1
.byte 0
;;; ON_LINE params
on_line_params:
.byte $02
on_line_unit_num:
.byte $60
on_line_buffer:
.addr PREFIX+1
;;; READ params
read_params:
.byte 4
read_ref_num:
.byte 0
read_data_buffer:
.addr $2000
read_request_count:
.word 0
read_transfer_count:
.word 0
;;; SET_PREFIX params
set_prefix_params:
.byte 1
.addr PREFIX
;;; GET_EOF params
;;; SET_MARK params
get_eof_params:
set_mark_params:
.byte 2
get_eof_ref_num:
set_mark_ref_num:
.byte 0
get_eof_eof:
set_mark_position:
.faraddr $A0A0A0
;;; ------------------------------------------------------------
.endproc
.assert .sizeof(bbb) - bbb <= $300, error, "Must fit in $300 bytes"
install_size = $300
poporg
;;; ************************************************************
.include "../inc/driver_postamble.inc"
;;; ************************************************************

View File

@ -1,6 +1,7 @@
;;; Disassembly of BYE.SYSTEM (Bird's Better Bye)
;;; Enhancements to the 80-column ProDOS 8 Selector ("BYE") found in
;;; ProDOS 1.9 and 2.0.x.
;;;
;;; 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)
;;; * installs, then chains to next .SYSTEM file

View File

@ -1,6 +1,7 @@
;;; Disassembly of BYE.SYSTEM (Bird's Better Bye)
;;; Modifications by Joshua Bell inexorabletash@gmail.com
;;; * installs, then chains to next .SYSTEM file
;;; Disassembly of the ProDOS 8 Selector ("BYE") found in ProDOS 1.9
;;; and 2.0.x and installed automatically for 80-column systems.
;;;
;;; Installer wrapper added by Joshua Bell inexorabletash@gmail.com
.setcpu "65C02"
.linecont +

View File

@ -1,6 +1,9 @@
;;; Disassembly of ProDOS 1.x's QUIT handler (program selector)
;;; Modifications by Joshua Bell inexorabletash@gmail.com
;;; * installs, then chains to next .SYSTEM file
;;; Disassembly of ProDOS QUIT handler (program selector)
;;; This is a 40-column selector that prompts for prefix/pathname,
;;; installed by default except on 80-column systems in 1.9 and
;;; later.
;;;
;;; Installer wrapper added by Joshua Bell inexorabletash@gmail.com
.setcpu "6502"
.linecont +