From f0abdcc7382e304a83748867ba2ff2e780e0fad5 Mon Sep 17 00:00:00 2001 From: Ivan Izaguirre Date: Mon, 14 Nov 2022 19:05:30 +0100 Subject: [PATCH] Driver for the Fujinet Clock --- Makefile | 2 +- fujinet/Makefile | 38 ++++++++ fujinet/README.md | 9 ++ fujinet/fn.clock.system.s | 187 ++++++++++++++++++++++++++++++++++++++ fujinet/smartport.inc | 111 ++++++++++++++++++++++ package.sh | 4 +- 6 files changed, 349 insertions(+), 2 deletions(-) create mode 100644 fujinet/Makefile create mode 100644 fujinet/README.md create mode 100644 fujinet/fn.clock.system.s create mode 100644 fujinet/smartport.inc diff --git a/Makefile b/Makefile index 1355857..631d326 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -targets := ns.clock cricket dclock romx selectors ram.drv util textcolors +targets := ns.clock cricket dclock romx fujinet selectors ram.drv util textcolors .PHONY: all $(targets) package diff --git a/fujinet/Makefile b/fujinet/Makefile new file mode 100644 index 0000000..d0d1fb3 --- /dev/null +++ b/fujinet/Makefile @@ -0,0 +1,38 @@ + +CAFLAGS = --target apple2enh --list-bytes 0 +LDFLAGS = --config apple2-asm.cfg + +OUTDIR = out + +HEADERS = $(wildcard *.inc) $(wildcard ../inc/*.inc) + +TARGETS = \ + $(OUTDIR)/fn.clock.system.SYS + +# For timestamps +MM = $(shell date "+%-m") +DD = $(shell date "+%-d") +YY = $(shell date "+%-y") +DEFINES = -D DD=$(DD) -D MM=$(MM) -D YY=$(YY) + +XATTR := $(shell command -v xattr 2> /dev/null) + +.PHONY: clean all +all: $(OUTDIR) $(TARGETS) + +$(OUTDIR): + mkdir -p $(OUTDIR) + +clean: + rm -f $(OUTDIR)/*.o + rm -f $(OUTDIR)/*.list + rm -f $(TARGETS) + +$(OUTDIR)/%.o: %.s $(HEADERS) + ca65 $(CAFLAGS) $(DEFINES) --listing $(basename $@).list -o $@ $< + +$(OUTDIR)/%.BIN $(OUTDIR)/%.SYS: $(OUTDIR)/%.o + ld65 $(LDFLAGS) -o $@ $< +ifdef XATTR + xattr -wx prodos.AuxType '00 20' $@ +endif diff --git a/fujinet/README.md b/fujinet/README.md new file mode 100644 index 0000000..523c3f6 --- /dev/null +++ b/fujinet/README.md @@ -0,0 +1,9 @@ +# FujiNet ProDOS Clock Driver + +[FujiNet](https://fujinet.online/) for Apple II provides a number of devices via SmartPort. Alongside four block and a network device it has a real time clock device. + +This driver is an adaptation of the other drivers in https://github.com/a2stuff/prodos-drivers + + + + diff --git a/fujinet/fn.clock.system.s b/fujinet/fn.clock.system.s new file mode 100644 index 0000000..69a8b8e --- /dev/null +++ b/fujinet/fn.clock.system.s @@ -0,0 +1,187 @@ +;;; ProDOS driver for the Fujinet clock +;;; Adapted from: https://github.com/a2stuff/prodos-drivers/blob/main/cricket/cricket.system.s + + .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" + .include "../inc/ascii.inc" + +;;; ************************************************************ + .include "../inc/driver_preamble.inc" + .include "./smartport.inc" +;;; ************************************************************ + +FN_CLOCK_DEVICE_TYPE := $13 ; As defined on the Fujinet firmware + + +;;; ============================================================ +;;; +;;; Driver Installer +;;; +;;; ============================================================ + + .define PRODUCT "Fujinet Clock" + +;;; ============================================================ +;;; Ensure there is not a previous clock driver installed. + +.proc maybe_install_driver + + lda MACHID + and #$01 ; existing clock card? + beq detect_fujinet_clock ; nope, check for clock + + rts ; yes, done! +.endproc + +;;; ============================================================ +;;; Fujinet Clock Driver - copied into ProDOS +;;; ============================================================ + +.proc driver + scratch := $3A ; ZP scratch location + + ;; Initialize + php + sei + + ;; Execute smartport command + jsr $c50d ; To be changed to the detected slot and address +drv_call_hi = *-1 +drv_call_lo = *-2 + .byte DRIVER_COMMAND_STATUS ; Command Status +params_address: + .word params - driver ; To be changed on relocation + + ;; Restore state and return + sta $CFFF ; release C8xx ROM space + plp + rts + +params: .byte $03 ; Status param count +port: .byte $00 ; Smartport device + .word DATELO ; Write directly on the four bytes reserved by Prodos for date and time + .byte 'P' ; Get datetime in ProDDOS format + +.endproc + sizeof_driver := .sizeof(driver) + .assert sizeof_driver <= 125, error, "Clock code must be <= 125 bytes" + + +;;; ------------------------------------------------------------ +;;; Detect Fujinet Clock. + +.proc detect_fujinet_clock + + ;; Serch for smartport cards + ldx #$C7 ; Start the search from slot 7 +search_slot: + jsr find_smartport + bcs not_found + + ;; Find a Fujinet Clock device on this slot + jsr setup_smartport + jsr device_count + cpx #$0 + beq continue_slot_search; no devices in the slot + +search_unit: + jsr unit_type + cmp #FN_CLOCK_DEVICE_TYPE + beq found + dex + bne search_unit +continue_slot_search: + ldx sp_call+1 ; restore card + dex + cpx #$C0 + bne search_slot + jmp not_found +found: + ; Modify the driver code with the detected data + stx driver::port + lda sp_call_lo + sta driver::drv_call_lo + lda sp_call_hi + sta driver::drv_call_hi + + jmp install_driver + +not_found: + ;; Show failure message + jsr log_message + scrcode PRODUCT, " - Not Found." + .byte 0 + rts + +.endproc + +;;; ------------------------------------------------------------ +;;; Install 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 + + ;; Find driver destination + lda DATETIME+1 + sta ptr + lda DATETIME+2 + sta ptr+1 + + ;; Fix pointers + clc + lda ptr + adc driver::params_address + sta driver::params_address + lda ptr+1 + adc driver::params_address+1 + sta driver::params_address+1 + + ;; Copy code + 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 + + ;; Display success message + jsr log_message + scrcode PRODUCT, " - " + .byte 0 + + ;; Display the current date + jsr cout_date + + rts ; done! +.endproc + + +;;; ************************************************************ + .include "../inc/driver_postamble.inc" +;;; ************************************************************ diff --git a/fujinet/smartport.inc b/fujinet/smartport.inc new file mode 100644 index 0000000..f55c197 --- /dev/null +++ b/fujinet/smartport.inc @@ -0,0 +1,111 @@ +;;; ------------------------------------------------------------ +;;; Smartport access functions +;;; Derived from: http://mirrors.apple2.org.za/ground.icaen.uiowa.edu/MiscInfo/Programming/smartport.statusexample + +;;This function scans the slots to locate a SmartPort. +;;On entry, X=$Cx, where x is the first slot to be checked. +;;On exit, X=$Cy, where y is the highest numbered slot less than or +;;equal to x which contains SmartPort firmware. If no SmartPort +;;is found, C=1 and A=$00. +ptr := $A5 ; Generic pointer + +.proc find_smartport + LDA #$00 + STA ptr ; Set up the pointer +try_slot: + STX ptr+1 + LDY #$01 + LDA (ptr),Y ; Check the first ID byte + CMP #$20 + BNE not_here + LDY #$03 + LDA (ptr),Y ; and the second one + CMP #$00 + BNE not_here + LDY #$05 + LDA (ptr),Y ; and the third one + CMP #$03 + BNE not_here + LDY #$07 + LDA (ptr),Y ; and the fourth one + CMP #$00 + BNE not_here + LDX ptr+1 ; Match! Get the address back + CLC + RTS +not_here: + LDX ptr+1 ; Mismatch + DEX ; Go down one slot + CPX #$C1 + BCS try_slot ; Stop once we have gone past slot 1 + LDX #$00 + SEC ; Error - no SmartPort found + RTS +.endproc + +;; This function sets up the SP_CALL function for calling the +;; SmartPort driver. On entry, X=$Cx, where x is the slot number +;; containing a SmartPort driver. This should be checked via +;; FIND_SMARTPORT if necessary - don't assume there is a SmartPort +;; device in slot 5, for example! +.proc setup_smartport + LDA #$00 + STA ptr ; Set up the pointer + STX ptr+1 + LDY #$FF + LDA (ptr),Y ; Get the ProDOS driver entry point + CLC + ADC #$03 ; Get the SmartPort driver entry point + STA sp_call_lo ; Store in the JSR + STX sp_call_hi ; also store the high byte + RTS +.endproc + +;; This function return in X the number of devices available +;; on a SmartPort +.proc device_count + LDA #$00 + STA st_unit + STA st_code + JSR sp_call + BCS device_count_error + LDX st_list+0 + RTS +device_count_error: + LDX #$00 + RTS +.endproc + +;; This function returns in A the device type for a unit in X +.proc unit_type + STX st_unit + LDA #$03 + STA st_code + JSR sp_call + BCS unit_type_error + LDA st_list+21 + LDX st_unit + RTS +unit_type_error: + LDA #$ff + LDX st_unit + RTS +.endproc + + + +;; Status command parameters +sp_call: JSR $0000 +sp_call_hi = *-1 +sp_call_lo = *-2 + .byte DRIVER_COMMAND_STATUS ; Command Status +params_address: + .word st_params + RTS + +st_params: + .byte $3 ; Parameter count +st_unit:.byte $0 + .word st_list +st_code:.byte $0 +st_list:.byte 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24 diff --git a/package.sh b/package.sh index 005b68d..e9de3a1 100755 --- a/package.sh +++ b/package.sh @@ -4,13 +4,14 @@ # https://github.com/mach-kernel/cadius set -e +set -x PACKDIR=$(mktemp -d) IMGFILE="prodos-drivers.po" VOLNAME="drivers" rm -f "$IMGFILE" -cadius CREATEVOLUME "$IMGFILE" "$VOLNAME" 140KB --no-case-bits --quiet +cadius CREATEVOLUME "$IMGFILE" "$VOLNAME" 800KB --no-case-bits --quiet cadius CREATEFOLDER "$IMGFILE" "/$VOLNAME/CRICKET.UTIL" --no-case-bits --quiet add_file () { @@ -25,6 +26,7 @@ add_file "cricket/out/test.BIN" "test#062000" "/$VOLNAME 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 "romx/out/romxrtc.system.SYS" "romxrtc.system#FF0000" "/$VOLNAME" +add_file "fujinet/out/fn.clock.system.SYS" "fn.clock.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"