mirror of
https://github.com/a2stuff/prodos-drivers.git
synced 2025-01-23 12:32:13 +00:00
Meld NSC with Cricket driver. Resolves #2
This commit is contained in:
parent
2efce01dde
commit
3bc1eb6d96
2
Makefile
2
Makefile
@ -3,7 +3,7 @@ CC65 = ~/dev/cc65/bin
|
|||||||
CAFLAGS = --target apple2enh --list-bytes 0
|
CAFLAGS = --target apple2enh --list-bytes 0
|
||||||
CCFLAGS = --config apple2-asm.cfg
|
CCFLAGS = --config apple2-asm.cfg
|
||||||
|
|
||||||
TARGETS = cricket.system.SYS prodos.mod.BIN test.system.SYS ns.clock.system.SYS
|
TARGETS = prodos.mod.BIN ns.clock.system.SYS cricket.system.SYS
|
||||||
|
|
||||||
.PHONY: clean all
|
.PHONY: clean all
|
||||||
all: $(TARGETS)
|
all: $(TARGETS)
|
||||||
|
119
common.inc
Normal file
119
common.inc
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; ASCII
|
||||||
|
|
||||||
|
BELL := $07
|
||||||
|
CR := $0D
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Constants
|
||||||
|
|
||||||
|
MAX_DW := $FFFF
|
||||||
|
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Softswitches
|
||||||
|
|
||||||
|
CLR80VID := $C00C ; 40 Columns
|
||||||
|
ROMIN2 := $C082 ; Read ROM; no write
|
||||||
|
RWRAM1 := $C08B ; Read/write RAM bank 1
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; ProDOS
|
||||||
|
|
||||||
|
PRODOS := $BF00
|
||||||
|
DATETIME := $BF06
|
||||||
|
DEVNUM := $BF30
|
||||||
|
BITMAP := $BF58
|
||||||
|
BITMAP_SIZE := 24 ; 24 bytes in system bit map
|
||||||
|
DATELO := $BF90
|
||||||
|
TIMELO := $BF92
|
||||||
|
MACHID := $BF98
|
||||||
|
|
||||||
|
SYS_ADDR := $2000 ; Load address for SYSTEM files
|
||||||
|
PATHNAME := $0280 ; Pathname of loaded system file
|
||||||
|
|
||||||
|
;;; MLI commands
|
||||||
|
MLI_QUIT := $65
|
||||||
|
MLI_READ_BLOCK := $80
|
||||||
|
MLI_OPEN := $C8
|
||||||
|
MLI_READ := $CA
|
||||||
|
MLI_CLOSE := $CC
|
||||||
|
|
||||||
|
.macro PRODOS_CALL call, params
|
||||||
|
jsr PRODOS
|
||||||
|
.byte call
|
||||||
|
.addr params
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
;;; Volume Directory Block Header structure
|
||||||
|
.scope VolumeDirectoryBlockHeader
|
||||||
|
prev_block := $00
|
||||||
|
next_block := $02
|
||||||
|
entry_length := $23
|
||||||
|
entries_per_block := $24
|
||||||
|
header_length := $2B
|
||||||
|
.endscope
|
||||||
|
|
||||||
|
;; File Entry structure
|
||||||
|
.scope FileEntry
|
||||||
|
storage_type := $00
|
||||||
|
name_length := $00
|
||||||
|
file_name := $01
|
||||||
|
file_type := $10
|
||||||
|
.endscope
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Monitor
|
||||||
|
|
||||||
|
INIT := $FB2F
|
||||||
|
MON_HOME := $FC58
|
||||||
|
CROUT := $FD8E
|
||||||
|
PRBYTE := $FDDA
|
||||||
|
COUT := $FDED
|
||||||
|
SETNORM := $FE84
|
||||||
|
SETKBD := $FE89
|
||||||
|
SETVID := $FE93
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; 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)
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
;;; Length-prefixed string
|
||||||
|
.macro PASCAL_STRING arg
|
||||||
|
.byte .strlen(arg)
|
||||||
|
.byte arg
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
;;; Define a string with high bits set
|
||||||
|
;;; e.g. HIASCII "Ding ding", $7, $7
|
||||||
|
.macro HIASCII arg, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||||
|
.if .blank(arg)
|
||||||
|
.exitmacro
|
||||||
|
.endif
|
||||||
|
.if .match ({arg}, "") ; string?
|
||||||
|
.repeat .strlen(arg), i
|
||||||
|
.byte .strat(arg, i) | $80
|
||||||
|
.endrep
|
||||||
|
.else ; otherwise assume number/char/identifier
|
||||||
|
.byte (arg | $80)
|
||||||
|
.endif
|
||||||
|
HIASCII arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
;;; Like HIASCII, but null-terminated
|
||||||
|
.macro HIASCIIZ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||||
|
HIASCII arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
||||||
|
.byte 0
|
||||||
|
.endmacro
|
||||||
|
|
||||||
|
;;; Set the high bit on the passed byte
|
||||||
|
.define HI(c) ((c)|$80)
|
568
cricket.system.s
568
cricket.system.s
@ -2,55 +2,559 @@
|
|||||||
;;; Adapted from /CRICKET/PRODOS.MOD
|
;;; Adapted from /CRICKET/PRODOS.MOD
|
||||||
;;; Original: Street Electronics Corporation (C) 1984
|
;;; Original: Street Electronics Corporation (C) 1984
|
||||||
|
|
||||||
|
;;; Adapted from: /NO.SLOT.CLOCK/NS.CLOCK.SYSTEM
|
||||||
|
;;; Original by "CAP" 04/21/91
|
||||||
|
;;; http://www.apple2.org.za/gswv/a2zine/GS.WorldView/v1999/Oct/MISC/NSC.Disk.TXT
|
||||||
|
|
||||||
.setcpu "6502"
|
.setcpu "6502"
|
||||||
|
.linecont +
|
||||||
|
|
||||||
.include "apple2.inc"
|
.include "apple2.inc"
|
||||||
|
.include "opcodes.inc"
|
||||||
|
|
||||||
.org $2000 ; System files start at $2000
|
.include "./common.inc"
|
||||||
|
|
||||||
;; ProDOS System Global Page
|
;;; ------------------------------------------------------------
|
||||||
PRODOS := $BF00 ; MLI entry point
|
|
||||||
DATETIME := $BF06 ; CLOCK CALENDAR ROUTINE.
|
|
||||||
DATELO := $BF90 ; BITS 15-9=YR, 8-5=MO, 4-0=DAY
|
|
||||||
TIMELO := $BF92 ; BITS 12-8=HR, 5-0=MIN; LOW-HI FORMAT.
|
|
||||||
|
|
||||||
;; SSC I/O Registers (for Slot 2)
|
data_buffer = $1800
|
||||||
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)
|
|
||||||
|
|
||||||
.proc install
|
.define SYSTEM_SUFFIX ".SYSTEM"
|
||||||
ptr := $42
|
.define PRODUCT "Cricket Clock"
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
.org $1000
|
||||||
|
|
||||||
|
;; Loaded at $2000 but relocates to $1000
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
sys_start:
|
||||||
|
sec
|
||||||
|
bcs relocate
|
||||||
|
|
||||||
|
.byte $11, $26, $17 ; 11/26/17 - 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 := SYS_ADDR
|
||||||
|
dst := $1000
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; 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 pre_install
|
||||||
|
floop: inc $A8
|
||||||
|
dex
|
||||||
|
beq copy
|
||||||
|
lda PATHNAME,x
|
||||||
|
eor #'/'
|
||||||
|
asl a
|
||||||
|
bne floop
|
||||||
|
|
||||||
|
;; Copy name into |self_name| buffer
|
||||||
|
copy: ldy #0
|
||||||
|
cloop: iny
|
||||||
|
inx
|
||||||
|
lda PATHNAME,x
|
||||||
|
sta self_name,y
|
||||||
|
cpy $A8
|
||||||
|
bcc cloop
|
||||||
|
sty self_name
|
||||||
|
.endproc
|
||||||
|
;; Fall through...
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Before installing, get the system to a known state and
|
||||||
|
;;; ensure there is not a previous clock driver installed.
|
||||||
|
|
||||||
|
.proc pre_install
|
||||||
|
cld
|
||||||
|
bit ROMIN2
|
||||||
|
|
||||||
|
;; Update reset vector - re-invokes this code.
|
||||||
|
lda #<pre_install
|
||||||
|
sta $03F2
|
||||||
|
lda #>pre_install
|
||||||
|
sta $03F3
|
||||||
|
eor #$A5
|
||||||
|
sta $03F4
|
||||||
|
|
||||||
|
;; Quit 80-column firmware
|
||||||
|
lda #$95 ; Ctrl+U (quit 80 col firmware)
|
||||||
|
jsr COUT
|
||||||
|
|
||||||
|
;; Reset stack
|
||||||
|
ldx #$FF
|
||||||
|
txs
|
||||||
|
|
||||||
|
;; Reset I/O
|
||||||
|
sta CLR80VID
|
||||||
|
sta CLRALTCHAR
|
||||||
|
jsr SETVID
|
||||||
|
jsr SETKBD
|
||||||
|
jsr SETNORM
|
||||||
|
jsr INIT
|
||||||
|
|
||||||
|
;; 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
|
||||||
|
|
||||||
|
lda MACHID
|
||||||
|
and #$88 ; IIe or IIc (or IIgs) ?
|
||||||
|
bne :+
|
||||||
|
lda #$DF
|
||||||
|
sta lowercase_mask ; lower case to upper case
|
||||||
|
|
||||||
|
: lda MACHID
|
||||||
|
and #$01 ; existing clock card?
|
||||||
|
beq detect_cricket ; nope, check for Cricket
|
||||||
|
|
||||||
|
;; Chain with no message
|
||||||
|
jmp launch_next_sys_file
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Detect Cricket.
|
||||||
|
;;; TODO: Implement this!
|
||||||
|
|
||||||
|
.proc detect_cricket
|
||||||
|
;; Preserve date/time
|
||||||
|
ldy #3 ; copy 4 bytes
|
||||||
|
: lda DATELO,y
|
||||||
|
sta saved,y
|
||||||
|
dey
|
||||||
|
bpl :-
|
||||||
|
|
||||||
|
;; TODO: Confirm SSC in slot 2
|
||||||
|
;; TODO: Write NUL and check for 'C' ... version ... $8D (CR)
|
||||||
|
;; https://github.com/inexorabletash/cricket/issues/3
|
||||||
|
|
||||||
|
jmp install_driver
|
||||||
|
|
||||||
|
;; If not found, restore date/time
|
||||||
|
not_found:
|
||||||
|
ldy #3
|
||||||
|
: lda saved,y
|
||||||
|
sta DATELO,y
|
||||||
|
dey
|
||||||
|
bpl :-
|
||||||
|
|
||||||
|
;; Show failure message
|
||||||
|
jsr MON_HOME
|
||||||
|
jsr zstrout
|
||||||
|
HIASCIIZ CR, CR, CR, PRODUCT, " - Not Found."
|
||||||
|
jmp launch_next_sys_file
|
||||||
|
|
||||||
|
saved: .byte 0, 0, 0, 0
|
||||||
|
.endproc
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Install Cricket Driver. Copy into address at DATETIME vector,
|
||||||
|
;;; update the vector and update MACHID bits to signal a clock
|
||||||
|
;;; is present.
|
||||||
|
|
||||||
|
.proc install_driver
|
||||||
|
ptr := $A5
|
||||||
|
|
||||||
;; Copy driver to target in ProDOS
|
|
||||||
lda DATETIME+1
|
lda DATETIME+1
|
||||||
sta ptr
|
sta ptr
|
||||||
lda DATETIME+2
|
lda DATETIME+2
|
||||||
sta ptr+1
|
sta ptr+1
|
||||||
lda #$4C ; JMP opcode
|
lda RWRAM1
|
||||||
sta DATETIME
|
lda RWRAM1
|
||||||
lda ROMIN ; Write bank 2
|
|
||||||
lda ROMIN
|
|
||||||
ldy #sizeof_driver-1
|
ldy #sizeof_driver-1
|
||||||
|
|
||||||
loop: lda driver,y
|
loop: lda driver,y
|
||||||
sta (ptr),y
|
sta (ptr),y
|
||||||
dey
|
dey
|
||||||
bpl loop
|
bpl loop
|
||||||
|
|
||||||
;; Exit via ProDOS to chain to next .SYSTEM file on startup
|
;; Set the "Recognizable Clock Card" bit
|
||||||
exit: jsr PRODOS ; Call the MLI
|
lda MACHID
|
||||||
.byte $65 ; CALL TYPE = QUIT
|
ora #$01
|
||||||
.addr parmtable ; Pointer to parameter table
|
sta MACHID
|
||||||
parmtable:
|
|
||||||
.byte 4 ; Number of parameters is 4
|
lda #OPC_JMP_abs
|
||||||
.byte 0 ; 0 is the only quit type
|
sta DATETIME
|
||||||
.word 0000 ; Pointer reserved for future use
|
|
||||||
.byte 0 ; Byte reserved for future use
|
;; Invoke the driver to init the time
|
||||||
.word 0000 ; Pointer reserved for future use
|
jsr DATETIME
|
||||||
|
|
||||||
|
;; Display success message
|
||||||
|
bit ROMIN2
|
||||||
|
jsr MON_HOME
|
||||||
|
jsr zstrout
|
||||||
|
HIASCIIZ CR, CR, CR, PRODUCT, " - Installed "
|
||||||
|
|
||||||
|
;; Display the current date
|
||||||
|
lda DATELO+1 ; month
|
||||||
|
ror a
|
||||||
|
pha
|
||||||
|
lda DATELO
|
||||||
|
pha
|
||||||
|
rol a
|
||||||
|
rol a
|
||||||
|
rol a
|
||||||
|
rol a
|
||||||
|
and #%00001111
|
||||||
|
jsr cout_number
|
||||||
|
|
||||||
|
lda #(HI '/') ; /
|
||||||
|
jsr COUT
|
||||||
|
|
||||||
|
pla ; day
|
||||||
|
and #%00011111
|
||||||
|
jsr cout_number
|
||||||
|
|
||||||
|
lda #(HI '/') ; /
|
||||||
|
jsr COUT
|
||||||
|
|
||||||
|
pla ; year
|
||||||
|
jsr cout_number
|
||||||
|
jsr CROUT
|
||||||
.endproc
|
.endproc
|
||||||
|
|
||||||
;; Driver - relocatable code. Called by ProDOS to update date/time bytes
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Find and invoke the next .SYSTEM file
|
||||||
|
|
||||||
|
.proc launch_next_sys_file
|
||||||
|
;; Update reset vector - now terminates.
|
||||||
|
lda #<quit
|
||||||
|
sta $03F2
|
||||||
|
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
|
||||||
|
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 #.strlen(SYSTEM_SUFFIX)-1
|
||||||
|
: lda (ptr),y
|
||||||
|
cmp suffix,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
|
||||||
|
HIASCIIZ CR, CR, CR, "* Unable to find next '.SYSTEM' file *", CR
|
||||||
|
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 #(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
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; 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
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
lowercase_mask:
|
||||||
|
.byte $FF ; Set to $DF on systems w/o lower-case
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Invoke ProDOS QUIT routine.
|
||||||
|
|
||||||
|
.proc quit
|
||||||
|
PRODOS_CALL MLI_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
|
||||||
|
PRODOS_CALL MLI_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
|
||||||
|
PRODOS_CALL MLI_OPEN, open_params
|
||||||
|
bcs on_error
|
||||||
|
|
||||||
|
lda open_params_ref_num
|
||||||
|
sta read_params_ref_num
|
||||||
|
|
||||||
|
PRODOS_CALL MLI_READ, read_params
|
||||||
|
bcs on_error
|
||||||
|
|
||||||
|
PRODOS_CALL MLI_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
|
||||||
|
HIASCIIZ CR, CR, CR, "** Disk Error $"
|
||||||
|
pla
|
||||||
|
jsr PRBYTE
|
||||||
|
jsr zstrout
|
||||||
|
HIASCIIZ " **", CR
|
||||||
|
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 MAX_DW ; 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
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
found_self_flag:
|
||||||
|
.byte 0
|
||||||
|
|
||||||
|
suffix: .byte SYSTEM_SUFFIX
|
||||||
|
|
||||||
|
self_name:
|
||||||
|
PASCAL_STRING "CRICKET.SYSTEM"
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
;;; Cricket Clock Driver - copied into ProDOS
|
||||||
|
|
||||||
.proc driver
|
.proc driver
|
||||||
scratch := $3A ; ZP scratch location
|
scratch := $3A ; ZP scratch location
|
||||||
|
|
||||||
@ -139,3 +643,7 @@ done: pla ; restore saved command state
|
|||||||
rts
|
rts
|
||||||
.endproc
|
.endproc
|
||||||
sizeof_driver := .sizeof(driver)
|
sizeof_driver := .sizeof(driver)
|
||||||
|
|
||||||
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
|
sys_end:
|
||||||
|
@ -11,86 +11,15 @@
|
|||||||
.include "apple2.inc"
|
.include "apple2.inc"
|
||||||
.include "opcodes.inc"
|
.include "opcodes.inc"
|
||||||
|
|
||||||
;; ASCII
|
.include "./common.inc"
|
||||||
BELL := $07
|
|
||||||
CR := $0D
|
|
||||||
|
|
||||||
;; Constants
|
|
||||||
MAX_DW := $FFFF
|
|
||||||
|
|
||||||
;; Softswitches
|
|
||||||
CLR80VID := $C00C ; 40 Columns
|
|
||||||
ROMIN2 := $C082 ; Read ROM; no write
|
|
||||||
RWRAM1 := $C08B ; Read/write RAM bank 1
|
|
||||||
|
|
||||||
;; ProDOS
|
|
||||||
PRODOS := $BF00
|
|
||||||
DATETIME := $BF06
|
|
||||||
DEVNUM := $BF30
|
|
||||||
BITMAP := $BF58
|
|
||||||
BITMAP_SIZE := 24 ; 24 bytes in bitmap
|
|
||||||
DATELO := $BF90
|
|
||||||
TIMELO := $BF92
|
|
||||||
MACHID := $BF98
|
|
||||||
|
|
||||||
SYS_ADDR := $2000
|
|
||||||
PATHNAME := $0280
|
|
||||||
MLI_QUIT := $65
|
|
||||||
MLI_READ_BLOCK := $80
|
|
||||||
MLI_OPEN := $C8
|
|
||||||
MLI_READ := $CA
|
|
||||||
MLI_CLOSE := $CC
|
|
||||||
|
|
||||||
.macro PRODOS_CALL call, params
|
|
||||||
jsr PRODOS
|
|
||||||
.byte call
|
|
||||||
.addr params
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
;; Monitor
|
|
||||||
INIT := $FB2F
|
|
||||||
MON_HOME := $FC58
|
|
||||||
CROUT := $FD8E
|
|
||||||
PRBYTE := $FDDA
|
|
||||||
COUT := $FDED
|
|
||||||
SETNORM := $FE84
|
|
||||||
SETKBD := $FE89
|
|
||||||
SETVID := $FE93
|
|
||||||
|
|
||||||
;;; ------------------------------------------------------------
|
|
||||||
|
|
||||||
.macro PASCAL_STRING arg
|
|
||||||
.byte .strlen(arg)
|
|
||||||
.byte arg
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
.macro HIASCII arg, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
|
||||||
.if .blank(arg)
|
|
||||||
.exitmacro
|
|
||||||
.endif
|
|
||||||
.if .match ({arg}, "") ; string?
|
|
||||||
.repeat .strlen(arg), i
|
|
||||||
.byte .strat(arg, i) | $80
|
|
||||||
.endrep
|
|
||||||
.else ; otherwise assume number/char/identifier
|
|
||||||
.byte (arg | $80)
|
|
||||||
.endif
|
|
||||||
HIASCII arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
.macro HIASCIIZ arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
|
||||||
HIASCII arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9
|
|
||||||
.byte 0
|
|
||||||
.endmacro
|
|
||||||
|
|
||||||
.define HI(c) ((c)|$80)
|
|
||||||
|
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
data_buffer = $1800
|
data_buffer = $1800
|
||||||
|
|
||||||
.define SYSTEM_SUFFIX ".SYSTEM"
|
.define SYSTEM_SUFFIX ".SYSTEM"
|
||||||
|
.define PRODUCT "No-Slot Clock"
|
||||||
|
|
||||||
;;; ------------------------------------------------------------
|
;;; ------------------------------------------------------------
|
||||||
|
|
||||||
@ -135,11 +64,12 @@ load: lda src,y ; self-modified
|
|||||||
;;; $280 with or without a path prefix. This is used when searching
|
;;; $280 with or without a path prefix. This is used when searching
|
||||||
;;; for the next .SYSTEM file to execute.
|
;;; for the next .SYSTEM file to execute.
|
||||||
|
|
||||||
|
.proc find_self_name
|
||||||
;; Search pathname buffer backwards for '/', then
|
;; Search pathname buffer backwards for '/', then
|
||||||
;; copy name into |self_name|; this is used later
|
;; copy name into |self_name|; this is used later
|
||||||
;; to find/invoke the next .SYSTEM file.
|
;; to find/invoke the next .SYSTEM file.
|
||||||
.proc find_self_name
|
|
||||||
;; find '/' (which may not be present, prefix is optional)
|
;; Find '/' (which may not be present, prefix is optional)
|
||||||
lda #0
|
lda #0
|
||||||
sta $A8
|
sta $A8
|
||||||
ldx PATHNAME
|
ldx PATHNAME
|
||||||
@ -309,7 +239,7 @@ not_found:
|
|||||||
;; Show failure message
|
;; Show failure message
|
||||||
jsr MON_HOME
|
jsr MON_HOME
|
||||||
jsr zstrout
|
jsr zstrout
|
||||||
HIASCIIZ CR, CR, CR, "No-Slot Clock - Not Found."
|
HIASCIIZ CR, CR, CR, PRODUCT, " - Not Found."
|
||||||
jmp launch_next_sys_file
|
jmp launch_next_sys_file
|
||||||
|
|
||||||
saved: .byte 0, 0, 0, 0
|
saved: .byte 0, 0, 0, 0
|
||||||
@ -358,7 +288,7 @@ loop: lda driver,y
|
|||||||
bit ROMIN2
|
bit ROMIN2
|
||||||
jsr MON_HOME
|
jsr MON_HOME
|
||||||
jsr zstrout
|
jsr zstrout
|
||||||
HIASCIIZ CR, CR, CR, "No-Slot Clock - Installed "
|
HIASCIIZ CR, CR, CR, PRODUCT, " - Installed "
|
||||||
|
|
||||||
;; Display the current date
|
;; Display the current date
|
||||||
lda DATELO+1 ; month
|
lda DATELO+1 ; month
|
||||||
@ -401,43 +331,31 @@ loop: lda driver,y
|
|||||||
sta $03F4
|
sta $03F4
|
||||||
|
|
||||||
ptr := $A5
|
ptr := $A5
|
||||||
|
num := $A7
|
||||||
len := $A8
|
len := $A8
|
||||||
|
|
||||||
;; Volume Directory Block Header structure
|
|
||||||
prev_block := $00
|
|
||||||
next_block := $02
|
|
||||||
entry_length := $23
|
|
||||||
entries_per_block := $24
|
|
||||||
header_length := $2B
|
|
||||||
|
|
||||||
lda DEVNUM ; stick with most recent device
|
lda DEVNUM ; stick with most recent device
|
||||||
sta read_block_params_unit_num
|
sta read_block_params_unit_num
|
||||||
jsr read_block
|
jsr read_block
|
||||||
|
|
||||||
lda data_buffer + entry_length
|
lda data_buffer + VolumeDirectoryBlockHeader::entry_length
|
||||||
sta entry_length_mod
|
sta entry_length_mod
|
||||||
lda data_buffer + entries_per_block
|
lda data_buffer + VolumeDirectoryBlockHeader::entries_per_block
|
||||||
sta entries_per_block_mod
|
sta entries_per_block_mod
|
||||||
lda #1
|
lda #1
|
||||||
sta $A7 ; ???
|
sta num
|
||||||
|
|
||||||
lda #<(data_buffer + header_length)
|
lda #<(data_buffer + VolumeDirectoryBlockHeader::header_length)
|
||||||
sta ptr
|
sta ptr
|
||||||
lda #>(data_buffer + header_length)
|
lda #>(data_buffer + VolumeDirectoryBlockHeader::header_length)
|
||||||
sta ptr+1
|
sta ptr+1
|
||||||
|
|
||||||
;; File Entry structure
|
|
||||||
storage_type := $00
|
|
||||||
name_length := $00
|
|
||||||
file_name := $01
|
|
||||||
file_type := $10
|
|
||||||
|
|
||||||
;; Process directory entry
|
;; Process directory entry
|
||||||
entry: ldy #file_type ; file_type
|
entry: ldy #FileEntry::file_type ; file_type
|
||||||
lda (ptr),y
|
lda (ptr),y
|
||||||
cmp #$FF ; type=SYS
|
cmp #$FF ; type=SYS
|
||||||
bne next
|
bne next
|
||||||
ldy #storage_type
|
ldy #FileEntry::storage_type
|
||||||
lda (ptr),y
|
lda (ptr),y
|
||||||
and #$30 ; regular file (not directory, pascal)
|
and #$30 ; regular file (not directory, pascal)
|
||||||
beq next
|
beq next
|
||||||
@ -475,21 +393,21 @@ next: lda ptr
|
|||||||
sta ptr
|
sta ptr
|
||||||
bcc :+
|
bcc :+
|
||||||
inc ptr+1
|
inc ptr+1
|
||||||
: inc $A7
|
: inc num
|
||||||
lda $A7
|
lda num
|
||||||
cmp #$0D ; self-modified: entries_per_block
|
cmp #$0D ; self-modified: entries_per_block
|
||||||
entries_per_block_mod := *-1
|
entries_per_block_mod := *-1
|
||||||
bcc entry
|
bcc entry
|
||||||
|
|
||||||
lda data_buffer + next_block
|
lda data_buffer + VolumeDirectoryBlockHeader::next_block
|
||||||
sta read_block_params_block_num
|
sta read_block_params_block_num
|
||||||
lda data_buffer + next_block + 1
|
lda data_buffer + VolumeDirectoryBlockHeader::next_block + 1
|
||||||
sta read_block_params_block_num+1
|
sta read_block_params_block_num+1
|
||||||
ora read_block_params_block_num
|
ora read_block_params_block_num
|
||||||
beq not_found ; last block has next=0
|
beq not_found ; last block has next=0
|
||||||
jsr read_block
|
jsr read_block
|
||||||
lda #$00
|
lda #0
|
||||||
sta $A7
|
sta num
|
||||||
lda #<(data_buffer + $04)
|
lda #<(data_buffer + $04)
|
||||||
sta ptr
|
sta ptr
|
||||||
lda #>(data_buffer + $04)
|
lda #>(data_buffer + $04)
|
||||||
@ -545,8 +463,7 @@ not_found:
|
|||||||
sta ptr
|
sta ptr
|
||||||
pla
|
pla
|
||||||
sta ptr+1
|
sta ptr+1
|
||||||
|
bne skip ; always (since data not on ZP)
|
||||||
bne skip ; ???
|
|
||||||
|
|
||||||
next: cmp #(HI 'a') ; lower-case?
|
next: cmp #(HI 'a') ; lower-case?
|
||||||
bcc :+
|
bcc :+
|
||||||
@ -555,7 +472,7 @@ next: cmp #(HI 'a') ; lower-case?
|
|||||||
skip: inc ptr
|
skip: inc ptr
|
||||||
bne :+
|
bne :+
|
||||||
inc ptr+1
|
inc ptr+1
|
||||||
: ldy #$00
|
: ldy #0
|
||||||
lda (ptr),y
|
lda (ptr),y
|
||||||
bne next
|
bne next
|
||||||
|
|
||||||
|
17
prodos.mod.s
17
prodos.mod.s
@ -4,21 +4,12 @@
|
|||||||
|
|
||||||
.setcpu "6502"
|
.setcpu "6502"
|
||||||
.include "apple2.inc"
|
.include "apple2.inc"
|
||||||
|
.include "opcodes.inc"
|
||||||
|
|
||||||
|
.include "./common.inc"
|
||||||
|
|
||||||
.org $300
|
.org $300
|
||||||
|
|
||||||
;; ProDOS System Global Page
|
|
||||||
DATETIME := $BF06 ; CLOCK CALENDAR ROUTINE.
|
|
||||||
DATELO := $BF90 ; BITS 15-9=YR, 8-5=MO, 4-0=DAY
|
|
||||||
TIMELO := $BF92 ; BITS 12-8=HR, 5-0=MIN; LOW-HI FORMAT.
|
|
||||||
|
|
||||||
;; SSC 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)
|
|
||||||
|
|
||||||
.proc install
|
.proc install
|
||||||
ptr := $42
|
ptr := $42
|
||||||
|
|
||||||
@ -27,7 +18,7 @@ CONTROL := $C08B + $20 ; ACIA Control Register (read/write)
|
|||||||
sta ptr
|
sta ptr
|
||||||
lda DATETIME+2
|
lda DATETIME+2
|
||||||
sta ptr+1
|
sta ptr+1
|
||||||
lda #$4C ; JMP opcode
|
lda #OPC_JMP_abs ; JMP opcode
|
||||||
sta DATETIME
|
sta DATETIME
|
||||||
lda ROMIN ; Write bank 2
|
lda ROMIN ; Write bank 2
|
||||||
lda ROMIN
|
lda ROMIN
|
||||||
|
@ -1,20 +0,0 @@
|
|||||||
|
|
||||||
.setcpu "6502"
|
|
||||||
.include "apple2.inc"
|
|
||||||
|
|
||||||
.org $2000 ; System files start at $2000
|
|
||||||
|
|
||||||
;; ProDOS System Global Page
|
|
||||||
PRODOS := $BF00 ; MLI entry point
|
|
||||||
|
|
||||||
|
|
||||||
.proc install
|
|
||||||
rts
|
|
||||||
|
|
||||||
parmtable:
|
|
||||||
.byte 4 ; Number of parameters is 4
|
|
||||||
.byte 0 ; 0 is the only quit type
|
|
||||||
.word 0000 ; Pointer reserved for future use
|
|
||||||
.byte 0 ; Byte reserved for future use
|
|
||||||
.word 0000 ; Pointer reserved for future use
|
|
||||||
.endproc
|
|
Loading…
x
Reference in New Issue
Block a user