From fbd79badee5d8a71433b3de0f696c7956958b119 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sun, 24 Feb 2019 20:03:51 -0800 Subject: [PATCH 01/18] initial snapshot --- Makefile | 29 ++ inc/apple2.inc | 27 ++ inc/macros.inc | 101 +++++++ inc/prodos.inc | 473 ++++++++++++++++++++++++++++++ ram.system.s | 780 +++++++++++++++++++++++++++++++++++++++++++++++++ res/go.sh | 18 ++ res/util.sh | 15 + 7 files changed, 1443 insertions(+) create mode 100644 Makefile create mode 100644 inc/apple2.inc create mode 100644 inc/macros.inc create mode 100644 inc/prodos.inc create mode 100644 ram.system.s create mode 100755 res/go.sh create mode 100644 res/util.sh diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8d8087f --- /dev/null +++ b/Makefile @@ -0,0 +1,29 @@ + +CC65 = ~/dev/cc65/bin +CAFLAGS = --target apple2enh --list-bytes 0 +CCFLAGS = --config apple2-asm.cfg + +OUTDIR = out + +HEADERS = $(wildcard inc/*.inc) + +TARGETS = $(OUTDIR)/ram.system.SYS + +.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) + $(CC65)/ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< + +# System Files .SYS +$(OUTDIR)/%.SYS: $(OUTDIR)/%.o + $(CC65)/ld65 $(CCFLAGS) -o '$@' $< + xattr -wx prodos.AuxType '00 20' $@ diff --git a/inc/apple2.inc b/inc/apple2.inc new file mode 100644 index 0000000..c0fdbdc --- /dev/null +++ b/inc/apple2.inc @@ -0,0 +1,27 @@ +;;; ============================================================ +;;; +;;; More Apple II Symbols +;;; +;;; ============================================================ + +;;; Soft Switches + +ROMIN2 := $C082 + +;;; ============================================================ +;;; Aux Memory / Extended 80 Column Card +;;; ============================================================ + +;;; Softswitches +RAMRDOFF := $C002 +RAMRDON := $C003 +RAMWRTOFF := $C004 +RAMWRTON := $C005 +ALTZPOFF := $C008 +ALTZPON := $C009 + +CLR80VID := $C00C +SET80VID := $C00D +RDALTZP := $C016 +RD80STORE := $C018 +RDPAGE2 := $C01C diff --git a/inc/macros.inc b/inc/macros.inc new file mode 100644 index 0000000..4bf6838 --- /dev/null +++ b/inc/macros.inc @@ -0,0 +1,101 @@ +;;; ============================================================ +;;; 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 + +;;; ============================================================ +;;; 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 diff --git a/inc/prodos.inc b/inc/prodos.inc new file mode 100644 index 0000000..b3ccfb3 --- /dev/null +++ b/inc/prodos.inc @@ -0,0 +1,473 @@ +;;; ============================================================ +;;; +;;; 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 + +;;; ============================================================ +;;; 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 diff --git a/ram.system.s b/ram.system.s new file mode 100644 index 0000000..018728c --- /dev/null +++ b/ram.system.s @@ -0,0 +1,780 @@ +;;; Disassembly of "RAM.SYSTEM" found on Mouse Desk 2.0 images + + .setcpu "6502" + + .include "apple2.inc" + .include "inc/macros.inc" + .include "inc/apple2.inc" + .include "inc/prodos.inc" + .include "opcodes.inc" + + + +zpproc_addr := $B0 +zpproc_relay_addr := $2D0 +chain_path := $280 + +driver_target = $FF00 + +kMaxUsableBanks = 24 ; Why is this capped so low??? + ; (driver has room for another ~20?) + +;;; ============================================================ +;;; RamWorks I/O + +RWBANK := $C073 + +;;; ============================================================ + + .org $2000 + + jmp relocate_chain + +;;; ============================================================ + + ;; Interpreter signature + .byte $EE,$EE + + ;; Buffer size + .byte 64 + +chain_path_orig: + PASCAL_STRING "/MOUSE.DESK/MD.SYSTEM", 63 + + .byte $FF, $FF + +;;; Configuration Parameters + +banks_to_reserve: .byte 0 ; banks to reserve (e.g. for AppleWorks) + +slot: .byte 3 ; S3D1; could be $B for S3D2 + + +;;; ============================================================ +;;; Chain to the next system file (path above) +;;; ============================================================ +;;; +;;; Relocated to $BD00 to leave room at $2000 for the sys file. + + chain_target = $BD00 + + saved_org .set * +.proc chain + .org ::chain_target + + ;; Copy path to $280 + ldx chain_path_orig + beq quit +: lda chain_path_orig,x + sta chain_path,x + dex + bpl :- + + MLI_CALL GET_FILE_INFO, get_file_info_params + bcs quit + + ldx get_file_info_params_file_type + inx + bne quit + MLI_CALL OPEN, open_params + bcs close + lda open_params_ref_num + sta read_params_ref_num + sta get_eof_params_ref_num + + MLI_CALL GET_EOF, get_eof_params + bcs close + + ;; Ensure there is room for chained file + lda get_eof_params_eof+2 + bne close + lda get_eof_params_eof+1 + cmp #$98 ; $2000+$97FF=$B7FF (have up to $BF00) + bcs close + sta read_params_request_count+1 + lda get_eof_params_eof + sta read_params_request_count + + ;; Read + MLI_CALL READ, read_params + bcs close + + ;; Close + MLI_CALL CLOSE, close_params + bcs close + + ;; Invoke it + jmp sys_target + +close: MLI_CALL CLOSE, close_params + +quit: MLI_CALL QUIT, quit_params + + DEFINE_QUIT_PARAMS quit_params + + sys_target := $2000 + io_buff := $1C00 + + DEFINE_GET_FILE_INFO_PARAMS get_file_info_params, chain_path + get_file_info_params_file_type := get_file_info_params::file_type + + DEFINE_OPEN_PARAMS open_params, chain_path, io_buff + open_params_ref_num := open_params::ref_num + + DEFINE_CLOSE_PARAMS close_params + + DEFINE_READ_PARAMS read_params, sys_target, 0 + read_params_ref_num := read_params::ref_num + read_params_request_count := read_params::request_count + + DEFINE_GET_EOF_PARAMS get_eof_params + get_eof_params_ref_num := get_eof_params::ref_num + get_eof_params_eof := get_eof_params::eof + +.endproc + .assert .sizeof(chain) <= $100, error, "Chain routine must fit in one page" + .org (saved_org + .sizeof(chain)) + +;;; ============================================================ +;;; Copy chain code to final location + +.proc relocate_chain + ldy #$00 +: lda chain,y + sta chain_target,y + iny + bne :- + ;; fall through +.endproc + +;;; ============================================================ +;;; Install the driver + +.proc install_driver + + sta CLR80COL + ldy #0 + sty RWBANK + sta ALTZPON ; Use ZP to probe banks + + ;; Clear map1 / map2 (256 bytes) to $FF + lda #$FF +: sta map1,y + iny + bne :- + + ;; Stash first two bytes of each bank (128 possible banks) +: sty RWBANK + lda $00 + sta stash_00,y + lda $01 + sta stash_01,y + iny + bpl :- + dey + + ;; Write bank num/complement at $0/$1 +: sty RWBANK + sty $00 + tya + eor #$FF + sta $01 + dey + bne :- + + ;; Y = 0 + + ;; Reset signature bytes on main/aux banks + sty RWBANK + sty $00 + sty $01 + sta ALTZPOFF + sty $00 + sty $01 + sta ALTZPON + + lda banks_to_reserve + sta reserved_banks + +;;; ============================================================ + + ;; Copy into every bank + ldy #1 +bank_loop: + ;; Check bank for signature bytes (bank num/complement at $0/$1) + sty RWBANK + cpy $00 + bne next_bank + tya + eor #$FF + eor $01 + bne next_bank + cpy $00 ; Bank 0 (aux) is reserved for 128k apps + bne next_bank + + ;; Flag as available in map2 + ;; (map2,N = N if available, $FF otherwise) + tya + sta map2,y + + ;; Skip over reserved banks, then start storing them in the map + ldx reserved_banks + bne :+ + sta first_used_bank +: dec reserved_banks + bpl next_bank + sta map1,y + ;; (map1,N = N if available, $FF otherwise - also???) + + ;; Copy helper proc into bank's ZP + ldx #sizeof_zpproc +: lda zpproc-1,x + sta zpproc_addr-1,x + dex + bne :- + +next_bank: + iny + bpl bank_loop + +;;; ============================================================ + + ;; Y = $80 + + ;; Restore stashed $0/$1 bytes of back + ;; (except first, in first_used_bank ???) +loop0: lda map2-1,y + bmi :+ + cmp first_used_bank + beq :+ + sta RWBANK + lda stash_00-1,y + sta $00 + lda stash_01-1,y + sta $01 +: dey + bne loop0 + + ;; Y = 0 + sty RWBANK + sty $00 + + ;; Count number of available banks, and populate + ;; driver_bank_list with list of banks. + ldx #$FF +loop1: inx + cpx #kMaxUsableBanks + bcs break +loop2: iny + bmi break + lda map1,y + bmi loop2 + sta driver_bank_list,x + bpl loop1 +break: + ;; Patch driver with block-specific data + ;; X = number of available banks + + ;; Compute number of blocks + txa + lsr a + sta vol_dir_header+VolumeDirectoryHeader::total_blocks+1 + ror vol_dir_header+VolumeDirectoryHeader::total_blocks + + stx driver_block_x ; num banks + dex ; -1 + stx num_banks_minus_one + + bmi fail ; 0 banks? give up. + + lda vol_dir_header+VolumeDirectoryHeader::total_blocks + sec + sbc driver_block_x + and #$F8 + sta vol_dir_header+VolumeDirectoryHeader::total_blocks + sta driver_blocks_lo + bcs :+ + dec vol_dir_header+VolumeDirectoryHeader::total_blocks+1 +: lda vol_dir_header+VolumeDirectoryHeader::total_blocks+1 + sta driver_blocks_hi + + lda driver_bank_list + sta RWBANK + lda $00 + beq fail + + ;; Check for ZP signature - if not found, set it and install. + ldx #2 +: lda L23A0,x + cmp $06,x + bne set_sig + dex + bpl :- + + bit BUTN1 ; escape hatch in case of loop ??? + bmi L21F0 + jmp do_install + +fail: jmp do_chain + +sloop: lda L23A0,x +set_sig: + sta $06,x + dex + bpl sloop + +;;; ============================================================ + +;;; Prepare key blocks in + +L21F0: sta ALTZPOFF + + ;; Stamp current date/time into vol_dir_header + ldy #3 +: lda DATELO,y + sta vol_dir_header+VolumeDirectoryHeader::creation_date,y + dey + bpl :- + + ;; Fill pages $06-$0F with 00-FF + sta RAMWRTON + iny + tya +: sta $0600,y + sta $0700,y + sta $0800,y + sta $0900,y + sta $0A00,y + sta $0B00,y + sta $0C00,y + sta $0D00,y + sta $0E00,y + sta $0F00,y + iny + bne :- + + ;; Copy vol_dir_header into page $06 + ldy #.sizeof(VolumeDirectoryHeader)-1 +: lda vol_dir_header,y + sta $0600,y + dey + bpl :- + + ldy #$02 + sty $0800 + iny + sty $0A00 + iny + sty $0C00 + sty $0802 + iny + sty $0A02 + + ptr := $3C + lda vol_dir_header+VolumeDirectoryHeader::total_blocks + sta ptr + lda vol_dir_header+VolumeDirectoryHeader::total_blocks+1 + lsr a + ror ptr + lsr a + ror ptr + lsr a + ror ptr + clc + adc #$0E + sta ptr+1 + + ldy #0 + tya +: sta (ptr),y + lda ptr + sec + sbc #1 + sta ptr + lda #$FF + bcs :- + dec ptr+1 + ldx ptr+1 + cpx #$0E + bcs :- + lda #$01 + sta $0E00 + +;;; ============================================================ + +do_install: + lda #0 + sta RAMWRTOFF + sta ALTZPOFF + sta RWBANK + bit LCBANK1 + bit LCBANK1 + + lda #OPC_CLD ; signature + cmp driver_target + beq copy_driver + sta ALTZPON ; Maybe in AUX? + cmp driver_target + beq copy_driver + cmp $DE00 ; ??? + beq copy_driver + sta ALTZPOFF + + ;; Copy driver into place +copy_driver: + ldy #0 +: lda driver_src,y + sta driver_target,y + iny + cpy #sizeof_driver + bcc :- + + ;; Check if slot already has a device + ldy DEVCNT +: lda DEVLST,y + lsr a + lsr a + lsr a + lsr a + cmp slot + beq install_device + dey + bpl :- + + ;; Shift devices up by one + inc DEVCNT + ldy DEVCNT +: lda DEVLST-1,y + sta DEVLST,y + dey + bne :- + + ;; Install device in ProDOS via DEVLST/DEVADR. + ;; (Y has index in DEVLST) +install_device: + lda slot + asl a + tax + asl a + asl a + asl a + sta on_line_params+1 ; unit_number + ora #$0E ; $3E - signature byte used by DeskTop + sta DEVLST,y + copy16 #(driver_target+1), DEVADR,x + + ;; Did we install into S3D2? + lda slot + cmp #$0B ; Slot 3 Drive 2 + beq finish + + ;; No, so uninstall S3D2 (regular /RAM) + ldy DEVCNT +: lda DEVLST,y + and #$F0 + cmp #$B0 ; Slot 3 drive 2 i.e. normal /RAM + beq found + dey + bpl :- + bmi finish ; always + + ;; Actually remove from DEVLST + slot3d2_devadr := DEVADR + $10 + 3*2 +found: ldx slot3d2_devadr + 1 + inx + bne finish +: copy DEVLST+1,y, DEVLST,y + iny + cpy DEVCNT + bcc :- + beq :- + dec DEVCNT + copy16 NODEV, slot3d2_devadr ; clear driver + +finish: bit ROMIN2 + MLI_CALL ON_LINE, on_line_params + ldx #$00 + lda on_line_params_buffer + ora L239F + bne do_chain + bcc do_chain + copy #$FF, L239F + sta ALTZPON + copy driver_bank_list, RWBANK + stx $06 + stx RWBANK + stx vol_dir_header+VolumeDirectoryHeader::total_blocks + jmp install_driver ; retry??? + +do_chain: + sta ALTZPOFF + jmp chain_target + +;;; ============================================================ +;;; Installed on zero page of each bank at $B0 + + saved_org .set * +.proc zpproc + .org ::zpproc_addr + + sta $E0 ; dst1 hi + bcs :+ + sty $E0 ; dst1 hi + tay +: lda #$00 + sta RAMWRTON + bcc :+ + txa + ldx #$00 + sta RAMWRTOFF + sta RAMRDON + + ;; One block = two pages +: sty $DD ; src1 hi + iny + sty $E3 ; src2 hi + + sta $DF ; dst1 lo + sta $E5 ; dst2 lo + + stx $DC ; src1 lo + stx $E2 ; src2 lo + + ldy $E0 ; dst1 hi + iny + sty $E6 ; dst2 hi + + ldy #$00 +: lda $1000,y ; src1 + sta $1000,y ; dst1 + lda $1000,y ; src2 + sta $1000,y ; dst2 + iny + bne :- + + sta RAMWRTOFF + sta RAMRDOFF + clc + bit $02E4 + rts +.endproc + sizeof_zpproc := .sizeof(zpproc) + .org (saved_org + .sizeof(zpproc)) + +;;; ============================================================ + + on_line_params_buffer := $220 + DEFINE_ON_LINE_PARAMS on_line_params, $30, on_line_params_buffer + +num_banks_minus_one: + .byte 0 + +L239F: .byte 0 +L23A0: .byte $C7, $C5, $C2 ; signature sequence ??? + + ;; Volume Directory Header +.proc vol_dir_header + .word 0 ; preceding block number + .word $03 ; succeeding block number + .byte ST_VOLUME_DIRECTORY << 4 | 3 ; storage type / name length + .byte "RAM" ; name field is 15 bytes + .res 15-3 + .res 8, 0 ; reserved (8 bytes) + .word 0, 0 ; creation date/time + .byte 1 ; version (1 = ProDOS 2.0) + .byte 0 ; min_version + .byte ACCESS_DEFAULT ; access + .byte $27 ; entry_length + .byte $D ; entries_per_block + .word 0 ; file_count + .word 6 ; bit_map_pointer +blocks: .word 0 ; total_blocks +.endproc + .assert .sizeof(vol_dir_header) = .sizeof(VolumeDirectoryHeader), error, "Size mismatch" + +.endproc + +;;; ============================================================ +;;; Ram Disk Driver - installed at $FF00 +;;; ============================================================ + + saved_org .set * +.proc driver_src + .org ::driver_target + driver_start := * + +start: cld ; used as a signature + + lda DRIVER_COMMAND + bne not_status + driver_blocks_lo := *+1 + ldx #0 ; self-modified - blocks low + driver_blocks_hi := *+1 + ldy #0 ; self-modified - blocks high +LFF09: clc + bcc LFF83 ; always + +not_status: + cmp #DRIVER_COMMAND_FORMAT + beq LFF09 + + ;; COMMAND_READ or COMMAND_WRITE +LFF10: lda #$27 + bcs rts1 + + lda RD80STORE + pha + sta CLR80COL + + ;; Save $40/41 + lda $40 + pha + lda $41 + pha + + lda DRIVER_BUFFER + sta $40 + ldx DRIVER_BUFFER+1 + inx + stx $41 + + jsr install_zpproc_relay + + zpproc_relay_patch1_offset := $04 + stx zpproc_relay_addr + zpproc_relay_patch1_offset + lda RDALTZP + + zpproc_relay_patch2_offset := $14 + sta zpproc_relay_addr + zpproc_relay_patch2_offset + lda DRIVER_BLOCK_NUMBER+1 + pha + tax + lda DRIVER_BLOCK_NUMBER +LFF3C: sec +: iny + sbc #$7F + bcs :- + dex + bpl LFF3C + + tya + adc DRIVER_BLOCK_NUMBER + bcc :+ + inc DRIVER_BLOCK_NUMBER+1 +: asl a + tay + lda DRIVER_BLOCK_NUMBER+1 + rol a + tax + pla + sta DRIVER_BLOCK_NUMBER+1 + driver_block_x := *+1 + cpx #$0 ; self-modified - ??? + bcs LFF74 + + tya + sbc #191 + cmp #16 + bcs :+ + adc #208 + + tay + bit LCBANK2 +: lda DRIVER_COMMAND + lsr a ; carry set = READ, clear = WRITE + lda bank_list,x + ldx DRIVER_BUFFER + jsr zpproc_relay_addr + bit LCBANK1 + +LFF74: jsr install_zpproc_relay + + ;; Restore $40/41 + pla + sta $41 + pla + sta $40 + + pla + bpl LFF83 + sta SET80COL +LFF83: lda #$00 + bcs LFF10 + +rts1: rts + +install_zpproc_relay: + ldy #sizeof_zpproc_relay+1 +: ldx zpproc_relay-1,y + lda zpproc_relay_addr-1,y + sta zpproc_relay-1,y + txa + sta zpproc_relay_addr-1,y + dey + bne :- + + ldx DRIVER_BUFFER+1 + bpl done + bit DRIVER_BUFFER+1 + bvc done + +: ldx $8000,y + lda (DRIVER_BUFFER),y + sta $8000,y + txa + sta (DRIVER_BUFFER),y + ldx $8100,y + lda ($40),y + sta $8100,y + txa + sta ($40),y + iny + bne :- + + ldx #$80 +done: rts + +bank_list: + .res ::kMaxUsableBanks, 0 + +.proc zpproc_relay + sta RWBANK + + patch_loc1 := *+1 + lda #$00 + sta ALTZPON + jsr zpproc_addr + sty RWBANK + bmi :+ + sta ALTZPOFF +: rts + + patch_loc2 := * +.endproc + sizeof_zpproc_relay := .sizeof(zpproc_relay) + patch_loc1_offset := zpproc_relay::patch_loc1 - zpproc_relay + patch_loc2_offset := zpproc_relay::patch_loc2 - zpproc_relay + ;; These offsets can't be used directly due to ca65 addressing mode + ;; assumptions, so just verify they are correct. + .assert zpproc_relay_patch1_offset = patch_loc1_offset, error, "Offset mismatch" + .assert zpproc_relay_patch2_offset = patch_loc2_offset, error, "Offset mismatch" + + .byte 0 + +.endproc + sizeof_driver := .sizeof(driver_src) + .org (saved_org + .sizeof(driver_src)) + + driver_blocks_lo := driver_src + driver_src::driver_blocks_lo - driver_src::driver_start + driver_blocks_hi := driver_src + driver_src::driver_blocks_hi - driver_src::driver_start + driver_block_x := driver_src + driver_src::driver_block_x - driver_src::driver_start + driver_bank_list := driver_src + driver_src::bank_list - driver_src::driver_start + +;;; Scratch space beyond code used during install + +reserved_banks := * +first_used_bank := *+1 +map1 := *+2 +map2 := *+2+$80 +stash_00 := *+2+$100 +stash_01 := *+2+$180 diff --git a/res/go.sh b/res/go.sh new file mode 100755 index 0000000..c36ecb7 --- /dev/null +++ b/res/go.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +# Run this from the ram.system directory + +set -e +source "res/util.sh" + +function verify { + diff "orig/$1" "out/$2" \ + && (cecho green "diff $2 good" ) \ + || (tput blink ; cecho red "DIFF $2 BAD" ; return 1) +} + + +#do_make clean +do_make all + +verify "RAM.SYSTEM.SYS" "ram.system.SYS" diff --git a/res/util.sh b/res/util.sh new file mode 100644 index 0000000..a2de088 --- /dev/null +++ b/res/util.sh @@ -0,0 +1,15 @@ +function cecho { + case $1 in + red) tput setaf 1 ; shift ;; + green) tput setaf 2 ; shift ;; + yellow) tput setaf 3 ; shift ;; + esac + echo -e "$@" + tput sgr0 +} + +function do_make { + make $MAKE_FLAGS "$1" \ + && (cecho green "make $1 good") \ + || (tput blink ; cecho red "MAKE $1 BAD" ; return 1) +} From a2bc49a38bed0928f843df6f4a988f5bed0f7867 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sun, 24 Feb 2019 20:05:42 -0800 Subject: [PATCH 02/18] Add README --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..7e34657 --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# Disassembly of Glen E. Bredon's `RAM.DRV.SYSTEM` for the Apple II + +This was started before realizing what the origin of the `RAM.SYSTEM` file was. + +There is a more complete diassembly with commentary at: + +http://boutillon.free.fr/Underground/Outils/Ram_Drv_System/Ram_Drv_System.html From 4d4a164e308fba229f6388908b409d9381155117 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 14 Jun 2019 21:00:53 -0700 Subject: [PATCH 03/18] Signature bytes --- ram.system.s | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/ram.system.s b/ram.system.s index 018728c..583b536 100644 --- a/ram.system.s +++ b/ram.system.s @@ -3,12 +3,14 @@ .setcpu "6502" .include "apple2.inc" + .include "apple2.mac" .include "inc/macros.inc" .include "inc/apple2.inc" .include "inc/prodos.inc" .include "opcodes.inc" +zp_sig_addr := $06 zpproc_addr := $B0 zpproc_relay_addr := $2D0 @@ -304,9 +306,9 @@ break: beq fail ;; Check for ZP signature - if not found, set it and install. - ldx #2 -: lda L23A0,x - cmp $06,x + ldx #sig_len-1 +: lda sig,x + cmp zp_sig_addr,x bne set_sig dex bpl :- @@ -317,9 +319,9 @@ break: fail: jmp do_chain -sloop: lda L23A0,x +sloop: lda sig,x set_sig: - sta $06,x + sta zp_sig_addr,x dex bpl sloop @@ -570,7 +572,9 @@ num_banks_minus_one: .byte 0 L239F: .byte 0 -L23A0: .byte $C7, $C5, $C2 ; signature sequence ??? + +sig: scrcode "GEB" ; signature sequence - Glen E. Bredon + sig_len = * - sig ;; Volume Directory Header .proc vol_dir_header From 9d424a4e011fb575a946ab39b92eb256fff4bf64 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 14 Jun 2019 21:23:24 -0700 Subject: [PATCH 04/18] Add pushorg/poporg macros --- inc/macros.inc | 17 +++++++++++++++++ ram.system.s | 28 ++++++++++++++-------------- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/inc/macros.inc b/inc/macros.inc index 4bf6838..23a2307 100644 --- a/inc/macros.inc +++ b/inc/macros.inc @@ -23,6 +23,23 @@ .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 ;;; diff --git a/ram.system.s b/ram.system.s index 583b536..b05813c 100644 --- a/ram.system.s +++ b/ram.system.s @@ -1,5 +1,7 @@ ;;; Disassembly of "RAM.SYSTEM" found on Mouse Desk 2.0 images +;;; Some details c/o http://boutillon.free.fr/Underground/Outils/Ram_Drv_System/Ram_Drv_System.html + .setcpu "6502" .include "apple2.inc" @@ -60,9 +62,8 @@ slot: .byte 3 ; S3D1; could be $B for S3D2 chain_target = $BD00 - saved_org .set * .proc chain - .org ::chain_target + pushorg ::chain_target ;; Copy path to $280 ldx chain_path_orig @@ -133,9 +134,9 @@ quit: MLI_CALL QUIT, quit_params get_eof_params_ref_num := get_eof_params::ref_num get_eof_params_eof := get_eof_params::eof + poporg .endproc .assert .sizeof(chain) <= $100, error, "Chain routine must fit in one page" - .org (saved_org + .sizeof(chain)) ;;; ============================================================ ;;; Copy chain code to final location @@ -342,15 +343,15 @@ L21F0: sta ALTZPOFF sta RAMWRTON iny tya -: sta $0600,y +: sta $0600,y ; Block 2 - volume dir sta $0700,y - sta $0800,y + sta $0800,y ; Block 3 - volume dir sta $0900,y - sta $0A00,y + sta $0A00,y ; Block 4 - volume dir sta $0B00,y - sta $0C00,y + sta $0C00,y ; Block 5 - volume dir sta $0D00,y - sta $0E00,y + sta $0E00,y ; Block 6 - volume bitmap sta $0F00,y iny bne :- @@ -515,9 +516,8 @@ do_chain: ;;; ============================================================ ;;; Installed on zero page of each bank at $B0 - saved_org .set * .proc zpproc - .org ::zpproc_addr + pushorg ::zpproc_addr sta $E0 ; dst1 hi bcs :+ @@ -559,9 +559,10 @@ do_chain: clc bit $02E4 rts + + poporg .endproc sizeof_zpproc := .sizeof(zpproc) - .org (saved_org + .sizeof(zpproc)) ;;; ============================================================ @@ -602,9 +603,8 @@ blocks: .word 0 ; total_blocks ;;; Ram Disk Driver - installed at $FF00 ;;; ============================================================ - saved_org .set * .proc driver_src - .org ::driver_target + pushorg ::driver_target driver_start := * start: cld ; used as a signature @@ -765,9 +765,9 @@ bank_list: .byte 0 + poporg .endproc sizeof_driver := .sizeof(driver_src) - .org (saved_org + .sizeof(driver_src)) driver_blocks_lo := driver_src + driver_src::driver_blocks_lo - driver_src::driver_start driver_blocks_hi := driver_src + driver_src::driver_blocks_hi - driver_src::driver_start From 6edbfa48ac2bb639ea64b4861dda6be98293d9d6 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Mon, 17 Jun 2019 20:45:00 -0700 Subject: [PATCH 05/18] Rename to match original --- .gitignore | 8 ++++++++ Makefile | 2 +- README.md | 3 ++- orig/RAM.SYSTEM.SYS | Bin 0 -> 1209 bytes ram.system.s => ram.drv.system.s | 0 res/go.sh | 4 ++-- 6 files changed, 13 insertions(+), 4 deletions(-) create mode 100644 .gitignore create mode 100644 orig/RAM.SYSTEM.SYS rename ram.system.s => ram.drv.system.s (100%) diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ce49713 --- /dev/null +++ b/.gitignore @@ -0,0 +1,8 @@ +# Build directory +out + +# Directory mounted in Virtual ][ as a ProDOS volume +mount + +# OS-specific files +.DS_Store diff --git a/Makefile b/Makefile index 8d8087f..b5dd72a 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ OUTDIR = out HEADERS = $(wildcard inc/*.inc) -TARGETS = $(OUTDIR)/ram.system.SYS +TARGETS = $(OUTDIR)/ram.drv.system.SYS .PHONY: clean all all: $(OUTDIR) $(TARGETS) diff --git a/README.md b/README.md index 7e34657..f0646db 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ # Disassembly of Glen E. Bredon's `RAM.DRV.SYSTEM` for the Apple II -This was started before realizing what the origin of the `RAM.SYSTEM` file was. +This was started before realizing what the origin of the `RAM.SYSTEM` +found on a MouseDesk 2.0 disk image file was. There is a more complete diassembly with commentary at: diff --git a/orig/RAM.SYSTEM.SYS b/orig/RAM.SYSTEM.SYS new file mode 100644 index 0000000000000000000000000000000000000000..7e862613b5499f36ac25a0062b803728ccf34193 GIT binary patch literal 1209 zcma)5T}&KR6h1Rkw(QbfhsGKVRVTdzNJHAC`hYDYOS4;kx}-+xgD-}d)WC}|!RVv3 z?%=xJyDlnbuLiqW9l{a^r;h^}X3`%WHoJ68is^&eRVzZOWGYoqAI3ZIW;F5U&i(n$ zopZl)?swwf2^$-c14jqWJUbXW5{(U>J~|LRGWgu!+1LR5@8-I|&G`i9dEF;Wjj<(u zO912A%ep!+_lmw|_t2enL06wr-qi6$9lxtn;LCS(^>O8W-A2l!zLZlB;JsoE} zV=1Mpb#yK#b(M>Qu)Cz=xedq|%cdgo>2CZ;FTM)zBQ)!XkNcH0idZ~;uqFBm&gu)$48Fl<3imltYjPOmQ za?2H@R1p3ODQS_qmBD$i!0LIl;5>gl zR#GRW(f?xSZf_U~NnLr!O?1kg9qWwLS#;IS&%36(sv-4mk--ou0^Va%DwK2EMXwic zRls$4nqqIRt-!Yq=TQZ1ncnPL=H2XXpSBy?F{7WhN}u5DPxALR+6@nEH^?y~X>Tcg zLSQx!2;dKqKSZG-GsPQ4cdFi?mZdu9$z2bv&XVfXB>DScG}mIR*^g*Xcn+*`yOF)` z{JPw3D7=B24W-_|Ek@e~lgjS;2dDswzy>cNyD|H4(Z!dLr-z-ikNYyCW~PkdKMRy| z9CWFwa*65;jk3nf`cs9SXgM?Sjg|O8x-I=U{`L6xpH!{HDvb|#0{rf1+4sD(ux3Ns z9d?Kf3sk^gT)zUq!R9mF|5=U`J>pPjw%giFIB!A z>6N>C<){>yj;)P%3rRO~lT{uv@f}v~>7A8Nby(}KtAEkb&7C`yWmkIwGjh-2*8N0{^y#RlVX1pqiVX7{X3Qd}Zw=)SEUviP4VJ99 zDRP5N+Rk*0e@u)$-M9#2m!ky6QWMcdIDa`p;CyN#V%a|x#)fDB|JtZZXe#}tpnBCC J_JlD6e*^nt>v;eG literal 0 HcmV?d00001 diff --git a/ram.system.s b/ram.drv.system.s similarity index 100% rename from ram.system.s rename to ram.drv.system.s diff --git a/res/go.sh b/res/go.sh index c36ecb7..c7ed09f 100755 --- a/res/go.sh +++ b/res/go.sh @@ -1,6 +1,6 @@ #!/bin/bash -# Run this from the ram.system directory +# Run this from the ram.drv.system directory set -e source "res/util.sh" @@ -15,4 +15,4 @@ function verify { #do_make clean do_make all -verify "RAM.SYSTEM.SYS" "ram.system.SYS" +verify "RAM.SYSTEM.SYS" "ram.drv.system.SYS" From d115882280eaca244e232acd06da4f3de1ed688d Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sun, 16 Jun 2019 19:48:09 -0700 Subject: [PATCH 06/18] Chain to next SYSTEM file. Resolves #1 --- inc/apple2.inc | 18 +- inc/prodos.inc | 9 + ram.drv.system.s | 514 +++++++++++++++++++++++++++++++++++------------ res/go.sh | 9 - 4 files changed, 410 insertions(+), 140 deletions(-) diff --git a/inc/apple2.inc b/inc/apple2.inc index c0fdbdc..080d76b 100644 --- a/inc/apple2.inc +++ b/inc/apple2.inc @@ -4,15 +4,10 @@ ;;; ;;; ============================================================ +;;; ============================================================ ;;; Soft Switches - -ROMIN2 := $C082 - -;;; ============================================================ -;;; Aux Memory / Extended 80 Column Card ;;; ============================================================ -;;; Softswitches RAMRDOFF := $C002 RAMRDON := $C003 RAMWRTOFF := $C004 @@ -25,3 +20,14 @@ SET80VID := $C00D RDALTZP := $C016 RD80STORE := $C018 RDPAGE2 := $C01C + +BANKSEL := $C073 ; Select RamWorks bank + +ROMIN2 := $C082 + +;;; ============================================================ +;;; Monitor ROM routines +;;; ============================================================ + +PRBYTE := $FDDA +COUT := $FDED diff --git a/inc/prodos.inc b/inc/prodos.inc index b3ccfb3..ac452c2 100644 --- a/inc/prodos.inc +++ b/inc/prodos.inc @@ -135,6 +135,15 @@ ERR_NETWORK_ERROR = $88 STORAGE_TYPE_MASK = $F0 NAME_LENGTH_MASK = $0F +;;; Volume Directory Block Header structure +.scope VolumeDirectoryBlockHeader + prev_block := $00 + next_block := $02 + entry_length := $23 + entries_per_block := $24 + header_length := $2B +.endscope + ;;; Volume Directory Header structure .struct VolumeDirectoryHeader prev_block .word diff --git a/ram.drv.system.s b/ram.drv.system.s index b05813c..b224eec 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -1,6 +1,8 @@ ;;; Disassembly of "RAM.SYSTEM" found on Mouse Desk 2.0 images - +;;; Based on Glen E. Bredon's "RAM.DRV.SYSTEM" ;;; Some details c/o http://boutillon.free.fr/Underground/Outils/Ram_Drv_System/Ram_Drv_System.html +;;; +;;; Modifications to chain to next .SYSTEM file .setcpu "6502" @@ -16,139 +18,94 @@ zp_sig_addr := $06 zpproc_addr := $B0 zpproc_relay_addr := $2D0 -chain_path := $280 -driver_target = $FF00 +PATHNAME := $280 + +data_buffer := $1800 ; I/O when chaining to next SYS file +driver_target := $FF00 ; Install location in ProDOS + kMaxUsableBanks = 24 ; Why is this capped so low??? ; (driver has room for another ~20?) -;;; ============================================================ -;;; RamWorks I/O - -RWBANK := $C073 +SYS_ADDR := $2000 ; Load address for SYS files +SYS_LEN = $BF00 - SYS_ADDR ; Maximum SYS file length ;;; ============================================================ - .org $2000 - jmp relocate_chain + ;; SYS files load at $2000; relocates self to $1000 + .org SYS_ADDR + dst_addr := $1000 ;;; ============================================================ - ;; Interpreter signature - .byte $EE,$EE +.proc relocate + src := SYS_ADDR + dst := $1000 - ;; Buffer size - .byte 64 + ldx #(sys_end - sys_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 + beq find_self_name ; done + jmp load +.endproc -chain_path_orig: - PASCAL_STRING "/MOUSE.DESK/MD.SYSTEM", 63 - .byte $FF, $FF +;;; ============================================================ +;;; Start of relocated code +sys_start: +;;; ============================================================ ;;; Configuration Parameters -banks_to_reserve: .byte 0 ; banks to reserve (e.g. for AppleWorks) - -slot: .byte 3 ; S3D1; could be $B for S3D2 +banks_to_reserve: .byte 0 ; banks to reserve (e.g. for AppleWorks) +slot: .byte 3 ; S3D1; could be $B for S3D2 ;;; ============================================================ -;;; Chain to the next system file (path above) -;;; ============================================================ -;;; -;;; Relocated to $BD00 to leave room at $2000 for the sys file. +;;; Identify the name of this SYS file, which should be present at +;;; $280 with or without a path prefix. This is used when searching +;;; for the next .SYSTEM file to execute. - chain_target = $BD00 +.proc find_self_name + ;; Search pathname buffer backwards for '/', then + ;; copy name into |self_name|; this is used later + ;; to find/invoke the next .SYSTEM file. -.proc chain - pushorg ::chain_target - - ;; Copy path to $280 - ldx chain_path_orig - beq quit -: lda chain_path_orig,x - sta chain_path,x + ;; Find '/' (which may not be present, prefix is optional) + lda #0 + sta $A8 + ldx PATHNAME + beq install_driver +floop: inc $A8 dex - bpl :- + beq copy_name + lda PATHNAME,x + eor #'/' + asl a + bne floop - MLI_CALL GET_FILE_INFO, get_file_info_params - bcs quit - - ldx get_file_info_params_file_type + ;; Copy name into |self_name| buffer +copy_name: + ldy #0 +cloop: iny inx - bne quit - MLI_CALL OPEN, open_params - bcs close - lda open_params_ref_num - sta read_params_ref_num - sta get_eof_params_ref_num - - MLI_CALL GET_EOF, get_eof_params - bcs close - - ;; Ensure there is room for chained file - lda get_eof_params_eof+2 - bne close - lda get_eof_params_eof+1 - cmp #$98 ; $2000+$97FF=$B7FF (have up to $BF00) - bcs close - sta read_params_request_count+1 - lda get_eof_params_eof - sta read_params_request_count - - ;; Read - MLI_CALL READ, read_params - bcs close - - ;; Close - MLI_CALL CLOSE, close_params - bcs close - - ;; Invoke it - jmp sys_target - -close: MLI_CALL CLOSE, close_params - -quit: MLI_CALL QUIT, quit_params - - DEFINE_QUIT_PARAMS quit_params - - sys_target := $2000 - io_buff := $1C00 - - DEFINE_GET_FILE_INFO_PARAMS get_file_info_params, chain_path - get_file_info_params_file_type := get_file_info_params::file_type - - DEFINE_OPEN_PARAMS open_params, chain_path, io_buff - open_params_ref_num := open_params::ref_num - - DEFINE_CLOSE_PARAMS close_params - - DEFINE_READ_PARAMS read_params, sys_target, 0 - read_params_ref_num := read_params::ref_num - read_params_request_count := read_params::request_count - - DEFINE_GET_EOF_PARAMS get_eof_params - get_eof_params_ref_num := get_eof_params::ref_num - get_eof_params_eof := get_eof_params::eof - - poporg -.endproc - .assert .sizeof(chain) <= $100, error, "Chain routine must fit in one page" - -;;; ============================================================ -;;; Copy chain code to final location - -.proc relocate_chain - ldy #$00 -: lda chain,y - sta chain_target,y - iny - bne :- - ;; fall through + lda PATHNAME,x + sta self_name,y + cpy $A8 + bcc cloop + sty self_name .endproc + ;; Fall through... ;;; ============================================================ ;;; Install the driver @@ -157,7 +114,7 @@ quit: MLI_CALL QUIT, quit_params sta CLR80COL ldy #0 - sty RWBANK + sty BANKSEL sta ALTZPON ; Use ZP to probe banks ;; Clear map1 / map2 (256 bytes) to $FF @@ -167,7 +124,7 @@ quit: MLI_CALL QUIT, quit_params bne :- ;; Stash first two bytes of each bank (128 possible banks) -: sty RWBANK +: sty BANKSEL lda $00 sta stash_00,y lda $01 @@ -177,7 +134,7 @@ quit: MLI_CALL QUIT, quit_params dey ;; Write bank num/complement at $0/$1 -: sty RWBANK +: sty BANKSEL sty $00 tya eor #$FF @@ -188,7 +145,7 @@ quit: MLI_CALL QUIT, quit_params ;; Y = 0 ;; Reset signature bytes on main/aux banks - sty RWBANK + sty BANKSEL sty $00 sty $01 sta ALTZPOFF @@ -205,7 +162,7 @@ quit: MLI_CALL QUIT, quit_params ldy #1 bank_loop: ;; Check bank for signature bytes (bank num/complement at $0/$1) - sty RWBANK + sty BANKSEL cpy $00 bne next_bank tya @@ -250,7 +207,7 @@ loop0: lda map2-1,y bmi :+ cmp first_used_bank beq :+ - sta RWBANK + sta BANKSEL lda stash_00-1,y sta $00 lda stash_01-1,y @@ -259,7 +216,7 @@ loop0: lda map2-1,y bne loop0 ;; Y = 0 - sty RWBANK + sty BANKSEL sty $00 ;; Count number of available banks, and populate @@ -302,7 +259,7 @@ break: sta driver_blocks_hi lda driver_bank_list - sta RWBANK + sta BANKSEL lda $00 beq fail @@ -409,7 +366,7 @@ do_install: lda #0 sta RAMWRTOFF sta ALTZPOFF - sta RWBANK + sta BANKSEL bit LCBANK1 bit LCBANK1 @@ -503,15 +460,15 @@ finish: bit ROMIN2 bcc do_chain copy #$FF, L239F sta ALTZPON - copy driver_bank_list, RWBANK + copy driver_bank_list, BANKSEL stx $06 - stx RWBANK + stx BANKSEL stx vol_dir_header+VolumeDirectoryHeader::total_blocks jmp install_driver ; retry??? do_chain: sta ALTZPOFF - jmp chain_target + jmp launch_next_sys_file ;;; ============================================================ ;;; Installed on zero page of each bank at $B0 @@ -742,13 +699,13 @@ bank_list: .res ::kMaxUsableBanks, 0 .proc zpproc_relay - sta RWBANK + sta BANKSEL patch_loc1 := *+1 lda #$00 sta ALTZPON jsr zpproc_addr - sty RWBANK + sty BANKSEL bmi :+ sta ALTZPOFF : rts @@ -774,11 +731,318 @@ bank_list: driver_block_x := driver_src + driver_src::driver_block_x - driver_src::driver_start driver_bank_list := driver_src + driver_src::bank_list - driver_src::driver_start +;;; ============================================================ +;;; Find and invoke the next .SYSTEM file + +.proc launch_next_sys_file + ;; Update reset vector - now terminates. + lda #quit + sta $03F3 + eor #$A5 + sta $03F4 + + ptr := $A5 + num := $A7 + len := $A8 + + lda DEVNUM ; stick with most recent device + sta read_block_params_unit_num + jsr read_block + + lda data_buffer + VolumeDirectoryBlockHeader::entry_length + sta entry_length_mod + lda data_buffer + VolumeDirectoryBlockHeader::entries_per_block + sta entries_per_block_mod + lda #1 + sta num + + lda #<(data_buffer + VolumeDirectoryBlockHeader::header_length) + sta ptr + lda #>(data_buffer + VolumeDirectoryBlockHeader::header_length) + 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+1,x + bne next + dey + dex + bpl :- + + ;; 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 + + lda data_buffer + VolumeDirectoryBlockHeader::next_block + sta read_block_params_block_num + lda data_buffer + VolumeDirectoryBlockHeader::next_block + 1 + sta read_block_params_block_num+1 + ora read_block_params_block_num + beq not_found ; last block has next=0 + jsr read_block + lda #0 + sta num + lda #<(data_buffer + $04) + sta ptr + lda #>(data_buffer + $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 + + ;; Compose the path to invoke. First walk self path + ;; backwards to '/'. + ldx PATHNAME + beq append +: dex + beq append + lda PATHNAME,x + eor #'/' + asl a + bne :- + + ;; Now append name of found file. +append: 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\r* Unable to find next '.SYSTEM' file *\r" + bit KBDSTRB +: lda KBD + bpl :- + bit KBDSTRB + jmp quit +.endproc + +;;; ------------------------------------------------------------ +;;; 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 #'a'|$80 ; 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 + +;;; ------------------------------------------------------------ +;;; COUT a 2-digit number in A + +.proc cout_number + ldx #'0'|$80 + cmp #10 ; >= 10? + bcc tens + + ;; divide by 10, dividend(+'0') in x remainder in a +: sbc #10 + inx + cmp #10 + bcs :- + +tens: pha + cpx #'0'|$80 + beq units + txa + jsr COUT + +units: pla + ora #'0'|$80 + jsr COUT + rts +.endproc + +;;; ------------------------------------------------------------ + +lowercase_mask: + .byte $FF ; Set to $DF on systems w/o lower-case + +;;; ------------------------------------------------------------ +;;; Invoke ProDOS QUIT routine. + +.proc quit + MLI_CALL QUIT, quit_params + .byte 0 ; crash if QUIT fails + rts + +.proc quit_params + .byte 4 ; param_count + .byte 0 ; quit_type + .word 0000 ; reserved + .byte 0 ; reserved + .word 0000 ; reserved +.endproc +.endproc + +;;; ------------------------------------------------------------ +;;; Read a disk block. + +.proc read_block + MLI_CALL READ_BLOCK, read_block_params + bcs on_error + rts +.endproc + +.proc read_block_params + .byte 3 ; param_count +unit_num: .byte $60 ; unit_num + .addr data_buffer ; data_buffer +block_num: .word 2 ; block_num - block 2 is volume directory +.endproc + read_block_params_unit_num := read_block_params::unit_num + read_block_params_block_num := read_block_params::block_num + +;;; ------------------------------------------------------------ +;;; 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 + + 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\r** Disk Error $" + pla + jsr PRBYTE + jsr zstrout + scrcode " **\r" + bit KBDSTRB +: lda KBD + bpl :- + bit KBDSTRB + jmp quit +.endproc + +;;; ------------------------------------------------------------ + +.proc open_params + .byte 3 ; param_count + .addr PATHNAME ; pathname + .addr data_buffer ; io_buffer +ref_num:.byte 1 ; ref_num +.endproc + open_params_ref_num := open_params::ref_num + +.proc read_params + .byte 4 ; param_count +ref_num:.byte 1 ; ref_num + .addr SYS_ADDR ; data_buffer + .word SYS_LEN ; request_count + .word 0 ; trans_count +.endproc + read_params_ref_num := read_params::ref_num + +.proc close_params + .byte 1 ; param_count +ref_num:.byte 0 ; ref_num +.endproc + +;;; ============================================================ +;;; Data + +suffix: + PASCAL_STRING ".SYSTEM" + +found_self_flag: + .byte 0 + +;;; ============================================================ +;;; End of relocated code +sys_end: + +;;; ============================================================ ;;; Scratch space beyond code used during install reserved_banks := * first_used_bank := *+1 -map1 := *+2 -map2 := *+2+$80 -stash_00 := *+2+$100 -stash_01 := *+2+$180 +map1 := *+2 ; len: $80 +map2 := *+2+$80 ; len: $80 +stash_00 := *+2+$100 ; len: $80 +stash_01 := *+2+$180 ; len: $80 +self_name := *+2+$200 ; len: 65 diff --git a/res/go.sh b/res/go.sh index c7ed09f..0aaa01d 100755 --- a/res/go.sh +++ b/res/go.sh @@ -5,14 +5,5 @@ set -e source "res/util.sh" -function verify { - diff "orig/$1" "out/$2" \ - && (cecho green "diff $2 good" ) \ - || (tput blink ; cecho red "DIFF $2 BAD" ; return 1) -} - - #do_make clean do_make all - -verify "RAM.SYSTEM.SYS" "ram.drv.system.SYS" From 903cd4ff1e11dc550e96403416388510f4116732 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 18 Jun 2019 22:10:49 -0700 Subject: [PATCH 07/18] Fix chaining --- inc/apple2.inc | 1 + inc/prodos.inc | 9 -- ram.drv.system.s | 224 +++++++++++++++++++++++++---------------------- 3 files changed, 118 insertions(+), 116 deletions(-) diff --git a/inc/apple2.inc b/inc/apple2.inc index 080d76b..144c53c 100644 --- a/inc/apple2.inc +++ b/inc/apple2.inc @@ -29,5 +29,6 @@ ROMIN2 := $C082 ;;; Monitor ROM routines ;;; ============================================================ +HOME := $FC58 PRBYTE := $FDDA COUT := $FDED diff --git a/inc/prodos.inc b/inc/prodos.inc index ac452c2..b3ccfb3 100644 --- a/inc/prodos.inc +++ b/inc/prodos.inc @@ -135,15 +135,6 @@ ERR_NETWORK_ERROR = $88 STORAGE_TYPE_MASK = $F0 NAME_LENGTH_MASK = $0F -;;; Volume Directory Block Header structure -.scope VolumeDirectoryBlockHeader - prev_block := $00 - next_block := $02 - entry_length := $23 - entries_per_block := $24 - header_length := $2B -.endscope - ;;; Volume Directory Header structure .struct VolumeDirectoryHeader prev_block .word diff --git a/ram.drv.system.s b/ram.drv.system.s index b224eec..4143a17 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -2,7 +2,10 @@ ;;; Based on Glen E. Bredon's "RAM.DRV.SYSTEM" ;;; Some details c/o http://boutillon.free.fr/Underground/Outils/Ram_Drv_System/Ram_Drv_System.html ;;; -;;; Modifications to chain to next .SYSTEM file +;;; Modifications: +;;; * Chain to next .SYSTEM file dynamically + + .feature string_escapes .setcpu "6502" @@ -21,18 +24,19 @@ zpproc_relay_addr := $2D0 PATHNAME := $280 -data_buffer := $1800 ; I/O when chaining to next SYS file +data_buf := $1C00 ; I/O when chaining to next SYS file driver_target := $FF00 ; Install location in ProDOS kMaxUsableBanks = 24 ; Why is this capped so low??? ; (driver has room for another ~20?) -SYS_ADDR := $2000 ; Load address for SYS files +SYS_ADDR := $2000 ; Load address for SYS files SYS_LEN = $BF00 - SYS_ADDR ; Maximum SYS file length -;;; ============================================================ + .define PRODUCT "RAMWorks RAM Disk" +;;; ============================================================ ;; SYS files load at $2000; relocates self to $1000 .org SYS_ADDR @@ -42,70 +46,41 @@ SYS_LEN = $BF00 - SYS_ADDR ; Maximum SYS file length .proc relocate src := SYS_ADDR - dst := $1000 ldx #(sys_end - sys_start + $FF) / $100 ; pages ldy #0 -load: lda src,y ; self-modified +load: lda sys_start,y ; self-modified load_hi := *-1 - sta dst,y ; self-modified + sta dst_addr,y ; self-modified store_hi := *-1 iny bne load inc load_hi inc store_hi dex - beq find_self_name ; done - jmp load + bne load + + jmp dst_addr .endproc ;;; ============================================================ ;;; Start of relocated code sys_start: + pushorg dst_addr + + ;; Save most recent device for later, when chaining + ;; to next .SYSTEM file. + lda DEVNUM + sta read_block_params_unit_num + + jmp install_driver ;;; ============================================================ ;;; Configuration Parameters -banks_to_reserve: .byte 0 ; banks to reserve (e.g. for AppleWorks) - -slot: .byte 3 ; S3D1; could be $B for S3D2 - -;;; ============================================================ -;;; Identify the name of this SYS file, which should be present at -;;; $280 with or without a path prefix. This is used when searching -;;; for the next .SYSTEM file to execute. - -.proc find_self_name - ;; Search pathname buffer backwards for '/', then - ;; copy name into |self_name|; this is used later - ;; to find/invoke the next .SYSTEM file. - - ;; Find '/' (which may not be present, prefix is optional) - lda #0 - sta $A8 - ldx PATHNAME - beq install_driver -floop: inc $A8 - dex - beq copy_name - lda PATHNAME,x - eor #'/' - asl a - bne floop - - ;; Copy name into |self_name| buffer -copy_name: - ldy #0 -cloop: iny - inx - lda PATHNAME,x - sta self_name,y - cpy $A8 - bcc cloop - sty self_name -.endproc - ;; Fall through... +banks_to_reserve: .byte 0 ; banks to reserve (e.g. for AppleWorks) +unitnum: .byte $03 ; S3D1; could be $B for S3D2 ;;; ============================================================ ;;; Install the driver @@ -275,7 +250,7 @@ break: bmi L21F0 jmp do_install -fail: jmp do_chain +fail: jmp install_failure sloop: lda sig,x set_sig: @@ -389,14 +364,14 @@ copy_driver: cpy #sizeof_driver bcc :- - ;; Check if slot already has a device + ;; Check if unitnum already has a device ldy DEVCNT : lda DEVLST,y lsr a lsr a lsr a lsr a - cmp slot + cmp unitnum beq install_device dey bpl :- @@ -412,7 +387,7 @@ copy_driver: ;; Install device in ProDOS via DEVLST/DEVADR. ;; (Y has index in DEVLST) install_device: - lda slot + lda unitnum asl a tax asl a @@ -424,7 +399,7 @@ install_device: copy16 #(driver_target+1), DEVADR,x ;; Did we install into S3D2? - lda slot + lda unitnum cmp #$0B ; Slot 3 Drive 2 beq finish @@ -456,8 +431,8 @@ finish: bit ROMIN2 ldx #$00 lda on_line_params_buffer ora L239F - bne do_chain - bcc do_chain + bne install_success + bcc install_success copy #$FF, L239F sta ALTZPON copy driver_bank_list, BANKSEL @@ -466,8 +441,24 @@ finish: bit ROMIN2 stx vol_dir_header+VolumeDirectoryHeader::total_blocks jmp install_driver ; retry??? -do_chain: +install_success: sta ALTZPOFF + + jsr HOME + jsr zstrout + scrcode "\r\r\r", PRODUCT, " - Installed" + .byte 0 + + jmp launch_next_sys_file + +install_failure: + sta ALTZPOFF + + jsr HOME + jsr zstrout + scrcode "\r\r\r", PRODUCT, " - Not Installed" + .byte 0 + jmp launch_next_sys_file ;;; ============================================================ @@ -735,6 +726,11 @@ bank_list: ;;; Find and invoke the next .SYSTEM file .proc launch_next_sys_file + ptr := $A5 + num := $A7 + len := $A8 + + ;; -------------------------------------------------- ;; Update reset vector - now terminates. lda #(data_buffer + VolumeDirectoryBlockHeader::header_length) + lda #>(data_buf + .sizeof(VolumeDirectoryHeader)) sta ptr+1 ;; Process directory entry @@ -780,11 +803,11 @@ entry: ldy #FileEntry::file_type ; file_type ;; Compare suffix - is it .SYSTEM? ldx suffix : lda (ptr),y - cmp suffix+1,x + cmp suffix,x bne next dey dex - bpl :- + bne :- ;; Yes; is it *this* .SYSTEM file? ldy self_name @@ -812,18 +835,18 @@ next: lda ptr entries_per_block_mod := *-1 bcc entry - lda data_buffer + VolumeDirectoryBlockHeader::next_block + lda data_buf + VolumeDirectoryHeader::next_block sta read_block_params_block_num - lda data_buffer + VolumeDirectoryBlockHeader::next_block + 1 + lda data_buf + VolumeDirectoryHeader::next_block + 1 sta read_block_params_block_num+1 ora read_block_params_block_num beq not_found ; last block has next=0 jsr read_block lda #0 sta num - lda #<(data_buffer + $04) + lda #<(data_buf + $04) sta ptr - lda #>(data_buffer + $04) + lda #>(data_buf + $04) sta ptr+1 jmp entry @@ -857,7 +880,9 @@ append: ldy #0 not_found: jsr zstrout - scrcode "\r\r\r* Unable to find next '.SYSTEM' file *\r" + scrcode "\r\r* Unable to find next '.SYSTEM' file *\r" + .byte 0 + bit KBDSTRB : lda KBD bpl :- @@ -935,13 +960,7 @@ lowercase_mask: .byte 0 ; crash if QUIT fails rts -.proc quit_params - .byte 4 ; param_count - .byte 0 ; quit_type - .word 0000 ; reserved - .byte 0 ; reserved - .word 0000 ; reserved -.endproc + DEFINE_QUIT_PARAMS quit_params .endproc ;;; ------------------------------------------------------------ @@ -953,12 +972,8 @@ lowercase_mask: rts .endproc -.proc read_block_params - .byte 3 ; param_count -unit_num: .byte $60 ; unit_num - .addr data_buffer ; data_buffer -block_num: .word 2 ; block_num - block 2 is volume directory -.endproc + ;; block 2 is volume directory + DEFINE_READ_BLOCK_PARAMS read_block_params, data_buf, 2 read_block_params_unit_num := read_block_params::unit_num read_block_params_block_num := read_block_params::block_num @@ -987,11 +1002,16 @@ block_num: .word 2 ; block_num - block 2 is volume directory .proc on_error pha jsr zstrout - scrcode "\r\r\r** Disk Error $" + scrcode "\r\r* Disk Error $" + .byte 0 + pla jsr PRBYTE + jsr zstrout - scrcode " **\r" + scrcode " *\r" + .byte 0 + bit KBDSTRB : lda KBD bpl :- @@ -1001,27 +1021,13 @@ block_num: .word 2 ; block_num - block 2 is volume directory ;;; ------------------------------------------------------------ -.proc open_params - .byte 3 ; param_count - .addr PATHNAME ; pathname - .addr data_buffer ; io_buffer -ref_num:.byte 1 ; ref_num -.endproc + DEFINE_OPEN_PARAMS open_params, PATHNAME, data_buf open_params_ref_num := open_params::ref_num -.proc read_params - .byte 4 ; param_count -ref_num:.byte 1 ; ref_num - .addr SYS_ADDR ; data_buffer - .word SYS_LEN ; request_count - .word 0 ; trans_count -.endproc + DEFINE_READ_PARAMS read_params, SYS_ADDR, SYS_LEN read_params_ref_num := read_params::ref_num -.proc close_params - .byte 1 ; param_count -ref_num:.byte 0 ; ref_num -.endproc + DEFINE_CLOSE_PARAMS close_params ;;; ============================================================ ;;; Data @@ -1032,9 +1038,6 @@ suffix: found_self_flag: .byte 0 -;;; ============================================================ -;;; End of relocated code -sys_end: ;;; ============================================================ ;;; Scratch space beyond code used during install @@ -1046,3 +1049,10 @@ map2 := *+2+$80 ; len: $80 stash_00 := *+2+$100 ; len: $80 stash_01 := *+2+$180 ; len: $80 self_name := *+2+$200 ; len: 65 + + .assert self_name + 64 < data_buf, error, "Too long" + +;;; ============================================================ +;;; End of relocated code + poporg +sys_end: From 88472a8e119cda18ffd03b6d5126177d9813b960 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Wed, 19 Jun 2019 20:12:18 -0700 Subject: [PATCH 08/18] Rearrange so driver is a subroutine --- ram.drv.system.s | 585 ++++++++++++++++++++++++----------------------- 1 file changed, 296 insertions(+), 289 deletions(-) diff --git a/ram.drv.system.s b/ram.drv.system.s index 4143a17..5911465 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -43,13 +43,14 @@ SYS_LEN = $BF00 - SYS_ADDR ; Maximum SYS file length dst_addr := $1000 ;;; ============================================================ +;;; Relocate from $2000 to $1000 .proc relocate src := SYS_ADDR ldx #(sys_end - sys_start + $FF) / $100 ; pages ldy #0 -load: lda sys_start,y ; self-modified +load: lda sys_start,y ; self-modified load_hi := *-1 sta dst_addr,y ; self-modified store_hi := *-1 @@ -60,21 +61,304 @@ load: lda sys_start,y ; self-modified dex bne load - jmp dst_addr + jmp main +.endproc + +;;; ============================================================ +;;; Start of relocated code +;;; + +sys_start: + pushorg dst_addr + + +;;; ============================================================ +;;; Main routine +;;; ============================================================ + +.proc main + jsr setup + jsr install_driver + jsr launch_next + brk .endproc ;;; ============================================================ -;;; Start of relocated code -sys_start: - pushorg dst_addr +;;; Preserve state needed to chain to next file +;;; ============================================================ +.proc setup ;; Save most recent device for later, when chaining ;; to next .SYSTEM file. lda DEVNUM sta read_block_params_unit_num + rts +.endproc - jmp install_driver + +;;; ============================================================ +;;; Find and invoke the next .SYSTEM file +;;; ============================================================ + +.proc launch_next + + ptr := $A5 + num := $A7 + len := $A8 + + ;; -------------------------------------------------- + ;; Update reset vector - now terminates. + lda #quit + sta $03F3 + eor #$A5 + sta $03F4 + + ;; -------------------------------------------------- + ;; 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) + lda #0 + sta len + ldx PATHNAME + beq read_dir +floop: inc len + dex + beq copy_name + lda PATHNAME,x + eor #'/' + asl a + bne floop + + ;; Copy name into |self_name| buffer +copy_name: + ldy #0 +cloop: iny + inx + lda PATHNAME,x + sta self_name,y + cpy len + bcc cloop + sty self_name + + ;; -------------------------------------------------- + ;; Read directory and look for .SYSTEM files; find this + ;; one, and invoke the following one. +read_dir: + jsr read_block + + lda data_buf + VolumeDirectoryHeader::entry_length + sta entry_length_mod + lda data_buf + VolumeDirectoryHeader::entries_per_block + sta entries_per_block_mod + lda #1 + sta num + + lda #<(data_buf + .sizeof(VolumeDirectoryHeader)) + sta ptr + lda #>(data_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 + + lda data_buf + VolumeDirectoryHeader::next_block + sta read_block_params_block_num + lda data_buf + VolumeDirectoryHeader::next_block + 1 + sta read_block_params_block_num+1 + ora read_block_params_block_num + beq not_found ; last block has next=0 + jsr read_block + lda #0 + sta num + lda #<(data_buf + $04) + sta ptr + lda #>(data_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 + + ;; Compose the path to invoke. First walk self path + ;; backwards to '/'. + ldx PATHNAME + beq append +: dex + beq append + lda PATHNAME,x + eor #'/' + asl a + bne :- + + ;; Now append name of found file. +append: 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 + +;;; ------------------------------------------------------------ +;;; Invoke ProDOS QUIT routine. + +.proc quit + MLI_CALL QUIT, quit_params + .byte 0 ; crash if QUIT fails + rts + + DEFINE_QUIT_PARAMS quit_params +.endproc + +;;; ------------------------------------------------------------ +;;; Read a disk block. + +.proc read_block + MLI_CALL READ_BLOCK, read_block_params + bcs on_error + rts +.endproc + + ;; block 2 is volume directory + DEFINE_READ_BLOCK_PARAMS read_block_params, data_buf, 2 + read_block_params_unit_num := read_block_params::unit_num + read_block_params_block_num := read_block_params::block_num + +;;; ------------------------------------------------------------ +;;; 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 + + 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 + +;;; ------------------------------------------------------------ + + DEFINE_OPEN_PARAMS open_params, PATHNAME, data_buf + open_params_ref_num := open_params::ref_num + + DEFINE_READ_PARAMS read_params, SYS_ADDR, SYS_LEN + read_params_ref_num := read_params::ref_num + + DEFINE_CLOSE_PARAMS close_params + +;;; ============================================================ +;;; Data + +suffix: + PASCAL_STRING ".SYSTEM" + +found_self_flag: + .byte 0 + + +;;; ============================================================ +;;; +;;; Driver +;;; +;;; ============================================================ ;;; ============================================================ ;;; Configuration Parameters @@ -449,7 +733,7 @@ install_success: scrcode "\r\r\r", PRODUCT, " - Installed" .byte 0 - jmp launch_next_sys_file + rts install_failure: sta ALTZPOFF @@ -459,7 +743,7 @@ install_failure: scrcode "\r\r\r", PRODUCT, " - Not Installed" .byte 0 - jmp launch_next_sys_file + rts ;;; ============================================================ ;;; Installed on zero page of each bank at $B0 @@ -722,173 +1006,10 @@ bank_list: driver_block_x := driver_src + driver_src::driver_block_x - driver_src::driver_start driver_bank_list := driver_src + driver_src::bank_list - driver_src::driver_start + +;;; ============================================================ +;;; Common Routines ;;; ============================================================ -;;; Find and invoke the next .SYSTEM file - -.proc launch_next_sys_file - ptr := $A5 - num := $A7 - len := $A8 - - ;; -------------------------------------------------- - ;; Update reset vector - now terminates. - lda #quit - sta $03F3 - eor #$A5 - sta $03F4 - - ;; -------------------------------------------------- - ;; 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) - lda #0 - sta len - ldx PATHNAME - beq read_dir -floop: inc len - dex - beq copy_name - lda PATHNAME,x - eor #'/' - asl a - bne floop - - ;; Copy name into |self_name| buffer -copy_name: - ldy #0 -cloop: iny - inx - lda PATHNAME,x - sta self_name,y - cpy len - bcc cloop - sty self_name - - ;; -------------------------------------------------- - ;; Read directory and look for .SYSTEM files; find this - ;; one, and invoke the following one. -read_dir: - jsr read_block - - lda data_buf + VolumeDirectoryHeader::entry_length - sta entry_length_mod - lda data_buf + VolumeDirectoryHeader::entries_per_block - sta entries_per_block_mod - lda #1 - sta num - - lda #<(data_buf + .sizeof(VolumeDirectoryHeader)) - sta ptr - lda #>(data_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 - - lda data_buf + VolumeDirectoryHeader::next_block - sta read_block_params_block_num - lda data_buf + VolumeDirectoryHeader::next_block + 1 - sta read_block_params_block_num+1 - ora read_block_params_block_num - beq not_found ; last block has next=0 - jsr read_block - lda #0 - sta num - lda #<(data_buf + $04) - sta ptr - lda #>(data_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 - - ;; Compose the path to invoke. First walk self path - ;; backwards to '/'. - ldx PATHNAME - beq append -: dex - beq append - lda PATHNAME,x - eor #'/' - asl a - bne :- - - ;; Now append name of found file. -append: 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 ;;; ------------------------------------------------------------ ;;; Output a high-ascii, null-terminated string. @@ -921,126 +1042,12 @@ skip: inc ptr rts .endproc -;;; ------------------------------------------------------------ -;;; COUT a 2-digit number in A - -.proc cout_number - ldx #'0'|$80 - cmp #10 ; >= 10? - bcc tens - - ;; divide by 10, dividend(+'0') in x remainder in a -: sbc #10 - inx - cmp #10 - bcs :- - -tens: pha - cpx #'0'|$80 - beq units - txa - jsr COUT - -units: pla - ora #'0'|$80 - jsr COUT - rts -.endproc - -;;; ------------------------------------------------------------ - lowercase_mask: .byte $FF ; Set to $DF on systems w/o lower-case -;;; ------------------------------------------------------------ -;;; Invoke ProDOS QUIT routine. - -.proc quit - MLI_CALL QUIT, quit_params - .byte 0 ; crash if QUIT fails - rts - - DEFINE_QUIT_PARAMS quit_params -.endproc - -;;; ------------------------------------------------------------ -;;; Read a disk block. - -.proc read_block - MLI_CALL READ_BLOCK, read_block_params - bcs on_error - rts -.endproc - - ;; block 2 is volume directory - DEFINE_READ_BLOCK_PARAMS read_block_params, data_buf, 2 - read_block_params_unit_num := read_block_params::unit_num - read_block_params_block_num := read_block_params::block_num - -;;; ------------------------------------------------------------ -;;; 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 - - 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 - -;;; ------------------------------------------------------------ - - DEFINE_OPEN_PARAMS open_params, PATHNAME, data_buf - open_params_ref_num := open_params::ref_num - - DEFINE_READ_PARAMS read_params, SYS_ADDR, SYS_LEN - read_params_ref_num := read_params::ref_num - - DEFINE_CLOSE_PARAMS close_params ;;; ============================================================ -;;; Data - -suffix: - PASCAL_STRING ".SYSTEM" - -found_self_flag: - .byte 0 - - -;;; ============================================================ -;;; Scratch space beyond code used during install +;;; Scratch space beyond code used during driver install reserved_banks := * first_used_bank := *+1 From 9b98a09067cfd60ccfc254744824ffbb0589f303 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Wed, 19 Jun 2019 20:21:10 -0700 Subject: [PATCH 09/18] rearrange config/data --- inc/prodos.inc | 4 ++++ ram.drv.system.s | 42 ++++++++++++++++++++---------------------- 2 files changed, 24 insertions(+), 22 deletions(-) diff --git a/inc/prodos.inc b/inc/prodos.inc index b3ccfb3..637e44e 100644 --- a/inc/prodos.inc +++ b/inc/prodos.inc @@ -29,6 +29,10 @@ 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 ;;; ============================================================ diff --git a/ram.drv.system.s b/ram.drv.system.s index 5911465..ed27caa 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -17,25 +17,6 @@ .include "opcodes.inc" -zp_sig_addr := $06 - -zpproc_addr := $B0 -zpproc_relay_addr := $2D0 - -PATHNAME := $280 - -data_buf := $1C00 ; I/O when chaining to next SYS file -driver_target := $FF00 ; Install location in ProDOS - - -kMaxUsableBanks = 24 ; Why is this capped so low??? - ; (driver has room for another ~20?) - -SYS_ADDR := $2000 ; Load address for SYS files -SYS_LEN = $BF00 - SYS_ADDR ; Maximum SYS file length - - .define PRODUCT "RAMWorks RAM Disk" - ;;; ============================================================ ;; SYS files load at $2000; relocates self to $1000 @@ -92,10 +73,12 @@ sys_start: ;; Save most recent device for later, when chaining ;; to next .SYSTEM file. lda DEVNUM - sta read_block_params_unit_num + sta devnum rts .endproc +devnum: .byte 0 +self_name: .res 16 ;;; ============================================================ ;;; Find and invoke the next .SYSTEM file @@ -149,6 +132,8 @@ cloop: iny ;; Read directory and look for .SYSTEM files; find this ;; one, and invoke the following one. read_dir: + lda devnum + sta read_block_params_unit_num jsr read_block lda data_buf + VolumeDirectoryHeader::entry_length @@ -363,6 +348,20 @@ found_self_flag: ;;; ============================================================ ;;; Configuration Parameters + .define PRODUCT "RAMWorks RAM Disk" + +zp_sig_addr := $06 + +zpproc_addr := $B0 +zpproc_relay_addr := $2D0 + +data_buf := $1C00 ; I/O when chaining to next SYS file +driver_target := $FF00 ; Install location in ProDOS + + +kMaxUsableBanks = 24 ; Why is this capped so low??? + ; (driver has room for another ~20?) + banks_to_reserve: .byte 0 ; banks to reserve (e.g. for AppleWorks) unitnum: .byte $03 ; S3D1; could be $B for S3D2 @@ -1055,9 +1054,8 @@ map1 := *+2 ; len: $80 map2 := *+2+$80 ; len: $80 stash_00 := *+2+$100 ; len: $80 stash_01 := *+2+$180 ; len: $80 -self_name := *+2+$200 ; len: 65 - .assert self_name + 64 < data_buf, error, "Too long" + .assert stash_01+$80 < data_buf, error, "Too long" ;;; ============================================================ ;;; End of relocated code From d4466231f5c92bfab49c4c69306d64d17257df47 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Wed, 19 Jun 2019 20:39:54 -0700 Subject: [PATCH 10/18] Save name earlier --- ram.drv.system.s | 96 ++++++++++++++++++++++++------------------------ 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/ram.drv.system.s b/ram.drv.system.s index ed27caa..562dc74 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -70,10 +70,48 @@ sys_start: ;;; ============================================================ .proc setup + ;; -------------------------------------------------- ;; 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 @@ -84,49 +122,22 @@ self_name: .res 16 ;;; Find and invoke the next .SYSTEM file ;;; ============================================================ -.proc launch_next +.proc quit + MLI_CALL QUIT, quit_params + .byte 0 ; crash if QUIT fails + DEFINE_QUIT_PARAMS quit_params +.endproc + +.proc launch_next ptr := $A5 num := $A7 len := $A8 ;; -------------------------------------------------- - ;; Update reset vector - now terminates. - lda #quit - sta $03F3 - eor #$A5 - sta $03F4 - - ;; -------------------------------------------------- - ;; 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) - lda #0 - sta len - ldx PATHNAME - beq read_dir -floop: inc len - dex - beq copy_name - lda PATHNAME,x - eor #'/' - asl a - bne floop - - ;; Copy name into |self_name| buffer -copy_name: - ldy #0 -cloop: iny - inx - lda PATHNAME,x - sta self_name,y - cpy len - bcc cloop - sty self_name + ;; Own name found? If not, just quit + lda self_name + beq quit ;; -------------------------------------------------- ;; Read directory and look for .SYSTEM files; find this @@ -252,17 +263,6 @@ not_found: jmp quit .endproc -;;; ------------------------------------------------------------ -;;; Invoke ProDOS QUIT routine. - -.proc quit - MLI_CALL QUIT, quit_params - .byte 0 ; crash if QUIT fails - rts - - DEFINE_QUIT_PARAMS quit_params -.endproc - ;;; ------------------------------------------------------------ ;;; Read a disk block. From f380680cddceda697dce36c3a35c532f0828af34 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 21 Jun 2019 15:25:11 -0700 Subject: [PATCH 11/18] Use file I/O rather than block I/O to read dir --- ram.drv.system.s | 129 ++++++++++++++++++++++++++--------------------- 1 file changed, 71 insertions(+), 58 deletions(-) diff --git a/ram.drv.system.s b/ram.drv.system.s index 562dc74..afb1d3a 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -129,7 +129,21 @@ self_name: .res 16 DEFINE_QUIT_PARAMS quit_params .endproc +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 @@ -138,25 +152,53 @@ self_name: .res 16 ;; Own name found? If not, just quit lda self_name beq quit - ;; -------------------------------------------------- - ;; Read directory and look for .SYSTEM files; find this - ;; one, and invoke the following one. -read_dir: + ;; Find name of boot device, copy into PATHNAME lda devnum - sta read_block_params_unit_num - jsr read_block + sta on_line_params::unit_num + MLI_CALL ON_LINE, on_line_params + bcc :+ + jmp on_error - lda data_buf + VolumeDirectoryHeader::entry_length +: 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 data_buf + VolumeDirectoryHeader::entries_per_block + lda dir_buf + VolumeDirectoryHeader::entries_per_block sta entries_per_block_mod lda #1 sta num - lda #<(data_buf + .sizeof(VolumeDirectoryHeader)) + ;; Set up pointers to entry + lda #<(dir_buf + .sizeof(VolumeDirectoryHeader)) sta ptr - lda #>(data_buf + .sizeof(VolumeDirectoryHeader)) + lda #>(dir_buf + .sizeof(VolumeDirectoryHeader)) sta ptr+1 ;; Process directory entry @@ -208,40 +250,34 @@ next: lda ptr entries_per_block_mod := *-1 bcc entry - lda data_buf + VolumeDirectoryHeader::next_block - sta read_block_params_block_num - lda data_buf + VolumeDirectoryHeader::next_block + 1 - sta read_block_params_block_num+1 - ora read_block_params_block_num - beq not_found ; last block has next=0 - jsr read_block - lda #0 + ;; Read next "block" + MLI_CALL READ, read_block_params + bcs not_found + + ;; Set up pointers to entry +: lda #0 sta num - lda #<(data_buf + $04) + lda #<(dir_buf + $04) sta ptr - lda #>(data_buf + $04) + 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 - ;; Compose the path to invoke. First walk self path - ;; backwards to '/'. - ldx PATHNAME - beq append -: dex - beq append - lda PATHNAME,x - eor #'/' - asl a - bne :- + MLI_CALL CLOSE, close_params - ;; Now append name of found file. -append: ldy #0 + ;; Compose the path to invoke. + ldx PATHNAME + inx + lda #'/' + sta PATHNAME,x + ldy #0 : iny inx lda (ptr),y @@ -249,6 +285,7 @@ append: ldy #0 cpy len bcc :- stx PATHNAME + jmp invoke_system_file not_found: @@ -263,20 +300,6 @@ not_found: jmp quit .endproc -;;; ------------------------------------------------------------ -;;; Read a disk block. - -.proc read_block - MLI_CALL READ_BLOCK, read_block_params - bcs on_error - rts -.endproc - - ;; block 2 is volume directory - DEFINE_READ_BLOCK_PARAMS read_block_params, data_buf, 2 - read_block_params_unit_num := read_block_params::unit_num - read_block_params_block_num := read_block_params::block_num - ;;; ------------------------------------------------------------ ;;; Load/execute the system file in PATHNAME @@ -284,8 +307,8 @@ not_found: MLI_CALL OPEN, open_params bcs on_error - lda open_params_ref_num - sta read_params_ref_num + lda open_params::ref_num + sta read_params::ref_num MLI_CALL READ, read_params bcs on_error @@ -319,16 +342,6 @@ not_found: jmp quit .endproc -;;; ------------------------------------------------------------ - - DEFINE_OPEN_PARAMS open_params, PATHNAME, data_buf - open_params_ref_num := open_params::ref_num - - DEFINE_READ_PARAMS read_params, SYS_ADDR, SYS_LEN - read_params_ref_num := read_params::ref_num - - DEFINE_CLOSE_PARAMS close_params - ;;; ============================================================ ;;; Data From 2dfb4410a9bf06eea50f36b197fb75dc60fb001d Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Fri, 21 Jun 2019 16:48:01 -0700 Subject: [PATCH 12/18] Update README with branch details --- README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f0646db..ed8d6ca 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Disassembly of Glen E. Bredon's `RAM.DRV.SYSTEM` for the Apple II +# Disassembly of Glen E. Bredon's `RAM.DRV.SYSTEM` for Apple II ProDOS This was started before realizing what the origin of the `RAM.SYSTEM` found on a MouseDesk 2.0 disk image file was. @@ -6,3 +6,10 @@ found on a MouseDesk 2.0 disk image file was. There is a more complete diassembly with commentary at: http://boutillon.free.fr/Underground/Outils/Ram_Drv_System/Ram_Drv_System.html + +## Project Details + +* The `orig` branch compiles to to match the original. +* The `master` branch has additions, including: + * Chains to next `.SYSTEM` file in dir order (not hard coded) + * Chains to next `.SYSTEM` file on non-block devices (e.g. file shares) From 754d267c1ec4f309004b5b39e64644a2eb98232d Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Sun, 22 Sep 2019 21:33:54 -0700 Subject: [PATCH 13/18] Build: Use cc65's make avail --- .travis.yml | 11 +++++++++++ Makefile | 7 +++---- 2 files changed, 14 insertions(+), 4 deletions(-) create mode 100644 .travis.yml 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 b5dd72a..b3bfc7d 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 OUTDIR = out @@ -21,9 +20,9 @@ clean: rm -f $(TARGETS) $(OUTDIR)/%.o: %.s $(HEADERS) - $(CC65)/ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< + ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< # System Files .SYS $(OUTDIR)/%.SYS: $(OUTDIR)/%.o - $(CC65)/ld65 $(CCFLAGS) -o '$@' $< + ld65 $(LDFLAGS) -o '$@' $< xattr -wx prodos.AuxType '00 20' $@ From ba0c5e53d38a750352b3bc9e4ed653e2dbd7fa8d Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Mon, 30 Sep 2019 20:20:59 -0700 Subject: [PATCH 14/18] Fix relocation --- ram.drv.system.s | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/ram.drv.system.s b/ram.drv.system.s index afb1d3a..be0b2f1 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -27,13 +27,14 @@ ;;; Relocate from $2000 to $1000 .proc relocate - src := SYS_ADDR + src := reloc_start + dst := dst_addr - ldx #(sys_end - sys_start + $FF) / $100 ; pages + ldx #(reloc_end - reloc_start + $FF) / $100 ; pages ldy #0 -load: lda sys_start,y ; self-modified +load: lda src,y ; self-modified load_hi := *-1 - sta dst_addr,y ; self-modified + sta dst,y ; self-modified store_hi := *-1 iny bne load @@ -49,17 +50,16 @@ load: lda sys_start,y ; self-modified ;;; Start of relocated code ;;; -sys_start: + reloc_start := * pushorg dst_addr - ;;; ============================================================ ;;; Main routine ;;; ============================================================ .proc main jsr setup - jsr install_driver + jsr maybe_install_driver jsr launch_next brk .endproc @@ -124,7 +124,7 @@ self_name: .res 16 .proc quit MLI_CALL QUIT, quit_params - .byte 0 ; crash if QUIT fails + brk ; crash if QUIT fails DEFINE_QUIT_PARAMS quit_params .endproc @@ -255,7 +255,7 @@ next: lda ptr bcs not_found ;; Set up pointers to entry -: lda #0 + lda #0 sta num lda #<(dir_buf + $04) sta ptr @@ -354,7 +354,7 @@ found_self_flag: ;;; ============================================================ ;;; -;;; Driver +;;; Driver Installer ;;; ;;; ============================================================ @@ -381,7 +381,7 @@ unitnum: .byte $03 ; S3D1; could be $B for S3D2 ;;; ============================================================ ;;; Install the driver -.proc install_driver +.proc maybe_install_driver sta CLR80COL ldy #0 @@ -735,7 +735,7 @@ finish: bit ROMIN2 stx $06 stx BANKSEL stx vol_dir_header+VolumeDirectoryHeader::total_blocks - jmp install_driver ; retry??? + jmp maybe_install_driver ; retry??? install_success: sta ALTZPOFF @@ -1072,5 +1072,6 @@ stash_01 := *+2+$180 ; len: $80 ;;; ============================================================ ;;; End of relocated code + poporg -sys_end: + reloc_end := * From 7cc70cd7298af057a4c6fabba89a15c5ce7c57c8 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Mon, 30 Sep 2019 20:34:17 -0700 Subject: [PATCH 15/18] Use common driver chain logic --- Makefile | 10 +- inc/apple2.inc | 22 ++- inc/macros.inc | 5 + ram.drv.system.s | 395 ++--------------------------------------------- 4 files changed, 45 insertions(+), 387 deletions(-) diff --git a/Makefile b/Makefile index b3bfc7d..06dfd81 100644 --- a/Makefile +++ b/Makefile @@ -4,10 +4,16 @@ LDFLAGS = --config apple2-asm.cfg OUTDIR = out -HEADERS = $(wildcard inc/*.inc) +HEADERS = $(wildcard *.inc) $(wildcard inc/*.inc) TARGETS = $(OUTDIR)/ram.drv.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) @@ -20,7 +26,7 @@ clean: rm -f $(TARGETS) $(OUTDIR)/%.o: %.s $(HEADERS) - ca65 $(CAFLAGS) --listing $(basename $@).list -o $@ $< + ca65 $(CAFLAGS) $(DEFINES) --listing $(basename $@).list -o $@ $< # System Files .SYS $(OUTDIR)/%.SYS: $(OUTDIR)/%.o diff --git a/inc/apple2.inc b/inc/apple2.inc index 144c53c..a66c24e 100644 --- a/inc/apple2.inc +++ b/inc/apple2.inc @@ -23,12 +23,32 @@ RDPAGE2 := $C01C BANKSEL := $C073 ; Select RamWorks bank -ROMIN2 := $C082 +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 index 23a2307..9610987 100644 --- a/inc/macros.inc +++ b/inc/macros.inc @@ -116,3 +116,8 @@ end: sta arg2+1 .endif .endmacro + +;;; ============================================================ + +;;; Set the high bit on the passed byte +.define HI(c) ((c)|$80) diff --git a/ram.drv.system.s b/ram.drv.system.s index be0b2f1..a5841ed 100644 --- a/ram.drv.system.s +++ b/ram.drv.system.s @@ -5,352 +5,21 @@ ;;; Modifications: ;;; * Chain to next .SYSTEM file dynamically - .feature string_escapes - .setcpu "6502" + .linecont + + .feature string_escapes .include "apple2.inc" .include "apple2.mac" - .include "inc/macros.inc" - .include "inc/apple2.inc" - .include "inc/prodos.inc" .include "opcodes.inc" + .include "inc/apple2.inc" + .include "inc/macros.inc" + .include "inc/prodos.inc" -;;; ============================================================ - - ;; SYS files load at $2000; relocates self to $1000 - .org SYS_ADDR - dst_addr := $1000 - -;;; ============================================================ -;;; Relocate from $2000 to $1000 - -.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 setup - jsr maybe_install_driver - jsr launch_next - brk -.endproc - - -;;; ============================================================ -;;; Preserve state needed to chain to next file -;;; ============================================================ - -.proc setup - ;; -------------------------------------------------- - ;; 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 - -;;; ============================================================ -;;; Find and invoke the next .SYSTEM file -;;; ============================================================ - -.proc quit - MLI_CALL QUIT, quit_params - brk ; crash if QUIT fails - - DEFINE_QUIT_PARAMS quit_params -.endproc - -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 - beq 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 - - 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 - -;;; ============================================================ -;;; Data - -suffix: - PASCAL_STRING ".SYSTEM" - -found_self_flag: - .byte 0 - +;;; ************************************************************ + .include "driver_preamble.inc" +;;; ************************************************************ ;;; ============================================================ ;;; @@ -1018,46 +687,6 @@ bank_list: driver_block_x := driver_src + driver_src::driver_block_x - driver_src::driver_start driver_bank_list := driver_src + driver_src::bank_list - driver_src::driver_start - -;;; ============================================================ -;;; 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 #'a'|$80 ; 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 - - ;;; ============================================================ ;;; Scratch space beyond code used during driver install @@ -1070,8 +699,6 @@ stash_01 := *+2+$180 ; len: $80 .assert stash_01+$80 < data_buf, error, "Too long" -;;; ============================================================ -;;; End of relocated code - - poporg - reloc_end := * +;;; ************************************************************ + .include "driver_postamble.inc" +;;; ************************************************************ From 850b10059db5516528016d6591c9b2b96a5e9a7b Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Mon, 30 Sep 2019 20:57:45 -0700 Subject: [PATCH 16/18] Add missing files --- driver_postamble.inc | 3 + driver_preamble.inc | 459 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 462 insertions(+) create mode 100644 driver_postamble.inc create mode 100644 driver_preamble.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..55eb9c2 --- /dev/null +++ b/driver_preamble.inc @@ -0,0 +1,459 @@ +;;; ------------------------------------------------------------ + + ;; 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 + jsr launch_next + brk +.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 From c7df8cb73b89a3a341c7acaf74da248e3a19e815 Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Mon, 30 Sep 2019 21:02:54 -0700 Subject: [PATCH 17/18] Add Travis build status --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index ed8d6ca..196de3d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # Disassembly of Glen E. Bredon's `RAM.DRV.SYSTEM` for Apple II ProDOS + +[![Build Status](https://travis-ci.org/a2stuff/ram.drv.system.svg?branch=master)](https://travis-ci.org/a2stuff/ram.drv.system) + + This was started before realizing what the origin of the `RAM.SYSTEM` found on a MouseDesk 2.0 disk image file was. From d049ae6dd856b1d33e7a886706906ecb5490623c Mon Sep 17 00:00:00 2001 From: Joshua Bell Date: Tue, 1 Oct 2019 22:27:18 -0700 Subject: [PATCH 18/18] Don't pollute stack --- driver_preamble.inc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/driver_preamble.inc b/driver_preamble.inc index 55eb9c2..88ff901 100644 --- a/driver_preamble.inc +++ b/driver_preamble.inc @@ -49,8 +49,7 @@ load: lda src,y ; self-modified jsr save_chain_info jsr init_system jsr maybe_install_driver - jsr launch_next - brk + jmp launch_next .endproc ;;; ============================================================