mirror of
https://github.com/a2stuff/prodos-drivers.git
synced 2024-06-09 18:29:30 +00:00
f2ea11fcde
This one driver pulls in the installers for each other clock driver, and invokes each in turn: * No-Slot Clock * ROMX * FujiNet * DClock * Cricket! This requires adding `.ifndef JUMBO` guards in the other drivers for when they pull in include files (symbols, macros, etc). The other drivers are adjusted to return with carry clear on successful install, failure otherwise.
406 lines
14 KiB
ArmAsm
406 lines
14 KiB
ArmAsm
; Fully disassembled and analyzed source to AE
|
|
; DCLOCK.SYSTEM by M.G. - 04/18/2017
|
|
; https://gist.github.com/mgcaret/7f0d7aeec169e90809c7cfaab9bf183b
|
|
; Further modified by @inexorabletash - 12/21/2020
|
|
|
|
; 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, [M.G.] totally missed this.
|
|
; This version of the code has fixes permanently applied.
|
|
|
|
.ifndef JUMBO_CLOCK_DRIVER
|
|
.setcpu "6502" ; changed below
|
|
.linecont +
|
|
.feature string_escapes
|
|
|
|
.include "apple2.inc"
|
|
.include "apple2.mac"
|
|
.include "opcodes.inc"
|
|
|
|
.include "../../inc/apple2.inc"
|
|
.include "../../inc/macros.inc"
|
|
.include "../../inc/prodos.inc"
|
|
.endif ; JUMBO_CLOCK_DRIVER
|
|
|
|
; zero page locations
|
|
SCRATCH := $0B ; scratch value for BCD range checks
|
|
SAVEBYTE := $0C ; slinky overwritten byte save location
|
|
BCDTMP := $3A ; location clock driver uses for BCD->Binary
|
|
|
|
; buffers & other spaces
|
|
INBUF := $0200 ; input buffer
|
|
CLOCKBUF := $0300 ; clock buffer
|
|
|
|
; I/O and hardware
|
|
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
|
|
|
|
;;; ************************************************************
|
|
.ifndef JUMBO_CLOCK_DRIVER
|
|
.include "../../inc/driver_preamble.inc"
|
|
.endif ; JUMBO_CLOCK_DRIVER
|
|
;;; ************************************************************
|
|
|
|
;;; ============================================================
|
|
;;;
|
|
;;; Driver Installer
|
|
;;;
|
|
;;; ============================================================
|
|
|
|
.ifndef JUMBO_CLOCK_DRIVER
|
|
.define PRODUCT "DClock"
|
|
.endif ; JUMBO_CLOCK_DRIVER
|
|
|
|
;;; ============================================================
|
|
;;; Ensure there is not a previous clock driver installed.
|
|
;;; And that this is a IIc. And that the clock is present.
|
|
;;; NOTE: Safe to run on a non-IIc (6502 opcodes, etc)
|
|
|
|
.proc maybe_install_driver
|
|
lda MACHID
|
|
and #$01 ; existing clock card?
|
|
bne done
|
|
|
|
lda VERSION ; IIc identification byte 1
|
|
cmp #$06
|
|
bne done
|
|
lda ZIDBYTE ; IIc identification byte 2
|
|
cmp #$00
|
|
bne done
|
|
|
|
;;; Since this is a IIc, okay to rely on 65C02 opcodes from here.
|
|
.pushcpu
|
|
.setcpu "65C02"
|
|
|
|
jsr ClockRead
|
|
jsr ValidTime
|
|
bcc InstallDriver
|
|
|
|
.ifndef JUMBO_CLOCK_DRIVER
|
|
;; Show failure message
|
|
jsr log_message
|
|
scrcode PRODUCT, " - Not Found."
|
|
.byte 0
|
|
.endif ; JUMBO_CLOCK_DRIVER
|
|
|
|
done: sec ; failure
|
|
rts
|
|
.endproc
|
|
|
|
; ----------------------------------------------------------------------------
|
|
; Install clock driver
|
|
.proc InstallDriver
|
|
|
|
;; Copy into address at DATETIME vector, update the vector and
|
|
;; update MACHID bits to signal a clock is present.
|
|
ptr := $A5
|
|
|
|
;; Update absolute addresses within driver
|
|
lda DATETIME+1
|
|
sta ptr
|
|
clc
|
|
adc #(regulk - driver)
|
|
sta regulk_addr
|
|
lda DATETIME+2
|
|
sta ptr+1
|
|
adc #0
|
|
sta regulk_addr+1
|
|
|
|
;; Copy driver into appropriate bank
|
|
lda RWRAM1
|
|
lda RWRAM1
|
|
ldy #sizeof_driver-1
|
|
|
|
loop: lda driver,y
|
|
sta (ptr),y
|
|
dey
|
|
bpl loop
|
|
|
|
;; Set the "Recognizable Clock Card" bit
|
|
lda MACHID
|
|
ora #$01
|
|
sta MACHID
|
|
|
|
lda #OPC_JMP_abs
|
|
sta DATETIME
|
|
|
|
;; Invoke the driver to init the time
|
|
jsr DATETIME
|
|
|
|
lda ROMIN2
|
|
|
|
.ifndef JUMBO_CLOCK_DRIVER
|
|
;; Display success message
|
|
jsr log_message
|
|
scrcode PRODUCT, " - "
|
|
.byte 0
|
|
|
|
;; Display the current date
|
|
jsr cout_date
|
|
.endif ; JUMBO_CLOCK_DRIVER
|
|
|
|
clc ; success
|
|
rts ; done!
|
|
.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
|
|
.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
|
|
.proc ClockWrite8b
|
|
ldx #$08 ; set adddr $080000
|
|
stx DPTRH
|
|
stz DPTRM
|
|
: stz DPTRL ; restore low byte to 0
|
|
sta DATA ; write byte
|
|
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
|
|
jsr SlinkyRestore
|
|
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
|
|
|
|
; ----------------------------------------------------------------------------
|
|
; clock driver code inserted into ProDOS
|
|
|
|
driver:
|
|
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
|
|
regulk_addr := *+1
|
|
ubytlp: lda regulk,y ; self-modified
|
|
ldx #$08 ; bit counter
|
|
ubitlp: stz DPTRL ; reset pointer to $08xx00
|
|
sta DATA ; write to $08xx00
|
|
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
|
|
|
|
sizeof_driver := * - driver
|
|
.assert sizeof_driver <= 125, error, "Clock code must be <= 125 bytes"
|
|
|
|
.popcpu
|
|
|
|
;;; ************************************************************
|
|
.ifndef JUMBO_CLOCK_DRIVER
|
|
.include "../../inc/driver_postamble.inc"
|
|
.endif ; JUMBO_CLOCK_DRIVER
|
|
;;; ************************************************************
|