Add ROMX RTC driver, c/o Jeff Mazur.

This is a modified version of the ROMX Real-Time Clock driver. The changes include:

* Converting the source to ca65.

* Integrating with the driver installer framework.

* Adapting the driver to not modify page 2 beyond $220. The ROMX RTC
  firmware writes bytes to $2B0, and the the original driver placed
  temp code at $250. This can conflict with ProDOS applications that
  use page 2, so the driver was reworked to save/restore anything at
  at $2B0.

Other changes:

* Add a util/ source dir, and cricket/date, quit.system and
  pause.system there.

* Pull the "print current date" logic out of clock drivers into driver
  preamble.
This commit is contained in:
Joshua Bell 2021-10-05 19:58:31 -07:00
parent 7c8c608b65
commit b621ac6a4d
19 changed files with 397 additions and 122 deletions

View File

@ -1,4 +1,4 @@
targets := ns.clock cricket dclock selectors ram.drv quit pause
targets := ns.clock cricket dclock romx selectors ram.drv util
.PHONY: all $(targets) package

View File

@ -23,12 +23,13 @@ This repository collects several drivers and uses common code to chain to the ne
## What is present here?
This repo includes The following drivers/modifications:
This repo includes the following drivers/modifications:
* Real-time Clock drivers
* No-Slot Clock
* Cricket!
* Applied Engineering DClock
* ROMX Real-Time Clock
* RAM Disk drivers
* RAMWorks Driver by Glen E. Bredon
* Quit dispatcher/selector (`BYE` routines)
@ -41,14 +42,17 @@ In addition, `QUIT.SYSTEM` is present which isn't a driver but which immediately
There's also `PAUSE.SYSTEM` which just waits for a fraction of a second before invoking the next driver file. (Why? In case the log messages from the other installers goes by too fast!)
Some date/time utilities for The Cricker! clock are also included.
Non-drivers that are included:
* The `DATE` binary file can be `BRUN` (or just `-DATE`) to show the current ProDOS Date/Time, to verify that the clock driver is working.
* Some utilities for The Cricket! clock are also included.
## How do you use these?
The intent is that you use a tool like Copy II Plus or [Apple II DeskTop](https://github.com/a2stuff/a2d) to copy and arrange the SYSTEM files on your boot disk as you see fit. A boot disk image catalog that is used on multiple different hardware configurations might include:
* `PRODOS` - the operating system, e.g. [ProDOS 2.4](https://prodos8.com/)
* `NS.CLOCK.SYSTEM` - install No-Slot Clock driver, if present
* `NS.CLOCK.SYSTEM` - install No-Slot clock driver, if present
* `ROMXRTC.SYSTEM` - install ROMX clock driver, if present
* `DCLOCK.SYSTEM` - install DClock clock driver, if present
* `CRICKET.SYSTEM` - install Cricket! clock driver, if present
* `RAM.DRV.SYSTEM` - install RamWorks RAM disk driver, if present

View File

@ -10,7 +10,6 @@ TARGETS = \
$(OUTDIR)/prodos.mod.BIN \
$(OUTDIR)/cricket.system.SYS \
$(OUTDIR)/test.BIN \
$(OUTDIR)/date.BIN \
$(OUTDIR)/set.time.BIN \
$(OUTDIR)/set.date.BIN

View File

@ -37,7 +37,6 @@ I ended up disassembling both [NS.CLOCK.SYSTEM](../ns.clock/ns.clock.system.s) (
## Other Utilities
These `BRUN`able files are also built:
* [DATE](date.s) just prints the current ProDOS date/time, to verify the time is set and updating. It does not depend on having a Cricket.
* [TEST](test.s) attempts to identify an SSC in Slot 2 and the Cricket via the ID sequence, to test routines.
* [SET.DATE](set.date.s) sets the Cricket's current date.
* [SET.TIME](set.time.s) sets the Cricket's current time.

View File

@ -210,30 +210,7 @@ loop: lda driver,y
.byte 0
;; 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 cout_date
rts ; done!
.endproc

View File

@ -49,7 +49,7 @@ ssc_not_found:
rts
;; TODO: Write NUL and check for 'C' ... version ... $8D (CR)
;; https://github.com/inexorabletash/cricket/issues/3
;; https://github.com/a2stuff/cricket/issues/3
init_ssc:
lda COMMAND ; save status of SSC registers
sta saved_command

View File

@ -130,30 +130,7 @@ loop: lda driver,y
.byte 0
;; 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 cout_date
rts ; done!
.endproc

View File

@ -457,3 +457,35 @@ units: pla
jsr COUT
rts
.endproc
;;; ------------------------------------------------------------
;;; COUT the current ProDOS date
.proc cout_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
rts
.endproc

View File

@ -3,7 +3,7 @@
;;; http://www.apple2.org.za/gswv/a2zine/GS.WorldView/v1999/Oct/MISC/NSC.Disk.TXT
;;; Modification history available at:
;;; https://github.com/a2stuff/cricket
;;; https://github.com/a2stuff/prodos-drivers
.setcpu "6502"
.linecont +
@ -186,30 +186,7 @@ loop: lda driver,y
.byte 0
;; 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 cout_date
rts ; done!
.endproc

View File

@ -19,19 +19,20 @@ add_file () {
}
add_file "cricket/out/cricket.system.SYS" "cricket.system#FF0000" "/$VOLNAME"
add_file "cricket/out/date.BIN" "date#062000" "/$VOLNAME/CRICKET.UTIL"
add_file "cricket/out/set.date.BIN" "set.date#062000" "/$VOLNAME/CRICKET.UTIL"
add_file "cricket/out/set.time.BIN" "set.time#062000" "/$VOLNAME/CRICKET.UTIL"
add_file "cricket/out/test.BIN" "test#062000" "/$VOLNAME/CRICKET.UTIL"
add_file "dclock/out/dclock.system.SYS" "dclock.system#FF0000" "/$VOLNAME"
add_file "ns.clock/out/ns.clock.system.SYS" "ns.clock.system#FF0000" "/$VOLNAME"
add_file "quit/out/quit.system.SYS" "quit.system#FF0000" "/$VOLNAME"
add_file "pause/out/pause.system.SYS" "pause.system#FF0000" "/$VOLNAME"
add_file "romx/out/romxrtc.system.SYS" "romxrtc.system#FF0000" "/$VOLNAME"
add_file "ram.drv/out/ram.drv.system.SYS" "ram.drv.system#FF0000" "/$VOLNAME"
add_file "selectors/out/bbb.system.SYS" "bbb.system#FF0000" "/$VOLNAME"
add_file "selectors/out/buhbye.system.SYS" "buhbye.system#FF0000" "/$VOLNAME"
add_file "selectors/out/bye.system.SYS" "bye.system#FF0000" "/$VOLNAME"
add_file "selectors/out/selector.system.SYS" "selector.system#FF0000" "/$VOLNAME"
add_file "util/out/quit.system.SYS" "quit.system#FF0000" "/$VOLNAME"
add_file "util/out/pause.system.SYS" "pause.system#FF0000" "/$VOLNAME"
add_file "util/out/date.BIN" "date#062000" "/$VOLNAME"
rm -r "$PACKDIR"

View File

@ -1,4 +0,0 @@
## QUIT.SYSTEM
This just invokes the ProDOS quit handler immediately. It can be used as the last in a chain of "driver" installers to invoke the program selector (e.g. [Bitsy Bye](https://prodos8.com/bitsy-bye/), [Bird's Better Bye](../bbb), etc)

View File

@ -7,7 +7,7 @@ OUTDIR = out
HEADERS = $(wildcard *.inc) $(wildcard ../inc/*.inc)
TARGETS = \
$(OUTDIR)/pause.system.SYS
$(OUTDIR)/romxrtc.system.SYS
# For timestamps
MM = $(shell date "+%-m")

3
romx/README.md Normal file
View File

@ -0,0 +1,3 @@
# ROMX ProDOS Clock Driver
Original source c/o Jeff Mazur.

329
romx/romxrtc.system.s Normal file
View File

@ -0,0 +1,329 @@
;;; ROMX ProDOS RTC Driver
;;; Based on:
;;; * Ver 0.91
;;; * Ver 0.92 Added ZIP slowdowns - 11-Aug-2021 -
;;; Modifications by Joshua Bell inexorabletash@gmail.com
;;; * Converted to ca65 syntax and adapted to driver wrapper.
;;; * Driver core rewritten to ensure that $220 and up are saved/restored.
.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.
.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
;; Preserve date/time
ldy #3 ; copy 4 bytes
: lda DATELO,y
sta saved,y
dey
bpl :-
.ifndef FAKE_CLOCK
;; 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 not_found
lda SigCk+1
cmp #$CD
bne not_found
lda FWReadClock ; is RTC code there?
cmp #$AD
php
bit SEL_MBANK ; restore original bank
plp
bne not_found
.endif
jmp install_driver ; found clock!
not_found:
;; Restore date/time
ldy #3
: lda saved,y
sta DATELO,y
dey
bpl :-
;; Show failure message
jsr log_message
scrcode PRODUCT, " - Not Found."
.byte 0
rts
saved: .byte 0, 0, 0, 0
.endproc
;;; ------------------------------------------------------------
;;; 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
;;; ============================================================
;;; The first ~$20 bytes of $200 (input buffer) are safe to
;;; overwrite. They are also used by the built-in Thunderclock
;;; slot-clock driver in ProDOS ($200-$20C).
StubLoc := $0200 ; RAM stub for ROMX (<$20 bytes)
;;; 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
ClockDrv:
;; --------------------------------------------------
;; Enter driver
php
sei
;; --------------------------------------------------
;; Copy the stub to RAM, and preserve RTC_BUF
ldx #RamStubEnd-RamStub-1 ; copy stub to RAM
RELOC1 := *+1
: lda RamStub - ClockDrv,x ; self-modified during relocation
sta StubLoc,x
lda RTC_BUF,x ; save `RTC_BUF` too (way more than needed)
pha
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
bne :-
;; --------------------------------------------------
;; Exit driver
plp
rts
MaskTable:
.byte $7f, $3f, $07, $3f, $1f, $ff
;; .... min hour wkdy date mnth year (`RTC_BUF` bytes 1..6)
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"
ClockDrvEnd := *
ClockDrvSize = ClockDrvEnd - ClockDrv
.assert ClockDrvSize <= 125, error, \
.sprintf("Clock driver must be <= 125 bytes, was %d bytes", ClockDrvSize)
;;; ************************************************************
.include "../inc/driver_postamble.inc"
;;; ************************************************************

View File

@ -7,7 +7,9 @@ OUTDIR = out
HEADERS = $(wildcard *.inc) $(wildcard ../inc/*.inc)
TARGETS = \
$(OUTDIR)/quit.system.SYS
$(OUTDIR)/quit.system.SYS \
$(OUTDIR)/pause.system.SYS \
$(OUTDIR)/date.BIN
# For timestamps
MM = $(shell date "+%-m")
@ -31,7 +33,7 @@ clean:
$(OUTDIR)/%.o: %.s $(HEADERS)
ca65 $(CAFLAGS) $(DEFINES) --listing $(basename $@).list -o $@ $<
$(OUTDIR)/%.SYS: $(OUTDIR)/%.o
$(OUTDIR)/%.BIN $(OUTDIR)/%.SYS: $(OUTDIR)/%.o
ld65 $(LDFLAGS) -o $@ $<
ifdef XATTR
xattr -wx prodos.AuxType '00 20' $@

8
util/README.md Normal file
View File

@ -0,0 +1,8 @@
# Utilities
* [DATE](date.s)
* Prints the current ProDOS date/time, to verify the time is set and updating. Run from the BASIC prompt: `-DATE`
* [QUIT.SYSTEM](quit.system.s)
* This invokes the ProDOS quit handler immediately. It can be used as the last in a chain of "driver" installers to invoke the program selector, e.g. if you want to also keep `BASIC.SYSTEM` in your root directory but not launch it.
* [PAUSE.SYSTEM](pause.system.s)
* Waits for a fraction of a second before invoking the next driver file. Useful in case the log messages from the driver installers go by too quickly!

View File

@ -1,5 +1,4 @@
;;; Query ProDOS and print the current date/time
;;; (No dependency on Cricket clock)
;;; Output is: MM/DD/YY HH:MM
@ -15,41 +14,17 @@
start:
MLI_CALL GET_TIME, 0
;;; Standard format:
;;;
;;; 49041 ($BF91) 49040 ($BF90)
;;; DATEHI ($BF91) DATELO ($BF90)
;;; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;; DATE: | year | month | day |
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;;
;;; 49043 ($BF93) 49042 ($BF92)
;;; TIMEHI ($BF93) TIMELO ($BF92)
;;; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;; TIME: |0 0 0| hour | |0 0| minute |
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;;
;;; Extended format (ProDOS 2.5):
;;; https://groups.google.com/d/topic/comp.sys.apple2/6MwlJSKTmQc/discussion
;;;
;;; 49039 ($BF8F) 49038 ($BF8E)
;;; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;; xTIME: | xSeconds | xMilliseconds |
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;;
;;; 49041 ($BF91) 49040 ($BF90)
;;; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;; DATE: | year | month | day |
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;;
;;; 49043 ($BF93) 49042 ($BF92)
;;; 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;;; TIME: |xYear| hour | |0 0| minute |
;;; +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
;; Date
@ -76,8 +51,7 @@ start:
jsr COUT
pla ; year
;; TODO: Shift in xYear bits
jsr cout_number ; TODO: Support 16-bit numbers
jsr cout_number
lda #HI(' ')
jsr COUT
@ -100,9 +74,6 @@ start:
rts
pm_flag:
.byte 0
;;; ------------------------------------------------------------
.proc cout_number