;;; ROMX ProDOS RTC Driver ;;; Ver 0.91 ;;; Ver 0.92 Added ZIP slowdowns ;;; Ver 0.93 Moved StubLoc to $0110 ;;; Ver 0.94 Moved StubLoc to RTC_BUF + 7. Save/restore in stack ;;; Ver 0.95 Moved MaskTable to after Thunderclock reloc area ;;; ;;; Modifications by Joshua Bell inexorabletash@gmail.com ;;; * Converted to ca65 syntax and adapted to driver wrapper. .setcpu "6502" .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" ;;; Uncomment the following to "fake" a clock with a fixed date. ;;; Used for testing without a real ROMX around. ;;; FAKE_CLOCK = 1 ;;; ************************************************************ .include "../../inc/driver_preamble.inc" ;;; ************************************************************ ZipSlo := $C0E0 ; ZIP CHIP slowdown ;;; ROMX locations FWReadClock := $D8F0 ; Firmware clock driver routine SigCk := $DFFE ; ROMX sig bytes SEL_MBANK := $F851 ; Select Main bank reg ;;; ============================================================ ;;; ;;; Driver Installer ;;; ;;; ============================================================ .define PRODUCT "ROMX Clock" ;;; ============================================================ ;;; Ensure there is not a previous clock driver installed. .ifdef FAKE_CLOCK maybe_install_driver := install_driver .else .proc maybe_install_driver lda MACHID and #$01 ; existing clock card? beq detect_romx ; nope, check for ROMX rts ; yes, done! .endproc ;;; ------------------------------------------------------------ .proc detect_romx ;; Try to detect ROMX and RTC bit ROMIN2 ; enable ROM bit ZipSlo ; disable ZIP bit $FACA ; enable ROMXe, temp bank 0 bit $FACA bit $FAFE lda SigCk ; Check for ROMX signature bytes cmp #$4A bne nope lda SigCk+1 cmp #$CD bne nope lda FWReadClock ; is RTC code there? cmp #$AD bne nope clc ; found clock! bcc :+ nope: sec ; not found : bit SEL_MBANK ; restore original bank (unconditionally) bcc install_driver ; found clock! ;; Show failure message jsr log_message scrcode PRODUCT, " - Not Found." .byte 0 rts .endproc .endif ;;; ------------------------------------------------------------ ;;; Install ROMX RTC 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 ;; Update absolute addresses within driver lda DATETIME+1 sta ptr lda DATETIME+2 sta ptr+1 lda ptr clc adc RELOC1 sta RELOC1 lda ptr + 1 adc RELOC1 + 1 sta RELOC1 + 1 lda ptr clc adc RELOC2 sta RELOC2 lda ptr + 1 adc RELOC2 + 1 sta RELOC2 + 1 ;; Copy driver into appropriate bank lda RWRAM1 lda RWRAM1 ldy #ClockDrvSize-1 loop: lda ClockDrv,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 ;; Display success message jsr log_message scrcode PRODUCT, " - " .byte 0 ;; Display the current date jsr cout_date rts ; done! .endproc ;;; ============================================================ ;;; ROMX RTC driver - Relocated into ProDOS clock driver space ;;; ============================================================ ;;; ROMX Firmware writes RTC data into this fixed location. ;;; It risks conflicting with some applications (e.g. A2DeskTop), ;;; so the data is saved/restored around clock reads. RTC_BUF := $02B0 ; use keyboard buffer StubLoc := RTC_BUF+7 ; RAM stub for ROMX ClockDrv: ;; -------------------------------------------------- ;; Enter driver php sei ;; -------------------------------------------------- ;; Copy the stub to RAM, and preserve RTC_BUF ldx #RamStubEnd-RamStub+7 ; preserve and copy stub to RAM : lda RTC_BUF,x pha RELOC1 := *+1 lda RamStub-ClockDrv-7,x ; self-modified during relocation sta RTC_BUF,x dex bpl :- ;; -------------------------------------------------- ;; Read the clock into `RTC_BUF` jsr StubLoc ;; -------------------------------------------------- ;; Strip non-number bits, convert decimal to binary, push to stack ldy #6 bufloop: lda RTC_BUF,y RELOC2 := *+1 and MaskTable-1-ClockDrv,y ; self-modified during relocation ;; BCD to Binary ;; On entry, A=BCD value &00-&99 ;; On exit, A=binary value 0-99 ldx #$FF ; Start with result=-1 sec ; Prepare for subtraction sed ; Switch to Decimal arithmetic : inx ; Add 1 to result sbc #1 ; Subtract 1 with BCD arithmetic bcs :- ; Loop until BCD value < 0 cld ; Switch back to Binary arithmetic txa ; return in A ;; Push to stack pha dey bne bufloop ; 6..1 ;; -------------------------------------------------- ;; Pull and place values into ProDOS time locations ;; (`RTC_BUF`+0 is not pushed) pla ; `RTC_BUF`+1 = minute sta TIMELO pla ; `RTC_BUF`+2 = hour sta TIMEHI pla ; `RTC_BUF`+3 = weekday (unused) pla ; `RTC_BUF`+4 = day sta DATELO pla ; `RTC_BUF`+5 = month asl a asl a asl a asl a asl a ; MSB will merge into DATEHI ora DATELO ; merge with day sta DATELO pla ; `RTC_BUF`+6 = year sta DATEHI rol DATEHI ; merge with MSB from month ;; -------------------------------------------------- ;; Restore what was originally at `RTC_BUF` ldx #0 : pla sta RTC_BUF,x inx cpx #RamStubEnd-RamStub+7+1 bne :- ;; -------------------------------------------------- ;; Exit driver plp rts RamStub: .ifndef FAKE_CLOCK ;; Really read the ROMX RTC bit ROMIN2 ; enable ROM bit ZipSlo ; disable ZIP bit $FACA ; enable ROMXe, temp bank 0 bit $FACA bit $FAFE jsr FWReadClock ; Call ROMX to read clock bit SEL_MBANK ; restore original bank bit LCBANK1 ; restore LC w/write bit LCBANK1 .else ;; No ROMX RTC around? Provide fake data for testing. ;; October 5, 2021 12:34:56 lda #$56 ; sec sta RTC_BUF+0 lda #$34 ; min sta RTC_BUF+1 lda #$12 ; hr sta RTC_BUF+2 lda #$05 ; date sta RTC_BUF+4 lda #$10 ; month sta RTC_BUF+5 lda #$21 ; year sta RTC_BUF+6 .endif rts RamStubEnd := * .assert RamStubEnd - RamStub < $20, error, "Stub too long" MaskTable: .byte $7f, $3f, $07, $3f, $1f, $ff ;; .... min hour wkdy date mnth year (`RTC_BUF` bytes 1..6) ClockDrvEnd := * ClockDrvSize = ClockDrvEnd - ClockDrv .assert ClockDrvSize <= 125, error, \ .sprintf("Clock driver must be <= 125 bytes, was %d bytes", ClockDrvSize) ;;; ************************************************************ .include "../../inc/driver_postamble.inc" ;;; ************************************************************