mirror of
https://github.com/Michaelangel007/apple2_dclock.git
synced 2024-12-23 00:29:51 +00:00
Added ca65 and merlin32 builds
This commit is contained in:
commit
fc9b33f7d2
24
Makefile
Normal file
24
Makefile
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
all: dclock.system.ca65 dclock.system.merlin32 compare
|
||||||
|
|
||||||
|
.PHONEY: compare clean
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(RM) dclock.system.ca65 dclock.system.merlin32
|
||||||
|
$(RM) dclock.system.ca65.lst dclock.system.merlin32_Output.txt
|
||||||
|
$(RM) dclock.system.ca65.o
|
||||||
|
$(RM) _FileInformation.txt
|
||||||
|
$(RM) a b
|
||||||
|
|
||||||
|
dclock.system.ca65: dclock.system.ca65.s
|
||||||
|
${CC65_HOME}/bin/ca65 dclock.system.ca65.s -l dclock.system.ca65.lst
|
||||||
|
${CC65_HOME}/bin/ld65 -t none -o dclock.system.ca65 dclock.system.ca65.o
|
||||||
|
|
||||||
|
dclock.system.merlin32: dclock.system.merlin32.s
|
||||||
|
merlin32 dclock.system.merlin32.s
|
||||||
|
|
||||||
|
compare: dclock.system.ca65 dclock.system.merlin32
|
||||||
|
hexdump -C dclock.system.ca65 > a
|
||||||
|
hexdump -C dclock.system.merlin32 > b
|
||||||
|
diff a b
|
||||||
|
|
||||||
|
|
758
dclock.system.ca65.s
Normal file
758
dclock.system.ca65.s
Normal file
@ -0,0 +1,758 @@
|
|||||||
|
; Fully disassembled and analyzed source to AE
|
||||||
|
; DCLOCK.SYSTEM by M.G. - 04/18/2017
|
||||||
|
; Assembles to a binary match for AE code unless
|
||||||
|
; FIX_BUGS is set.
|
||||||
|
|
||||||
|
; speaking of FIX_BUGS, there are critical bugs in the
|
||||||
|
; original AE code:
|
||||||
|
; * When driver loader is initially probing it corrupts the
|
||||||
|
; Apple //c Memory Expansion Card:
|
||||||
|
; - it saves, but fails to restore, data at address $080000
|
||||||
|
; - it fails to reset slinky pointer, and *will* trash $080000-$080007
|
||||||
|
; * When the clock is read, it corrupts data at address $08xx01
|
||||||
|
; - John Brooks spotted this, I totally missed this.
|
||||||
|
; Setting FIX_BUGS to 1 will fix these issues.
|
||||||
|
|
||||||
|
; other notes:
|
||||||
|
; * uses direct block access to read volume directory,
|
||||||
|
; so won't launch from an AppleShare volume.
|
||||||
|
|
||||||
|
; Build instructions:
|
||||||
|
; ca65 dclock.system.s -l dclock.system.lst
|
||||||
|
; ld65 -t none -o dclock.system dclock.system.o
|
||||||
|
; put dclock.system as a SYS file on a ProDOS disk.
|
||||||
|
|
||||||
|
FIX_BUGS := 0 ; set to 1 to fix critical bugs
|
||||||
|
|
||||||
|
.setcpu "65C02"
|
||||||
|
|
||||||
|
; zero page locations
|
||||||
|
SLASHOFFS := $00 ; offset of last '/' in our path
|
||||||
|
MYNAMELEN := $01 ; length of our file name in path
|
||||||
|
FENTPTR := $02 ; directory file entry pointer
|
||||||
|
FENTPTRL := FENTPTR
|
||||||
|
FENTPTRH := FENTPTR+1
|
||||||
|
CURENT := $04 ; current file entry in block
|
||||||
|
ENTLEN := $05 ; length of a file entry
|
||||||
|
ENTPERBLK := $06 ; number of entries per block
|
||||||
|
DIRBLK := $07 ; directory block to read
|
||||||
|
DIRBLKL := DIRBLK
|
||||||
|
DIRBLKH := DIRBLK+1
|
||||||
|
CHRPTR := $09 ; character pointer for print routine
|
||||||
|
CHRPTRL := CHRPTR
|
||||||
|
CHRPTRH := CHRPTR+1
|
||||||
|
SCRATCH := $0B ; scratch value for BCD range checks
|
||||||
|
SAVEBYTE := $0C ; slinky overwritten byte save location
|
||||||
|
BCDTMP := $3A ; location clock driver uses for BCD->Binary
|
||||||
|
|
||||||
|
; entry points
|
||||||
|
PRODOS := $BF00
|
||||||
|
HOME := $FC58
|
||||||
|
WAIT := $FCA8
|
||||||
|
COUT1 := $FDF0
|
||||||
|
|
||||||
|
; buffers & other spaces
|
||||||
|
INBUF := $0200 ; input buffer
|
||||||
|
PATHBUF := $0280 ; path buffer
|
||||||
|
CLOCKBUF := $0300 ; clock buffer
|
||||||
|
RELOCT := $1200 ; reloc target
|
||||||
|
BLOCKBUF := $1000 ; buffer for BLOCK_READ
|
||||||
|
READBUF := $1C00 ; I/O buffer for READ
|
||||||
|
SYSEXEC := $2000 ; location of SYS file executable
|
||||||
|
CLKCODE := $D742 ; Clock code location
|
||||||
|
|
||||||
|
; global Page entries
|
||||||
|
CLKENTRY := $BF06 ; clock routine entry point
|
||||||
|
DATELO := $BF90
|
||||||
|
DATEHI := $BF91
|
||||||
|
TIMELO := $BF92
|
||||||
|
TIMEHI := $BF93
|
||||||
|
MACHID := $BF98 ; machine ID
|
||||||
|
|
||||||
|
; I/O and hardware
|
||||||
|
ROMIn2 := $C082 ; access to read ROM/no write RAM
|
||||||
|
LCBank1 := $C08B ; Access twice to write bank 1
|
||||||
|
C8OFF := $CFFF ; C8xx ROM off
|
||||||
|
SLOT4ROM := $C400 ; Slot 4 ROM space
|
||||||
|
SLOT4IO := $C0C0 ; Slot 4 I/O space
|
||||||
|
DPTRL := SLOT4IO+0 ; Slinky data ptr low
|
||||||
|
DPTRM := SLOT4IO+1 ; Slinky data ptr middle
|
||||||
|
DPTRH := SLOT4IO+2 ; Slinky data ptr high
|
||||||
|
DATA := SLOT4IO+3 ; Slinky data byte
|
||||||
|
|
||||||
|
; Misc
|
||||||
|
CLKCODEMAX := $7D
|
||||||
|
|
||||||
|
.org SYSEXEC
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; relocate code from RELOCS to RELOCT
|
||||||
|
.proc DClockSystem
|
||||||
|
ldy #(rseg1e-rseg1b)
|
||||||
|
: lda RELOCS,y
|
||||||
|
sta RELOCT-1,y
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
; greetings
|
||||||
|
jsr HOME
|
||||||
|
jsr iprint
|
||||||
|
.byte $07,"DClock",$0d
|
||||||
|
jsr iprint
|
||||||
|
.byte $27,"Copyright (c)1988 Applied Engineering",$0D,$0D
|
||||||
|
jsr ClockRead
|
||||||
|
jsr ValidTime
|
||||||
|
bcc InstallDriver
|
||||||
|
; clock not found
|
||||||
|
jsr iprint
|
||||||
|
.byte $11,"Can't find clock",$0D
|
||||||
|
jmp NextSys
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Install clock driver
|
||||||
|
.proc InstallDriver
|
||||||
|
; make language card writable
|
||||||
|
lda LCBank1
|
||||||
|
lda LCBank1
|
||||||
|
; copy clock driver into ProDOS
|
||||||
|
; should not be hard-coded, Apple says to put it at
|
||||||
|
; the address pointed to at ($BF07). [PDOS8TRM 6.1.1]
|
||||||
|
ldx #$00
|
||||||
|
: lda rclkdrv-1,x
|
||||||
|
sta CLKCODE,x
|
||||||
|
inx
|
||||||
|
cpx #CLKCODEMAX
|
||||||
|
bcc :-
|
||||||
|
; make LC write-protected
|
||||||
|
lda ROMIn2
|
||||||
|
; make sure clock vector is preceded by a JMP
|
||||||
|
; (it is RTS if no clock installed)
|
||||||
|
lda #$4C
|
||||||
|
sta CLKENTRY
|
||||||
|
; indicate in MACHID that clock is present
|
||||||
|
lda MACHID
|
||||||
|
ora #$01
|
||||||
|
sta MACHID
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; find and launch the next .SYSTEM file
|
||||||
|
.proc NextSys
|
||||||
|
; check our path for last / (counted string at $0280)
|
||||||
|
ldy PATHBUF
|
||||||
|
: lda PATHBUF,y
|
||||||
|
cmp #'/'
|
||||||
|
beq LSlash
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
LSlash: sty SLASHOFFS ; offset of '/' into $00
|
||||||
|
lda PATHBUF
|
||||||
|
sec
|
||||||
|
sbc SLASHOFFS ; calculate length of our name
|
||||||
|
sta MYNAMELEN ; and put in $01
|
||||||
|
jsr ReadVolDir1 ; read first block of volume directory
|
||||||
|
bcs BadSys ; didn't get anything valid
|
||||||
|
; Now search for our own file name
|
||||||
|
ChkSlf: lda (FENTPTR) ; get length & storage type
|
||||||
|
and #$0F ; mask in length
|
||||||
|
cmp MYNAMELEN ; same as our name?
|
||||||
|
bne INext ; Nope, next entry
|
||||||
|
tay ; Now let's see if name matches
|
||||||
|
ldx PATHBUF
|
||||||
|
: lda (FENTPTR),y
|
||||||
|
cmp PATHBUF,x
|
||||||
|
bne INext ; no match, next entry
|
||||||
|
dex
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
; ok, found ourself, now get next entry and start looking for *.SYSTEM
|
||||||
|
bra SNext ; Get next entry and start checking for .SYSTEM file
|
||||||
|
INext: jsr NextFileEnt ; Get next entry and check again for ourself
|
||||||
|
bcc ChkSlf
|
||||||
|
bra BadSys ; no more valid entries
|
||||||
|
; check the current entry for .SYSTEM
|
||||||
|
ChkSys: lda (FENTPTR) ; get storage & length
|
||||||
|
and #$F0 ; mask in storage type
|
||||||
|
beq SNext ; not valid if 0
|
||||||
|
cmp #$40
|
||||||
|
bcs SNext ; not valid if >= $40 (not type 1-3)
|
||||||
|
lda (FENTPTR) ; load it again
|
||||||
|
and #$0F ; but mask in length this time
|
||||||
|
cmp #$07
|
||||||
|
bcc SNext ; not valid if not at least 7 chars long
|
||||||
|
; now check to see if it ends with .SYSTEM
|
||||||
|
tay
|
||||||
|
ldx #$07
|
||||||
|
: lda (FENTPTR),y
|
||||||
|
cmp dSYSTEM,x
|
||||||
|
bne SNext ; no match, next!
|
||||||
|
dey
|
||||||
|
dex
|
||||||
|
bne :-
|
||||||
|
ldy #$10
|
||||||
|
lda (FENTPTR),y ; get file Type
|
||||||
|
cmp #$FF ; is SYS
|
||||||
|
bne SNext ; Nope
|
||||||
|
; okay we have a .SYSTEM file to load
|
||||||
|
lda (FENTPTR) ; get storage type/name length again
|
||||||
|
and #$0F ; mask in name length
|
||||||
|
tay ; and save for copying
|
||||||
|
; calculate total length of path and put in length byte at PATHBUF
|
||||||
|
clc
|
||||||
|
adc PATHBUF
|
||||||
|
sec
|
||||||
|
sbc MYNAMELEN
|
||||||
|
sta PATHBUF
|
||||||
|
; copy filename into path
|
||||||
|
tax
|
||||||
|
: lda (FENTPTR),y
|
||||||
|
sta PATHBUF,x
|
||||||
|
dex
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
jmp LaunchNext ; proceed to launch code
|
||||||
|
; get next entry for looking for .SYSTEM
|
||||||
|
SNext: jsr NextFileEnt
|
||||||
|
bcc ChkSys
|
||||||
|
; if we get here, unable to identify next .SYSTEM
|
||||||
|
BadSys: cmp #$00 ; error code in accumulator?
|
||||||
|
beq NoSys ; no, must have not found it
|
||||||
|
pha
|
||||||
|
jsr iprint
|
||||||
|
.byte $18,"Directory ProDOS error #"
|
||||||
|
pla
|
||||||
|
jsr PrHex
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT1
|
||||||
|
jmp DoQuit ; quit to ProDOS
|
||||||
|
NoSys: jsr iprint
|
||||||
|
.byte $1d,"Can't find next .SYSTEM file",$0d
|
||||||
|
jmp DoQuit ; quit to ProDOS
|
||||||
|
dSYSTEM = * - 1
|
||||||
|
.byte ".SYSTEM"
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; this looks like some unused debugging code to print the filename
|
||||||
|
; from the current directory entry pointed to at ($02)
|
||||||
|
.proc PrintFN
|
||||||
|
lda (FENTPTR) ; get storage type/name length
|
||||||
|
pha ; save it
|
||||||
|
and #$0F ; mask in name length
|
||||||
|
sta (FENTPTR) ; put in file entry
|
||||||
|
beq done ; if zero, we are done
|
||||||
|
ldy #$01 ; start with byte 1 of entry
|
||||||
|
: lda (FENTPTR),y ; get file name char
|
||||||
|
ora #$80
|
||||||
|
jsr COUT1 ; print it
|
||||||
|
tya
|
||||||
|
iny
|
||||||
|
cmp (FENTPTR) ; printed all the chars?
|
||||||
|
bcc :- ; nope
|
||||||
|
lda #$8D ; CR
|
||||||
|
jsr COUT1
|
||||||
|
done: pla ; get type/name length
|
||||||
|
sta (FENTPTR) ; and restore it in file entry
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; get volume directory first block ($0002)
|
||||||
|
; and initialize values for processing
|
||||||
|
; returns carry clear if no error, set otherwise
|
||||||
|
.proc ReadVolDir1
|
||||||
|
lda #$02
|
||||||
|
sta DIRBLKL ; initialize block number low byte
|
||||||
|
stz DIRBLKH ; and high byte
|
||||||
|
jsr ReadVolDir ; read volume directory block
|
||||||
|
bcs done ; done if error
|
||||||
|
lda BLOCKBUF+$23 ; get entry length
|
||||||
|
sta ENTLEN ; and save it
|
||||||
|
lda BLOCKBUF+$24 ; get entries per block
|
||||||
|
sta ENTPERBLK ; and save it
|
||||||
|
; intial values $02/03 = $102B (offset of first file entry in first VD block)
|
||||||
|
lda #<(BLOCKBUF+$2b)
|
||||||
|
sta FENTPTRL
|
||||||
|
lda #>(BLOCKBUF+$2b)
|
||||||
|
sta FENTPTRH
|
||||||
|
lda #$02 ; on first block, start with entry #2
|
||||||
|
sta CURENT
|
||||||
|
clc
|
||||||
|
done: rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Update pointer to the next directory file entry
|
||||||
|
; read the next block if necessary
|
||||||
|
; returns carry clear if no error, set otherwise
|
||||||
|
.proc NextFileEnt
|
||||||
|
; add entry length to current entry pointer at ($02)
|
||||||
|
clc
|
||||||
|
lda FENTPTRL
|
||||||
|
adc ENTLEN
|
||||||
|
sta FENTPTRL
|
||||||
|
lda FENTPTRH
|
||||||
|
adc #$00
|
||||||
|
sta FENTPTRH
|
||||||
|
inc CURENT ; increment current entry number
|
||||||
|
lda CURENT ; and load it
|
||||||
|
cmp ENTPERBLK ; did the last one in block?
|
||||||
|
bcc Okay ; nope, exit
|
||||||
|
; check if last block of Volume Directory
|
||||||
|
lda DIRBLKL ; block low byte
|
||||||
|
bne NxtBlk ; another one to read
|
||||||
|
lda DIRBLKH ; block high byte
|
||||||
|
beq Fail ; also zero, exit with error
|
||||||
|
; read next block of Volume Directory
|
||||||
|
NxtBlk: jsr ReadVolDir ; next volume directory block
|
||||||
|
bcs Fail ; read problem, exit with error
|
||||||
|
lda #<(BLOCKBUF+$04) ; now set entry pointer to the offset of the first
|
||||||
|
sta FENTPTRL ; one in the block
|
||||||
|
lda #>(BLOCKBUF+$04) ; ...
|
||||||
|
sta FENTPTRH ; ...
|
||||||
|
lda #$01 ; and set current entry
|
||||||
|
sta CURENT ; to 1
|
||||||
|
Okay: clc
|
||||||
|
rts
|
||||||
|
Fail: sec
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; read volume directory block at ($07)
|
||||||
|
; and update to point to next block
|
||||||
|
; returns carry clear if no error, set otherwise
|
||||||
|
.proc ReadVolDir
|
||||||
|
; most recent accessed device into param list for READ_BLOCK
|
||||||
|
lda $BF30 ; most recent access device
|
||||||
|
sta PL_READ_BLOCK+1 ; into READ_BLOCK parameter list
|
||||||
|
; copy block number to param list
|
||||||
|
lda DIRBLKL ; copy block number
|
||||||
|
sta PL_READ_BLOCK+4 ; to parameter list
|
||||||
|
lda DIRBLKH ; ...
|
||||||
|
sta PL_READ_BLOCK+5 ; ...
|
||||||
|
jsr PRODOS ; now get the block
|
||||||
|
.byte $80 ; READ_BLOCK
|
||||||
|
.word PL_READ_BLOCK
|
||||||
|
bcs Done ; error, bail out
|
||||||
|
lda BLOCKBUF+$02 ; otherwise get next block number
|
||||||
|
sta DIRBLKL ; from offset $02/$03
|
||||||
|
lda BLOCKBUF+$03 ; and save it
|
||||||
|
sta DIRBLKH ; ...
|
||||||
|
Done: rts
|
||||||
|
; Parameter list for READ_BLOCK
|
||||||
|
PL_READ_BLOCK:
|
||||||
|
.byte $03 ; param count
|
||||||
|
.byte $00 ; unit number
|
||||||
|
.word BLOCKBUF ; data buffer
|
||||||
|
.word $0000 ; block number
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; enable slinky registers, set adddress and save byte we intend to trash
|
||||||
|
.proc SlinkyEnable
|
||||||
|
lda C8OFF ; not needed on //c, but release $C8xx firmware
|
||||||
|
lda SLOT4ROM ; enable slinky registers
|
||||||
|
lda #$08 ; set addr $080000
|
||||||
|
sta DPTRH
|
||||||
|
stz DPTRM
|
||||||
|
stz DPTRL
|
||||||
|
lda DATA ; read data byte
|
||||||
|
sta SAVEBYTE ; save it to restore later
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Routine to restore trashed byte in slinky RAM
|
||||||
|
; WARNING: never called by unfixed, so the value is never restored
|
||||||
|
.proc SlinkyRestore
|
||||||
|
lda #$08 ; set adddr $080000
|
||||||
|
sta DPTRH
|
||||||
|
stz DPTRM
|
||||||
|
stz DPTRL
|
||||||
|
lda SAVEBYTE ; get saved byte
|
||||||
|
sta DATA ; and put it back
|
||||||
|
lda C8OFF ; not needed on //c, but release $C8xx firmware
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Write 8 bits to clock
|
||||||
|
; WARNING: the unfixed code has a bug that trashes 8 bytes in the RAM card at $080000
|
||||||
|
.proc ClockWrite8b
|
||||||
|
ldx #$08 ; set adddr $080000
|
||||||
|
.if ::FIX_BUGS
|
||||||
|
stx DPTRH
|
||||||
|
stz DPTRM
|
||||||
|
: stz DPTRL ; restore low byte to 0
|
||||||
|
sta DATA ; write byte
|
||||||
|
.else
|
||||||
|
stz DPTRL
|
||||||
|
stz DPTRM
|
||||||
|
stx DPTRH
|
||||||
|
: sta DATA ; write byte
|
||||||
|
.endif
|
||||||
|
lsr a ; next bit into 0 position
|
||||||
|
dex
|
||||||
|
bne :-
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; unlock the clock by writing the magic bit sequence
|
||||||
|
.proc ClockUnlock
|
||||||
|
ldy #$08
|
||||||
|
: lda unlock,y
|
||||||
|
jsr ClockWrite8b ; write 8 bits
|
||||||
|
dey
|
||||||
|
bne :-
|
||||||
|
rts
|
||||||
|
unlock = * - 1
|
||||||
|
.byte $5c, $a3, $3a, $c5, $5c, $a3, $3a, $c5
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Read 8 bits from the clock
|
||||||
|
.proc ClockRead8b
|
||||||
|
ldx #$08 ; set adddr $080000
|
||||||
|
stz DPTRL
|
||||||
|
stz DPTRM
|
||||||
|
stx DPTRH
|
||||||
|
: pha ; save accumulator
|
||||||
|
lda DATA ; get data byte
|
||||||
|
lsr a ; bit 0 into carry
|
||||||
|
pla ; restore accumulator
|
||||||
|
ror a ; put read bit into position
|
||||||
|
dex
|
||||||
|
bne :-
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; read the clock data into memory at CLOCKBUF
|
||||||
|
; WARNING: unfixed code never restores byte we trashed
|
||||||
|
.proc ClockRead
|
||||||
|
jsr SlinkyEnable
|
||||||
|
jsr ClockUnlock
|
||||||
|
ldy #$00
|
||||||
|
: jsr ClockRead8b
|
||||||
|
sta CLOCKBUF,y
|
||||||
|
iny
|
||||||
|
cpy #$08 ; have we read 8 bytes?
|
||||||
|
bcc :- ; nope
|
||||||
|
.if ::FIX_BUGS
|
||||||
|
jsr SlinkyRestore
|
||||||
|
.endif
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; validate the DClock data makes sense
|
||||||
|
; return carry clear if it does, carry set if it does not
|
||||||
|
.proc ValidTime
|
||||||
|
; validate ms
|
||||||
|
ldx #$00
|
||||||
|
ldy #$99
|
||||||
|
lda CLOCKBUF
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
; validate seconds
|
||||||
|
ldx #$00
|
||||||
|
ldy #$59
|
||||||
|
lda CLOCKBUF+$01
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
; validate minutes
|
||||||
|
ldx #$00
|
||||||
|
ldy #$59
|
||||||
|
lda CLOCKBUF+$02
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
; validate hours
|
||||||
|
ldx #$00
|
||||||
|
ldy #$23
|
||||||
|
lda CLOCKBUF+$03
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
; validate day of week
|
||||||
|
ldx #$01
|
||||||
|
ldy #$07
|
||||||
|
lda CLOCKBUF+$04
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
; validate day of month
|
||||||
|
ldx #$01
|
||||||
|
ldy #$31
|
||||||
|
lda CLOCKBUF+$05
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
; validate month
|
||||||
|
ldx #$01
|
||||||
|
ldy #$12
|
||||||
|
lda CLOCKBUF+$06
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
; validate year
|
||||||
|
ldx #$00
|
||||||
|
ldy #$99
|
||||||
|
lda CLOCKBUF+$07
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :+
|
||||||
|
clc ; all good
|
||||||
|
rts
|
||||||
|
: sec ; problem
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Check BCD number in range of [x,y]
|
||||||
|
; return carry clear if it is, carry set if it is not
|
||||||
|
.proc CheckBCD
|
||||||
|
sed ; decimal mode
|
||||||
|
stx SCRATCH ; lower bound into scratch
|
||||||
|
cmp SCRATCH ; compare it
|
||||||
|
bcc :++ ; fail if out of range
|
||||||
|
sty SCRATCH ; upper bound into scratch
|
||||||
|
cmp SCRATCH ; compare it
|
||||||
|
beq :+ ; OK if equal
|
||||||
|
bcs :++ ; fail if out of range
|
||||||
|
: cld ; in range
|
||||||
|
clc
|
||||||
|
rts
|
||||||
|
: cld ; not in range
|
||||||
|
sec
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; This code segment is relocated to RELOCT at the start of program
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
RELOCS = * - 1
|
||||||
|
rseg1bm = *
|
||||||
|
.org RELOCT
|
||||||
|
rseg1b = *
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; This routine attempts to execute the next system file that we identified
|
||||||
|
; in the main code
|
||||||
|
.proc LaunchNext
|
||||||
|
jsr PRODOS
|
||||||
|
.byte $C8 ; OPEN
|
||||||
|
.word PL_OPEN
|
||||||
|
bcs LaunchFail ; if error
|
||||||
|
lda PL_OPEN+5 ; copy reference number
|
||||||
|
sta PL_GET_EOF+1 ; to parm list for GET_EOF
|
||||||
|
sta PL_READ+1 ; and parm list for READ
|
||||||
|
sta PL_CLOSE+1 ; and parm list for CLOSE
|
||||||
|
jsr PRODOS
|
||||||
|
.byte $D1 ; GET_EOF
|
||||||
|
.word PL_GET_EOF
|
||||||
|
bcs LaunchFail ; if error
|
||||||
|
lda PL_GET_EOF+4 ; high byte of length
|
||||||
|
bne LaunchFail ; bigger than 64K... sheesh
|
||||||
|
lda PL_GET_EOF+2 ; copy EOF middle and low
|
||||||
|
sta PL_READ+4 ; to read reqest count
|
||||||
|
lda PL_GET_EOF+3 ; ...
|
||||||
|
sta PL_READ+5 ; ...
|
||||||
|
jsr PRODOS ; and do read
|
||||||
|
.byte $CA ; READ
|
||||||
|
.word PL_READ
|
||||||
|
bcs LaunchFail ; if error
|
||||||
|
jsr PRODOS
|
||||||
|
.byte $CC ; CLOSE
|
||||||
|
.word PL_CLOSE
|
||||||
|
bcs LaunchFail ; if error
|
||||||
|
jmp SYSEXEC ; execute system file
|
||||||
|
LaunchFail:
|
||||||
|
pha ; save accumulator
|
||||||
|
jsr iprint ; because this trashes it
|
||||||
|
.byte $22,"Can't start next SYS file: error #"
|
||||||
|
pla ; restore accumulator
|
||||||
|
jsr PrHex ; print error code
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT1
|
||||||
|
jmp DoQuit ; quit to ProDOS
|
||||||
|
; parameter list for OPEN
|
||||||
|
PL_OPEN:
|
||||||
|
.byte $03 ; param count
|
||||||
|
.word PATHBUF ; pathname address
|
||||||
|
.word READBUF ; I/O buffer
|
||||||
|
.byte $00 ; reference number
|
||||||
|
; parameter list for GET_EOF
|
||||||
|
PL_GET_EOF:
|
||||||
|
.byte $02 ; param count
|
||||||
|
.byte $00 ; ref number
|
||||||
|
.byte $00,$00,$00 ; EOF
|
||||||
|
; parameter list for READ
|
||||||
|
PL_READ:
|
||||||
|
.byte $04 ; param count
|
||||||
|
.byte $00 ; ref number
|
||||||
|
.word SYSEXEC ; data buffer
|
||||||
|
.word $0000 ; request count
|
||||||
|
.word $0000 ; transfer count
|
||||||
|
; parameter list for CLOSE
|
||||||
|
PL_CLOSE:
|
||||||
|
.byte $01 ; param count
|
||||||
|
.byte $00 ; ref number
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Routine to print hex number via LUT
|
||||||
|
; the firmware has a perfectly good routine for this, not sure why
|
||||||
|
; AE engineers put this in here. Nice wheel, though.
|
||||||
|
.proc PrHex
|
||||||
|
pha
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
tax
|
||||||
|
lda :+,x
|
||||||
|
jsr COUT1
|
||||||
|
pla
|
||||||
|
and #$0F
|
||||||
|
tax
|
||||||
|
lda :+,x
|
||||||
|
jsr COUT1
|
||||||
|
rts
|
||||||
|
: .byte "0123456789ABCDEF"
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Execute QUIT call after long delay, exit via RTS if QUIT fails
|
||||||
|
.proc DoQuit
|
||||||
|
ldx #$0C
|
||||||
|
: lda #$FF
|
||||||
|
jsr WAIT
|
||||||
|
dex
|
||||||
|
bne :-
|
||||||
|
jsr PRODOS
|
||||||
|
.byte $65
|
||||||
|
.word PL_QUIT
|
||||||
|
rts
|
||||||
|
; parameter list for QUIT
|
||||||
|
PL_QUIT:
|
||||||
|
.byte $04 ; param count
|
||||||
|
.byte $00 ; quit type - $00 is only type
|
||||||
|
.word $0000 ; reserved
|
||||||
|
.byte $00 ; reserved
|
||||||
|
.word $0000 ; reserved
|
||||||
|
; unnecessary fill?
|
||||||
|
brk
|
||||||
|
brk
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; 'inline print'
|
||||||
|
; print counted string following JSR
|
||||||
|
.proc iprint
|
||||||
|
; get pointer into $09/$0a
|
||||||
|
pla
|
||||||
|
clc
|
||||||
|
adc #$01
|
||||||
|
sta CHRPTRL
|
||||||
|
pla
|
||||||
|
adc #$00
|
||||||
|
sta CHRPTRH
|
||||||
|
lda (CHRPTR)
|
||||||
|
beq done
|
||||||
|
; now print the string
|
||||||
|
tay
|
||||||
|
ldy #$01
|
||||||
|
ploop: lda (CHRPTR),y
|
||||||
|
ora #$80
|
||||||
|
jsr COUT1
|
||||||
|
tya
|
||||||
|
iny
|
||||||
|
cmp (CHRPTR)
|
||||||
|
bcc ploop
|
||||||
|
; done, fix up stack and exit
|
||||||
|
done: clc
|
||||||
|
adc CHRPTRL
|
||||||
|
sta CHRPTRL
|
||||||
|
lda #$00
|
||||||
|
adc CHRPTRH
|
||||||
|
pha
|
||||||
|
lda CHRPTRL
|
||||||
|
pha
|
||||||
|
rts
|
||||||
|
.endproc
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; end of relocated code
|
||||||
|
rseg1e = *
|
||||||
|
; fix up org address so we get a clean ref to rclkdrv
|
||||||
|
.org rseg1bm + (rseg1e - rseg1b + 1)
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; clock driver code inserted into ProDOS at $D742 - this shouldn't be
|
||||||
|
; hard-coded but it is.
|
||||||
|
; critical bug: Corrupts byte in $08xx01 of the //c memory expansion card.
|
||||||
|
rclkdrv = *
|
||||||
|
.org CLKCODE
|
||||||
|
.proc clockdrv
|
||||||
|
begin = *
|
||||||
|
lda #$08 ; useless instruction
|
||||||
|
php
|
||||||
|
sei
|
||||||
|
lda SLOT4ROM ; activate slinky registers
|
||||||
|
; ($08 from above overwritten)
|
||||||
|
stz DPTRL ; set slinky address to $08xx00
|
||||||
|
ldy #$08 ; also counter for unlock bytes
|
||||||
|
sty DPTRH
|
||||||
|
lda DATA ; get destroyed byte
|
||||||
|
; (slinky now at $08xx01)
|
||||||
|
pha ; save value on stack
|
||||||
|
; unlock dclock registers
|
||||||
|
ubytlp: lda regulk,y
|
||||||
|
ldx #$08 ; bit counter
|
||||||
|
.if ::FIX_BUGS
|
||||||
|
ubitlp: stz DPTRL ; reset pointer to $08xx00
|
||||||
|
sta DATA ; write to $08xx00
|
||||||
|
.else
|
||||||
|
ubitlp: sta DATA ; write to $08xx00
|
||||||
|
; (!but not on first iteration!)
|
||||||
|
stz DPTRL ; reset pointer to $08xx00
|
||||||
|
.endif
|
||||||
|
lsr a ; next bit into 0 position
|
||||||
|
dex
|
||||||
|
bne ubitlp
|
||||||
|
dey
|
||||||
|
bne ubytlp
|
||||||
|
; now read 64 bits (8 bytes) from dclock
|
||||||
|
ldx #$08 ; byte counter
|
||||||
|
rbytlp: ldy #$08 ; bit counter
|
||||||
|
rbitlp: pha
|
||||||
|
lda DATA ; data byte
|
||||||
|
lsr a ; bit 0 into carry
|
||||||
|
pla
|
||||||
|
ror a ; carry into bit 7
|
||||||
|
dey
|
||||||
|
bne rbitlp
|
||||||
|
; got 8 bits now, convert from BCD to binary
|
||||||
|
pha
|
||||||
|
and #$0F
|
||||||
|
sta BCDTMP
|
||||||
|
pla
|
||||||
|
and #$F0
|
||||||
|
lsr a
|
||||||
|
pha
|
||||||
|
adc BCDTMP
|
||||||
|
sta BCDTMP
|
||||||
|
pla
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
adc BCDTMP
|
||||||
|
; place in input buffer, which is OK because the ThunderClock driver does this
|
||||||
|
sta INBUF-1,x
|
||||||
|
dex
|
||||||
|
bne rbytlp
|
||||||
|
; done copying, now put necessary values into ProDOS time locations
|
||||||
|
; copy hours to ProDOS hours
|
||||||
|
lda INBUF+4
|
||||||
|
sta TIMEHI
|
||||||
|
; copy minutes to ProDOS minutes
|
||||||
|
lda INBUF+5
|
||||||
|
sta TIMELO
|
||||||
|
; copy month ...
|
||||||
|
lda INBUF+1
|
||||||
|
lsr a
|
||||||
|
ror a
|
||||||
|
ror a
|
||||||
|
ror a
|
||||||
|
; ... and day of month to ProDOS month/day
|
||||||
|
ora INBUF+2
|
||||||
|
sta DATELO
|
||||||
|
; copy year and final bit of month to ProDOS year/month
|
||||||
|
lda INBUF
|
||||||
|
rol a
|
||||||
|
sta DATEHI
|
||||||
|
stz DPTRL ; set slinky back to $08xx00
|
||||||
|
pla ; get saved byte
|
||||||
|
sta DATA ; put it back
|
||||||
|
plp
|
||||||
|
rts
|
||||||
|
; DS1215 unlock sequence (in reverse)
|
||||||
|
regulk = * - 1
|
||||||
|
.byte $5C, $A3, $3A, $C5, $5C, $A3, $3A, $C5
|
||||||
|
end = *
|
||||||
|
.assert (begin - end + 1) < CLKCODEMAX, error, "DCLOCK driver too big"
|
||||||
|
.endproc
|
772
dclock.system.merlin32.s
Normal file
772
dclock.system.merlin32.s
Normal file
@ -0,0 +1,772 @@
|
|||||||
|
; Fully disassembled and analyzed source to AE
|
||||||
|
; DCLOCK.SYSTEM by M.G. - 04/18/2017
|
||||||
|
; Assembles to a binary match for AE code unless
|
||||||
|
; FIX_BUGS is set.
|
||||||
|
|
||||||
|
; speaking of FIX_BUGS, there are critical bugs in the
|
||||||
|
; original AE code:
|
||||||
|
; * When driver loader is initially probing it corrupts the
|
||||||
|
; Apple //c Memory Expansion Card:
|
||||||
|
; - it saves, but fails to restore, data at address $080000
|
||||||
|
; - it fails to reset slinky pointer, and *will* trash $080000-$080007
|
||||||
|
; * When the clock is read, it corrupts data at address $08xx01
|
||||||
|
; - John Brooks spotted this, I totally missed this.
|
||||||
|
; Setting FIX_BUGS to 1 will fix these issues.
|
||||||
|
|
||||||
|
; other notes:
|
||||||
|
; * uses direct block access to read volume directory,
|
||||||
|
; so won't launch from an AppleShare volume.
|
||||||
|
|
||||||
|
; Build instructions:
|
||||||
|
; ca65 dclock.system.s -l dclock.system.lst
|
||||||
|
; ld65 -t none -o dclock.system dclock.system.o
|
||||||
|
; put dclock.system as a SYS file on a ProDOS disk.
|
||||||
|
|
||||||
|
FIX_BUGS = 0 ; set to 1 to fix critical bugs
|
||||||
|
|
||||||
|
;.setcpu "65C02"
|
||||||
|
|
||||||
|
; zero page locations
|
||||||
|
SLASHOFFS = $00 ; offset of last '/' in our path
|
||||||
|
MYNAMELEN = $01 ; length of our file name in path
|
||||||
|
FENTPTR = $02 ; directory file entry pointer
|
||||||
|
FENTPTRL = FENTPTR
|
||||||
|
FENTPTRH = FENTPTR+1
|
||||||
|
CURENT = $04 ; current file entry in block
|
||||||
|
ENTLEN = $05 ; length of a file entry
|
||||||
|
ENTPERBLK = $06 ; number of entries per block
|
||||||
|
DIRBLK = $07 ; directory block to read
|
||||||
|
DIRBLKL = DIRBLK
|
||||||
|
DIRBLKH = DIRBLK+1
|
||||||
|
CHRPTR = $09 ; character pointer for print routine
|
||||||
|
CHRPTRL = CHRPTR
|
||||||
|
CHRPTRH = CHRPTR+1
|
||||||
|
SCRATCH = $0B ; scratch value for BCD range checks
|
||||||
|
SAVEBYTE = $0C ; slinky overwritten byte save location
|
||||||
|
BCDTMP = $3A ; location clock driver uses for BCD->Binary
|
||||||
|
|
||||||
|
; entry points
|
||||||
|
PRODOS = $BF00
|
||||||
|
HOME = $FC58
|
||||||
|
WAIT = $FCA8
|
||||||
|
COUT1 = $FDF0
|
||||||
|
|
||||||
|
; buffers & other spaces
|
||||||
|
INBUF = $0200 ; input buffer
|
||||||
|
PATHBUF = $0280 ; path buffer
|
||||||
|
CLOCKBUF = $0300 ; clock buffer
|
||||||
|
RELOCT = $1200 ; reloc target
|
||||||
|
BLOCKBUF = $1000 ; buffer for BLOCK_READ
|
||||||
|
READBUF = $1C00 ; I/O buffer for READ
|
||||||
|
SYSEXEC = $2000 ; location of SYS file executable
|
||||||
|
CLKCODE = $D742 ; Clock code location
|
||||||
|
|
||||||
|
; global Page entries
|
||||||
|
CLKENTRY = $BF06 ; clock routine entry point
|
||||||
|
DATELO = $BF90
|
||||||
|
DATEHI = $BF91
|
||||||
|
TIMELO = $BF92
|
||||||
|
TIMEHI = $BF93
|
||||||
|
MACHID = $BF98 ; machine ID
|
||||||
|
|
||||||
|
; I/O and hardware
|
||||||
|
ROMIn2 = $C082 ; access to read ROM/no write RAM
|
||||||
|
LCBank1 = $C08B ; Access twice to write bank 1
|
||||||
|
C8OFF = $CFFF ; C8xx ROM off
|
||||||
|
SLOT4ROM = $C400 ; Slot 4 ROM space
|
||||||
|
SLOT4IO = $C0C0 ; Slot 4 I/O space
|
||||||
|
DPTRL = SLOT4IO+0 ; Slinky data ptr low
|
||||||
|
DPTRM = SLOT4IO+1 ; Slinky data ptr middle
|
||||||
|
DPTRH = SLOT4IO+2 ; Slinky data ptr high
|
||||||
|
DATA = SLOT4IO+3 ; Slinky data byte
|
||||||
|
|
||||||
|
; Misc
|
||||||
|
CLKCODEMAX = $7D
|
||||||
|
|
||||||
|
; PRODOS Command
|
||||||
|
PRODOS_QUIT = $65
|
||||||
|
PRODOS_READ_BLOCK = $80
|
||||||
|
PRODOS_OPEN = $C8
|
||||||
|
PRODOS_READ = $CA
|
||||||
|
PRODOS_CLOSE = $CC
|
||||||
|
PRODOS_GET_EOF = $D1
|
||||||
|
|
||||||
|
ORG SYSEXEC
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; relocate code from RELOCS to RELOCT
|
||||||
|
DClockSystem
|
||||||
|
RSEG1 = rseg1e-rseg1b ; MERLIN32: removed ()
|
||||||
|
ldy #rseg1e-rseg1b ; MERLIN32: removed ()
|
||||||
|
:_ lda RELOCS,y
|
||||||
|
sta RELOCT-1,y
|
||||||
|
dey
|
||||||
|
bne :_
|
||||||
|
; greetings
|
||||||
|
jsr HOME
|
||||||
|
jsr iprint
|
||||||
|
STR 'DClock',0D
|
||||||
|
jsr iprint
|
||||||
|
STR 'Copyright (c)1988 Applied Engineering',0D,0D
|
||||||
|
jsr ClockRead
|
||||||
|
jsr ValidTime
|
||||||
|
bcc InstallDriver
|
||||||
|
; clock not found
|
||||||
|
jsr iprint
|
||||||
|
STR 'Can',27,'t find clock',0D
|
||||||
|
jmp NextSys
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Install clock driver
|
||||||
|
InstallDriver
|
||||||
|
; make language card writable
|
||||||
|
lda LCBank1
|
||||||
|
lda LCBank1
|
||||||
|
; copy clock driver into ProDOS
|
||||||
|
; should not be hard-coded, Apple says to put it at
|
||||||
|
; the address pointed to at ($BF07). [PDOS8TRM 6.1.1]
|
||||||
|
ldx #$00
|
||||||
|
:_ lda rclkdrv-1,x
|
||||||
|
sta CLKCODE,x
|
||||||
|
inx
|
||||||
|
cpx #CLKCODEMAX
|
||||||
|
bcc :_
|
||||||
|
; make LC write-protected
|
||||||
|
lda ROMIn2
|
||||||
|
; make sure clock vector is preceded by a JMP
|
||||||
|
; (it is RTS if no clock installed)
|
||||||
|
lda #$4C
|
||||||
|
sta CLKENTRY
|
||||||
|
; indicate in MACHID that clock is present
|
||||||
|
lda MACHID
|
||||||
|
ora #$01
|
||||||
|
sta MACHID
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; find and launch the next .SYSTEM file
|
||||||
|
NextSys
|
||||||
|
; check our path for last / (counted string at $0280)
|
||||||
|
ldy PATHBUF
|
||||||
|
:_ lda PATHBUF,y
|
||||||
|
cmp #'/'
|
||||||
|
beq :LSlash
|
||||||
|
dey
|
||||||
|
bne :_
|
||||||
|
:LSlash sty SLASHOFFS ; offset of '/' into $00
|
||||||
|
lda PATHBUF
|
||||||
|
sec
|
||||||
|
sbc SLASHOFFS ; calculate length of our name
|
||||||
|
sta MYNAMELEN ; and put in $01
|
||||||
|
jsr ReadVolDir1 ; read first block of volume directory
|
||||||
|
bcs :BadSys ; didn't get anything valid
|
||||||
|
; Now search for our own file name
|
||||||
|
:ChkSlf lda (FENTPTR) ; get length & storage type
|
||||||
|
and #$0F ; mask in length
|
||||||
|
cmp MYNAMELEN ; same as our name?
|
||||||
|
bne :INext ; Nope, next entry
|
||||||
|
tay ; Now let's see if name matches
|
||||||
|
ldx PATHBUF
|
||||||
|
:__ lda (FENTPTR),y
|
||||||
|
cmp PATHBUF,x
|
||||||
|
bne :INext ; no match, next entry
|
||||||
|
dex
|
||||||
|
dey
|
||||||
|
bne :__
|
||||||
|
; ok, found ourself, now get next entry and start looking for *.SYSTEM
|
||||||
|
bra :SNext ; Get next entry and start checking for .SYSTEM file
|
||||||
|
:INext jsr NextFileEnt ; Get next entry and check again for ourself
|
||||||
|
bcc :ChkSlf
|
||||||
|
bra :BadSys ; no more valid entries
|
||||||
|
; check the current entry for .SYSTEM
|
||||||
|
:ChkSys lda (FENTPTR) ; get storage & length
|
||||||
|
and #$F0 ; mask in storage type
|
||||||
|
beq :SNext ; not valid if 0
|
||||||
|
cmp #$40
|
||||||
|
bcs :SNext ; not valid if >= $40 (not type 1-3)
|
||||||
|
lda (FENTPTR) ; load it again
|
||||||
|
and #$0F ; but mask in length this time
|
||||||
|
cmp #$07
|
||||||
|
bcc :SNext ; not valid if not at least 7 chars long
|
||||||
|
; now check to see if it ends with .SYSTEM
|
||||||
|
tay
|
||||||
|
ldx #$07
|
||||||
|
:___ lda (FENTPTR),y
|
||||||
|
cmp dSYSTEM,x
|
||||||
|
bne :SNext ; no match, next!
|
||||||
|
dey
|
||||||
|
dex
|
||||||
|
bne :___
|
||||||
|
ldy #$10
|
||||||
|
lda (FENTPTR),y ; get file Type
|
||||||
|
cmp #$FF ; is SYS
|
||||||
|
bne :SNext ; Nope
|
||||||
|
; okay we have a .SYSTEM file to load
|
||||||
|
lda (FENTPTR) ; get storage type/name length again
|
||||||
|
and #$0F ; mask in name length
|
||||||
|
tay ; and save for copying
|
||||||
|
; calculate total length of path and put in length byte at PATHBUF
|
||||||
|
clc
|
||||||
|
adc PATHBUF
|
||||||
|
sec
|
||||||
|
sbc MYNAMELEN
|
||||||
|
sta PATHBUF
|
||||||
|
; copy filename into path
|
||||||
|
tax
|
||||||
|
:____ lda (FENTPTR),y
|
||||||
|
sta PATHBUF,x
|
||||||
|
dex
|
||||||
|
dey
|
||||||
|
bne :____
|
||||||
|
jmp LaunchNext ; proceed to launch code
|
||||||
|
; get next entry for looking for .SYSTEM
|
||||||
|
:SNext jsr NextFileEnt
|
||||||
|
bcc :ChkSys
|
||||||
|
; if we get here, unable to identify next .SYSTEM
|
||||||
|
:BadSys cmp #$00 ; error code in accumulator?
|
||||||
|
beq :NoSys ; no, must have not found it
|
||||||
|
pha
|
||||||
|
jsr iprint
|
||||||
|
STR 'Directory ProDOS error #' ; MERLIN32: removed len $18
|
||||||
|
pla
|
||||||
|
jsr PrHex
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT1
|
||||||
|
jmp DoQuit ; quit to ProDOS
|
||||||
|
:NoSys jsr iprint
|
||||||
|
STR 'Can',27,'t find next .SYSTEM file',0d ; MERLIN32: REMOVED length $1D, replaced "'" with /27/
|
||||||
|
jmp DoQuit ; quit to ProDOS
|
||||||
|
dSYSTEM = * - 1
|
||||||
|
ASC '.SYSTEM'
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; this looks like some unused debugging code to print the filename
|
||||||
|
; from the current directory entry pointed to at ($02)
|
||||||
|
PrintFN
|
||||||
|
lda (FENTPTR) ; get storage type/name length
|
||||||
|
pha ; save it
|
||||||
|
and #$0F ; mask in name length
|
||||||
|
sta (FENTPTR) ; put in file entry
|
||||||
|
beq :done ; if zero, we are done
|
||||||
|
ldy #$01 ; start with byte 1 of entry
|
||||||
|
:_ lda (FENTPTR),y ; get file name char
|
||||||
|
ora #$80
|
||||||
|
jsr COUT1 ; print it
|
||||||
|
tya
|
||||||
|
iny
|
||||||
|
cmp (FENTPTR) ; printed all the chars?
|
||||||
|
bcc :_ ; nope
|
||||||
|
lda #$8D ; CR
|
||||||
|
jsr COUT1
|
||||||
|
:done pla ; get type/name length
|
||||||
|
sta (FENTPTR) ; and restore it in file entry
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; get volume directory first block ($0002)
|
||||||
|
; and initialize values for processing
|
||||||
|
; returns carry clear if no error, set otherwise
|
||||||
|
ReadVolDir1
|
||||||
|
lda #$02
|
||||||
|
sta DIRBLKL ; initialize block number low byte
|
||||||
|
stz DIRBLKH ; and high byte
|
||||||
|
jsr ReadVolDir ; read volume directory block
|
||||||
|
bcs :done ; done if error
|
||||||
|
lda BLOCKBUF+$23 ; get entry length
|
||||||
|
sta ENTLEN ; and save it
|
||||||
|
lda BLOCKBUF+$24 ; get entries per block
|
||||||
|
sta ENTPERBLK ; and save it
|
||||||
|
; intial values $02/03 = $102B (offset of first file entry in first VD block)
|
||||||
|
lda #<BLOCKBUF+$2b ; MERLIN32: removed ()
|
||||||
|
sta FENTPTRL
|
||||||
|
lda #>BLOCKBUF+$2b ; MERLIN32: removed ()
|
||||||
|
sta FENTPTRH
|
||||||
|
lda #$02 ; on first block, start with entry #2
|
||||||
|
sta CURENT
|
||||||
|
clc
|
||||||
|
:done rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Update pointer to the next directory file entry
|
||||||
|
; read the next block if necessary
|
||||||
|
; returns carry clear if no error, set otherwise
|
||||||
|
NextFileEnt
|
||||||
|
; add entry length to current entry pointer at ($02)
|
||||||
|
clc
|
||||||
|
lda FENTPTRL
|
||||||
|
adc ENTLEN
|
||||||
|
sta FENTPTRL
|
||||||
|
lda FENTPTRH
|
||||||
|
adc #$00
|
||||||
|
sta FENTPTRH
|
||||||
|
inc CURENT ; increment current entry number
|
||||||
|
lda CURENT ; and load it
|
||||||
|
cmp ENTPERBLK ; did the last one in block?
|
||||||
|
bcc :Okay ; nope, exit
|
||||||
|
; check if last block of Volume Directory
|
||||||
|
lda DIRBLKL ; block low byte
|
||||||
|
bne :NxtBlk ; another one to read
|
||||||
|
lda DIRBLKH ; block high byte
|
||||||
|
beq :Fail ; also zero, exit with error
|
||||||
|
; read next block of Volume Directory
|
||||||
|
:NxtBlk jsr ReadVolDir ; next volume directory block
|
||||||
|
bcs :Fail ; read problem, exit with error
|
||||||
|
lda #<BLOCKBUF+$04 ; now set entry pointer to the offset of the first MERLIN32: removed ()
|
||||||
|
sta FENTPTRL ; one in the block
|
||||||
|
lda #>BLOCKBUF+$04 ; ... MERLIN32: removed()
|
||||||
|
sta FENTPTRH ; ...
|
||||||
|
lda #$01 ; and set current entry
|
||||||
|
sta CURENT ; to 1
|
||||||
|
:Okay clc
|
||||||
|
rts
|
||||||
|
:Fail sec
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; read volume directory block at ($07)
|
||||||
|
; and update to point to next block
|
||||||
|
; returns carry clear if no error, set otherwise
|
||||||
|
ReadVolDir
|
||||||
|
; most recent accessed device into param list for READ_BLOCK
|
||||||
|
lda $BF30 ; most recent access device
|
||||||
|
sta :PL_READ_BLOCK+1 ; into READ_BLOCK parameter list
|
||||||
|
; copy block number to param list
|
||||||
|
lda DIRBLKL ; copy block number
|
||||||
|
sta :PL_READ_BLOCK+4 ; to parameter list
|
||||||
|
lda DIRBLKH ; ...
|
||||||
|
sta :PL_READ_BLOCK+5 ; ...
|
||||||
|
jsr PRODOS ; now get the block
|
||||||
|
DB PRODOS_READ_BLOCK ; READ_BLOCK
|
||||||
|
DW :PL_READ_BLOCK
|
||||||
|
bcs :Done ; error, bail out
|
||||||
|
lda BLOCKBUF+$02 ; otherwise get next block number
|
||||||
|
sta DIRBLKL ; from offset $02/$03
|
||||||
|
lda BLOCKBUF+$03 ; and save it
|
||||||
|
sta DIRBLKH ; ...
|
||||||
|
:Done rts
|
||||||
|
; Parameter list for READ_BLOCK
|
||||||
|
:PL_READ_BLOCK
|
||||||
|
DB $03 ; param count
|
||||||
|
DB $00 ; unit number
|
||||||
|
DW BLOCKBUF ; data buffer
|
||||||
|
DW $0000 ; block number
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; enable slinky registers, set adddress and save byte we intend to trash
|
||||||
|
SlinkyEnable
|
||||||
|
lda C8OFF ; not needed on //c, but release $C8xx firmware
|
||||||
|
lda SLOT4ROM ; enable slinky registers
|
||||||
|
lda #$08 ; set addr $080000
|
||||||
|
sta DPTRH
|
||||||
|
stz DPTRM
|
||||||
|
stz DPTRL
|
||||||
|
lda DATA ; read data byte
|
||||||
|
sta SAVEBYTE ; save it to restore later
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Routine to restore trashed byte in slinky RAM
|
||||||
|
; WARNING: never called by unfixed, so the value is never restored
|
||||||
|
SlinkyRestore
|
||||||
|
lda #$08 ; set adddr $080000
|
||||||
|
sta DPTRH
|
||||||
|
stz DPTRM
|
||||||
|
stz DPTRL
|
||||||
|
lda SAVEBYTE ; get saved byte
|
||||||
|
sta DATA ; and put it back
|
||||||
|
lda C8OFF ; not needed on //c, but release $C8xx firmware
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Write 8 bits to clock
|
||||||
|
; WARNING: the unfixed code has a bug that trashes 8 bytes in the RAM card at $080000
|
||||||
|
ClockWrite8b
|
||||||
|
ldx #$08 ; set adddr $080000
|
||||||
|
IF FIX_BUGS
|
||||||
|
stx DPTRH
|
||||||
|
stz DPTRM
|
||||||
|
:_1 stz DPTRL ; restore low byte to 0
|
||||||
|
sta DATA ; write byte
|
||||||
|
lsr a ; next bit into 0 position
|
||||||
|
dex
|
||||||
|
bne :_1 ; MERLIN32: uniq label
|
||||||
|
ELSE
|
||||||
|
stz DPTRL
|
||||||
|
stz DPTRM
|
||||||
|
stx DPTRH
|
||||||
|
:_2 sta DATA ; write byte
|
||||||
|
lsr a ; next bit into 0 position
|
||||||
|
dex
|
||||||
|
bne :_2 ; MERLIN32: uniq label
|
||||||
|
FIN
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; unlock the clock by writing the magic bit sequence
|
||||||
|
ClockUnlock
|
||||||
|
ldy #$08
|
||||||
|
:_ lda unlock,y
|
||||||
|
jsr ClockWrite8b ; write 8 bits
|
||||||
|
dey
|
||||||
|
bne :_
|
||||||
|
rts
|
||||||
|
unlock = * - 1
|
||||||
|
DB $5c, $a3, $3a, $c5, $5c, $a3, $3a, $c5
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Read 8 bits from the clock
|
||||||
|
ClockRead8b
|
||||||
|
ldx #$08 ; set adddr $080000
|
||||||
|
stz DPTRL
|
||||||
|
stz DPTRM
|
||||||
|
stx DPTRH
|
||||||
|
:_ pha ; save accumulator
|
||||||
|
lda DATA ; get data byte
|
||||||
|
lsr a ; bit 0 into carry
|
||||||
|
pla ; restore accumulator
|
||||||
|
ror a ; put read bit into position
|
||||||
|
dex
|
||||||
|
bne :_
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; read the clock data into memory at CLOCKBUF
|
||||||
|
; WARNING: unfixed code never restores byte we trashed
|
||||||
|
ClockRead
|
||||||
|
jsr SlinkyEnable
|
||||||
|
jsr ClockUnlock
|
||||||
|
ldy #$00
|
||||||
|
:_ jsr ClockRead8b
|
||||||
|
sta CLOCKBUF,y
|
||||||
|
iny
|
||||||
|
cpy #$08 ; have we read 8 bytes?
|
||||||
|
bcc :_ ; nope
|
||||||
|
IF FIX_BUGS
|
||||||
|
jsr SlinkyRestore
|
||||||
|
FIN
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; validate the DClock data makes sense
|
||||||
|
; return carry clear if it does, carry set if it does not
|
||||||
|
ValidTime
|
||||||
|
; validate ms
|
||||||
|
ldx #$00
|
||||||
|
ldy #$99
|
||||||
|
lda CLOCKBUF
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
; validate seconds
|
||||||
|
ldx #$00
|
||||||
|
ldy #$59
|
||||||
|
lda CLOCKBUF+$01
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
; validate minutes
|
||||||
|
ldx #$00
|
||||||
|
ldy #$59
|
||||||
|
lda CLOCKBUF+$02
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
; validate hours
|
||||||
|
ldx #$00
|
||||||
|
ldy #$23
|
||||||
|
lda CLOCKBUF+$03
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
; validate day of week
|
||||||
|
ldx #$01
|
||||||
|
ldy #$07
|
||||||
|
lda CLOCKBUF+$04
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
; validate day of month
|
||||||
|
ldx #$01
|
||||||
|
ldy #$31
|
||||||
|
lda CLOCKBUF+$05
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
; validate month
|
||||||
|
ldx #$01
|
||||||
|
ldy #$12
|
||||||
|
lda CLOCKBUF+$06
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
; validate year
|
||||||
|
ldx #$00
|
||||||
|
ldy #$99
|
||||||
|
lda CLOCKBUF+$07
|
||||||
|
jsr CheckBCD
|
||||||
|
bcs :bad
|
||||||
|
clc ; all good
|
||||||
|
rts
|
||||||
|
:bad sec ; problem
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Check BCD number in range of [x,y]
|
||||||
|
; return carry clear if it is, carry set if it is not
|
||||||
|
CheckBCD
|
||||||
|
sed ; decimal mode
|
||||||
|
stx SCRATCH ; lower bound into scratch
|
||||||
|
cmp SCRATCH ; compare it
|
||||||
|
bcc :bad ; fail if out of range
|
||||||
|
sty SCRATCH ; upper bound into scratch
|
||||||
|
cmp SCRATCH ; compare it
|
||||||
|
beq :good ; OK if equal
|
||||||
|
bcs :bad ; fail if out of range
|
||||||
|
:good cld ; in range
|
||||||
|
clc
|
||||||
|
rts
|
||||||
|
:bad cld ; not in range
|
||||||
|
sec
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; This code segment is relocated to RELOCT at the start of program
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
RELOCS = * - 1
|
||||||
|
rseg1bm = *
|
||||||
|
ORG RELOCT
|
||||||
|
rseg1b = *
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; This routine attempts to execute the next system file that we identified
|
||||||
|
; in the main code
|
||||||
|
LaunchNext
|
||||||
|
jsr PRODOS
|
||||||
|
DB PRODOS_OPEN ; OPEN
|
||||||
|
DW :PL_OPEN
|
||||||
|
bcs :LaunchFail ; if error
|
||||||
|
lda :PL_OPEN+5 ; copy reference number
|
||||||
|
sta :PL_GET_EOF+1 ; to parm list for GET_EOF
|
||||||
|
sta :PL_READ+1 ; and parm list for READ
|
||||||
|
sta :PL_CLOSE+1 ; and parm list for CLOSE
|
||||||
|
jsr PRODOS
|
||||||
|
DB PRODOS_GET_EOF ; GET_EOF
|
||||||
|
DW :PL_GET_EOF
|
||||||
|
bcs :LaunchFail ; if error
|
||||||
|
lda :PL_GET_EOF+4 ; high byte of length
|
||||||
|
bne :LaunchFail ; bigger than 64K... sheesh
|
||||||
|
lda :PL_GET_EOF+2 ; copy EOF middle and low
|
||||||
|
sta :PL_READ+4 ; to read reqest count
|
||||||
|
lda :PL_GET_EOF+3 ; ...
|
||||||
|
sta :PL_READ+5 ; ...
|
||||||
|
jsr PRODOS ; and do read
|
||||||
|
DB PRODOS_READ ; READ
|
||||||
|
DW :PL_READ
|
||||||
|
bcs :LaunchFail ; if error
|
||||||
|
jsr PRODOS
|
||||||
|
DB PRODOS_CLOSE ; CLOSE
|
||||||
|
DW :PL_CLOSE
|
||||||
|
bcs :LaunchFail ; if error
|
||||||
|
jmp SYSEXEC ; execute system file
|
||||||
|
:LaunchFail
|
||||||
|
pha ; save accumulator
|
||||||
|
jsr iprint ; because this trashes it
|
||||||
|
STR 'Can',27,'t start next SYS file: error #' ; MERLIN32: removed length $22
|
||||||
|
pla ; restore accumulator
|
||||||
|
jsr PrHex ; print error code
|
||||||
|
lda #$8D
|
||||||
|
jsr COUT1
|
||||||
|
jmp DoQuit ; quit to ProDOS
|
||||||
|
; parameter list for OPEN
|
||||||
|
:PL_OPEN
|
||||||
|
DB $03 ; param count
|
||||||
|
DW PATHBUF ; pathname address
|
||||||
|
DW READBUF ; I/O buffer
|
||||||
|
DB $00 ; reference number
|
||||||
|
; parameter list for GET_EOF
|
||||||
|
:PL_GET_EOF
|
||||||
|
DB $02 ; param count
|
||||||
|
DB $00 ; ref number
|
||||||
|
DB $00,$00,$00 ; EOF
|
||||||
|
; parameter list for READ
|
||||||
|
:PL_READ
|
||||||
|
DB $04 ; param count
|
||||||
|
DB $00 ; ref number
|
||||||
|
DW SYSEXEC ; data buffer
|
||||||
|
DW $0000 ; request count
|
||||||
|
DW $0000 ; transfer count
|
||||||
|
; parameter list for CLOSE
|
||||||
|
:PL_CLOSE
|
||||||
|
DB $01 ; param count
|
||||||
|
DB $00 ; ref number
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Routine to print hex number via LUT
|
||||||
|
; the firmware has a perfectly good routine for this, not sure why
|
||||||
|
; AE engineers put this in here. Nice wheel, though.
|
||||||
|
PrHex
|
||||||
|
pha
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
tax
|
||||||
|
lda :_,x
|
||||||
|
jsr COUT1
|
||||||
|
pla
|
||||||
|
and #$0F
|
||||||
|
tax
|
||||||
|
lda :_,x
|
||||||
|
jsr COUT1
|
||||||
|
rts
|
||||||
|
:_ ASC '0123456789ABCDEF'
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; Execute QUIT call after long delay, exit via RTS if QUIT fails
|
||||||
|
DoQuit
|
||||||
|
ldx #$0C
|
||||||
|
:_ lda #$FF
|
||||||
|
jsr WAIT
|
||||||
|
dex
|
||||||
|
bne :_
|
||||||
|
jsr PRODOS
|
||||||
|
DB PRODOS_QUIT
|
||||||
|
DW :PL_QUIT
|
||||||
|
rts
|
||||||
|
; parameter list for QUIT
|
||||||
|
:PL_QUIT
|
||||||
|
DB $04 ; param count
|
||||||
|
DB $00 ; quit type - $00 is only type
|
||||||
|
DW $0000 ; reserved
|
||||||
|
DB $00 ; reserved
|
||||||
|
DW $0000 ; reserved
|
||||||
|
; unnecessary fill?
|
||||||
|
brk
|
||||||
|
brk
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; 'inline print'
|
||||||
|
; print counted string following JSR
|
||||||
|
iprint
|
||||||
|
; get pointer into $09/$0a
|
||||||
|
pla
|
||||||
|
clc
|
||||||
|
adc #$01
|
||||||
|
sta CHRPTRL
|
||||||
|
pla
|
||||||
|
adc #$00
|
||||||
|
sta CHRPTRH
|
||||||
|
lda (CHRPTR)
|
||||||
|
beq :done
|
||||||
|
; now print the string
|
||||||
|
tay
|
||||||
|
ldy #$01
|
||||||
|
:ploop lda (CHRPTR),y
|
||||||
|
ora #$80
|
||||||
|
jsr COUT1
|
||||||
|
tya
|
||||||
|
iny
|
||||||
|
cmp (CHRPTR)
|
||||||
|
bcc :ploop
|
||||||
|
; done, fix up stack and exit
|
||||||
|
:done clc
|
||||||
|
adc CHRPTRL
|
||||||
|
sta CHRPTRL
|
||||||
|
lda #$00
|
||||||
|
adc CHRPTRH
|
||||||
|
pha
|
||||||
|
lda CHRPTRL
|
||||||
|
pha
|
||||||
|
rts
|
||||||
|
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; end of relocated code
|
||||||
|
rseg1e = *
|
||||||
|
; fix up org address so we get a clean ref to rclkdrv
|
||||||
|
; ORG rseg1bm + (rseg1e - rseg1b + 1) ; MERLIN32: remove ()
|
||||||
|
ORG rseg1bm + rseg1e - rseg1b + 1 ; MERLIN32: remove ()
|
||||||
|
; ----------------------------------------------------------------------------
|
||||||
|
; clock driver code inserted into ProDOS at $D742 - this shouldn't be
|
||||||
|
; hard-coded but it is.
|
||||||
|
; critical bug: Corrupts byte in $08xx01 of the //c memory expansion card.
|
||||||
|
rclkdrv = *
|
||||||
|
ORG CLKCODE
|
||||||
|
clockdrv
|
||||||
|
begin = *
|
||||||
|
lda #$08 ; useless instruction
|
||||||
|
php
|
||||||
|
sei
|
||||||
|
lda SLOT4ROM ; activate slinky registers
|
||||||
|
; ($08 from above overwritten)
|
||||||
|
stz DPTRL ; set slinky address to $08xx00
|
||||||
|
ldy #$08 ; also counter for unlock bytes
|
||||||
|
sty DPTRH
|
||||||
|
lda DATA ; get destroyed byte
|
||||||
|
; (slinky now at $08xx01)
|
||||||
|
pha ; save value on stack
|
||||||
|
; unlock dclock registers
|
||||||
|
:ubytlp lda regulk,y
|
||||||
|
ldx #$08 ; bit counter
|
||||||
|
:ubitlp ; MERLIN32: moved outside conditional
|
||||||
|
IF FIX_BUGS
|
||||||
|
stz DPTRL ; reset pointer to $08xx00
|
||||||
|
sta DATA ; write to $08xx00
|
||||||
|
ELSE
|
||||||
|
sta DATA ; write to $08xx00
|
||||||
|
; (!but not on first iteration!)
|
||||||
|
stz DPTRL ; reset pointer to $08xx00
|
||||||
|
FIN
|
||||||
|
lsr a ; next bit into 0 position
|
||||||
|
dex
|
||||||
|
bne :ubitlp
|
||||||
|
dey
|
||||||
|
bne :ubytlp
|
||||||
|
; now read 64 bits (8 bytes) from dclock
|
||||||
|
ldx #$08 ; byte counter
|
||||||
|
:rbytlp ldy #$08 ; bit counter
|
||||||
|
:rbitlp pha
|
||||||
|
lda DATA ; data byte
|
||||||
|
lsr a ; bit 0 into carry
|
||||||
|
pla
|
||||||
|
ror a ; carry into bit 7
|
||||||
|
dey
|
||||||
|
bne :rbitlp
|
||||||
|
; got 8 bits now, convert from BCD to binary
|
||||||
|
pha
|
||||||
|
and #$0F
|
||||||
|
sta BCDTMP
|
||||||
|
pla
|
||||||
|
and #$F0
|
||||||
|
lsr a
|
||||||
|
pha
|
||||||
|
adc BCDTMP
|
||||||
|
sta BCDTMP
|
||||||
|
pla
|
||||||
|
lsr a
|
||||||
|
lsr a
|
||||||
|
adc BCDTMP
|
||||||
|
; place in input buffer, which is OK because the ThunderClock driver does this
|
||||||
|
sta INBUF-1,x
|
||||||
|
dex
|
||||||
|
bne :rbytlp
|
||||||
|
; done copying, now put necessary values into ProDOS time locations
|
||||||
|
; copy hours to ProDOS hours
|
||||||
|
lda INBUF+4
|
||||||
|
sta TIMEHI
|
||||||
|
; copy minutes to ProDOS minutes
|
||||||
|
lda INBUF+5
|
||||||
|
sta TIMELO
|
||||||
|
; copy month ...
|
||||||
|
lda INBUF+1
|
||||||
|
lsr a
|
||||||
|
ror a
|
||||||
|
ror a
|
||||||
|
ror a
|
||||||
|
; ... and day of month to ProDOS month/day
|
||||||
|
ora INBUF+2
|
||||||
|
sta DATELO
|
||||||
|
; copy year and final bit of month to ProDOS year/month
|
||||||
|
lda INBUF
|
||||||
|
rol a
|
||||||
|
sta DATEHI
|
||||||
|
stz DPTRL ; set slinky back to $08xx00
|
||||||
|
pla ; get saved byte
|
||||||
|
sta DATA ; put it back
|
||||||
|
plp
|
||||||
|
rts
|
||||||
|
; DS1215 unlock sequence (in reverse)
|
||||||
|
regulk = * - 1
|
||||||
|
DB $5C, $A3, $3A, $C5, $5C, $A3, $3A, $C5
|
||||||
|
end = *
|
||||||
|
;.assert (begin - end + 1) < CLKCODEMAX, error, "DCLOCK driver too big"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user