From 992d77de93431cea15a15453f440a56cf6766353 Mon Sep 17 00:00:00 2001
From: Oliver Schmidt
Date: Fri, 26 Jan 2018 22:04:39 +0100
Subject: [PATCH] Current xHD client for IIgs.
The code uses the SCC Z8530 found in the IIgs. It runs from bank $E0.
Supposed to be assembled with https://www.brutaldeluxe.fr/products/crossdevtools/merlin/
---
client/z8530/xHD.s | 655 +++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 655 insertions(+)
create mode 100644 client/z8530/xHD.s
diff --git a/client/z8530/xHD.s b/client/z8530/xHD.s
new file mode 100644
index 0000000..0880364
--- /dev/null
+++ b/client/z8530/xHD.s
@@ -0,0 +1,655 @@
+*=================================================
+* xHD serial driver
+* By John Brooks 10/28/2015
+* Virtual disk drive based on ideas from Terence J. Boldt
+*=================================================
+ lst off
+
+ typ bin
+ dsk xHD
+
+ZpPageNum = $3a
+ZpChecksum = $3b
+ZpReadEnd = $3c
+ZpTemp = $3e
+
+ZpDrvrCmd = $42
+ZpDrvrUnit = $43
+ZpDrvrBufPtr = $44
+ZpDrvrBlk = $46
+
+P8ErrIoErr = $27
+
+TxtLight = $e00427
+
+
+P8CmdQuit = $65
+
+P8Mli = $BF00
+P8DevCnt = $BF31
+P8DevLst = $BF32
+
+IoSccCmdB = $C038
+IoSccCmdA = $C039
+IoSccDataB = $C03A
+IoSccDataA = $C03B
+
+IoRomIn = $C081
+IoLcBank2 = $C08B
+
+RomStrOut = $DB3A ;YA=C string
+
+*-------------------------------------------------
+
+ org $2000
+Start
+
+:MoveE0Driver
+ lda IoLcBank2
+ lda IoLcBank2
+
+ ; Copy E0Driver
+ clc
+ xce
+ rep #$30
+ ldx #E0DriverBin1-ToE0Driver+E0DriverBin2
+ ldy #E0Driver
+ lda #E0DriverEnd-E0Driver-1
+ mvn E0DriverBin1, E0Driver
+ ldx #E0DriverBin2
+ ldy #ToE0Driver
+ lda #E0DriverBin1-ToE0Driver-1
+ mvn E0DriverBin2, ToE0Driver
+ ;phk
+ ;plb
+
+ lda $BF10 ;Get 'null' E0Driver address
+ ldy #2
+:FindSlot cmp $BF10,y
+ bne :NotEmpty
+ cmp $BF20,y
+ beq :GotSlot
+:NotEmpty iny
+ iny
+ cpy #$10
+ bcc :FindSlot
+
+ ldy #2 ;All slots filled. Overwrite slot 1 devices
+:GotSlot
+ lda #ToE0Driver
+ sta $BF10,y
+ sta $BF20,y
+
+ phy
+
+ sep #$30
+ tya
+ ora #$10 ;Set Drive 2 (hi) bit
+ xba ;Save in high byte
+ tya ;Set Slot,Drive 1 in low byte
+ rep #$20
+ asl ;Shift *8 to finish slot*16
+ asl
+ asl
+
+ ldy P8DevCnt
+ sta P8DevLst+1,Y
+ iny
+ iny
+ sty P8DevCnt
+
+ sec
+ xce
+ mx %11
+
+ lda IoRomIn ; Disable LC
+
+ lda #StrSlot
+ ldy #>StrSlot
+ jsr RomStrOut
+ pla
+ lsr
+ jsr $FDE5
+Exit
+ tsc
+ cmp #$fc
+ bcc :GotBasic
+:Quit
+ jsr P8Mli ; $BF00
+ db P8CmdQuit
+ dw :QuitParms
+:QuitParms
+ db 4
+ ds 7
+:GotBasic
+ rts
+
+StrSlot
+ asc 'Modem xHD in Slot ',00
+*-------------------------------------------------
+E0DriverBin2
+ org $00d7a0
+ToE0Driver
+ ldx #0
+ clc
+ xce
+ jsl >E0Driver
+E0DriverReturn
+ xce
+ sec
+ xce
+ rts
+CmdHdr ;asc "E"
+CurCmd db 0
+HdrBlk dw 0
+HdrChecksum db 0
+HdrCopy ds 4-1
+;TempDate ds 4
+HdrCopyCksum dw 1
+
+
+*-------------------------------------------------
+E0DriverBin1
+ org $e0bd00
+
+E0Driver
+ jmp (GSCmd,x)
+GSCmd
+ dw xHdClient
+
+xHdClient
+ lda #2
+ bit ZpDrvrUnit
+ bpl :GotZpDrvrUnit
+ asl
+:GotZpDrvrUnit
+ sta CurCmd ;2=Drive1, 4=Drive2
+
+ lda #15 ;Are 8530 interrupts disabled?
+ sta IoSccCmdB
+ lda IoSccCmdB
+ beq :ConfigOK ;If not then SCC is set up by firmware, so reset it
+
+ bit $c030
+ ldx #-SccInitLen
+:InitSCC
+ ldal SccInitTblEnd-$100,x
+ sta IoSccCmdB
+ inx
+ bne :InitSCC
+
+:ConfigOK
+
+ do 0
+ phx
+ ldal $227fff
+ tax
+ lda ZpDrvrCmd
+ stal $228000,x
+ lda ZpDrvrBlk
+ stal $228100,x
+ lda ZpDrvrBlk+1
+ stal $228200,x
+ inx
+ txa
+ stal $227fff
+ plx
+ fin
+
+ lda ZpDrvrCmd
+ beq :DoStatus ;0=status
+ dec
+ beq ReadBlock ;1=read block
+ dec
+ bne :NoCmd ;2=write block
+ jmp WriteBlock
+:DoStatus
+ ldx #$ff ;TODO - returns 32MB HD regardless of image size
+ txy
+:NoCmd
+ lda #0 ; no error
+ clc
+ rtl
+
+;230k baud
+SccInitTbl
+ db 4, %01000100 ; 4: x16 clock, 1 stop, no parity
+ db 3, %11000000 ; 3: 8 data bits, auto enables off, Rx off
+ db 5, %01100010 ; 5: DTR on, 8 data bits, no break, Tx off, RTS off
+ db 11, %00000000 ;11: external clock
+ db 14, %00000000 ;14: no loopback
+ db 3, %11000001 ; 3: 8 data bits, Rx on
+ db 5, %01101010 ; 5: DTR on; Tx on
+ db 15, %00000000 ;15: no interrupts
+SccInitTblEnd
+SccInitLen = SccInitTblEnd-SccInitTbl
+
+*-------------------------------------------------
+ mx %11
+ReadBlock
+ rep #$10
+ xba ;ah=0
+ lda CurCmd
+ lsr
+ ora #$30
+ stal TxtLight
+ inc CurCmd ;3=drive1, 5=drive2
+ ldx ZpDrvrBlk
+ stx HdrBlk
+ jsr ClearRx
+ jsr SendCmd
+ stz ZpChecksum
+
+ do 1
+ ldy #HdrCopy
+ ldx #HdrCopy+5-1
+; ldx #HdrCopy+9
+ stx ZpReadEnd
+ jsr ReadBytes
+ bcc ReadError
+ lda ZpChecksum
+ bne ReadError
+
+ ldy #2
+:ErrChk lda CmdHdr,y
+ cmp HdrCopy,y
+ bne ReadError
+ dey
+ bpl :ErrChk
+
+ fin
+
+ do 0
+ jsr ReadOneByte
+ cmp #"E"
+ bne ReadError
+ jsr ReadOneByte
+ cmp CurCmd
+ bne ReadError
+ jsr ReadOneByte
+ cmp ZpDrvrBlk
+ bne ReadError
+ jsr ReadOneByte
+ cmp ZpDrvrBlk+1
+ bne ReadError
+ jsr ReadOneByte
+ sta TempDate
+ jsr ReadOneByte
+ sta TempDate+1
+ jsr ReadOneByte
+ sta TempDate+2
+ jsr ReadOneByte
+ sta TempDate+3
+ jsr ReadOneByte
+ lda ZpChecksum
+ bne ReadError
+
+ stz ZpChecksum
+ fin
+
+ rep #$21
+ ldy ZpDrvrBufPtr
+ tya
+ adc #$200
+ sta ZpReadEnd
+ lda #0
+ sep #$20
+ jsr ReadBytes
+ bcc ReadError
+
+ jsr ReadOneByte ;Read checksum
+ bcc ReadError ;Err if P8Timeout
+ lda ZpChecksum ;Chksum==0?
+ bne ReadError ;Err if bad chksum
+
+ tsb TxtLight
+ sep #$10
+ clc
+ rtl
+
+*-------------------------------------------------
+ mx %10
+ReadError
+ jsr ClearRx
+ lda #0
+ tsb TxtLight
+ sep #$10
+ lda #P8ErrIoErr
+ sec
+ rtl
+
+
+*-------------------------------------------------
+ mx %11
+WriteBlock
+ rep #$10
+ xba ;ah=0
+ lda #$17
+ stal TxtLight
+ ldx ZpDrvrBlk
+ stx HdrBlk
+ jsr ClearRx
+ jsr SendCmd
+ stz ZpChecksum
+
+ ldy ZpDrvrBufPtr
+ sty ZpReadEnd
+ inc ZpReadEnd+1
+ inc ZpReadEnd+1 ;Send 2x pages = 512 bytes
+ jsr WriteBytes
+
+ sta ZpPageNum ;Save block checksum
+
+ ldy #ZpChecksum
+ sty ZpReadEnd
+ jsr WriteBytes
+
+ do 1
+ ldy #HdrCopy
+ ldx #HdrCopy+5-1
+; ldx #HdrCopy+9
+ stx ZpReadEnd
+ jsr ReadBytes
+ bcc ReadError
+
+ cmp ZpPageNum ;block ZpChecksum
+ bne ReadError
+
+ ldy #2
+:ErrChk lda CmdHdr,y
+ cmp HdrCopy,y
+ bne ReadError
+ dey
+ bpl :ErrChk
+
+ fin
+
+ do 0
+; jsr ReadOneByte
+; bcc WriteError
+; cmp #"E"
+; bne WriteError
+ jsr ReadOneByte
+ bcc WriteError
+ cmp CurCmd ;Write
+ bne WriteError
+ jsr ReadOneByte ;Block low
+ bcc WriteError
+ cmp ZpDrvrBlk
+ bne WriteError
+ jsr ReadOneByte ;Block high
+ bcc WriteError
+ cmp ZpDrvrBlk+1
+ bne WriteError
+ lda ZpPageNum ;Restore block ZpChecksum
+ sta ZpChecksum
+ jsr ReadOneByte ;Block data checksum
+ bcc WriteError
+ lda ZpChecksum
+ bne WriteError
+ fin
+
+ tsb TxtLight
+
+ sep #$10
+ clc
+ rtl
+
+*-------------------------------------------------
+ mx %10
+WriteError
+ jsr ClearRx
+ lda #0
+ tsb TxtLight
+ sep #$10
+ lda #P8ErrIoErr
+ sec
+ rtl
+
+*-------------------------------------------------
+ mx %10
+SendCmd
+ inc $c034
+ stz ZpChecksum
+
+ ldy #CmdHdr
+ ldx #HdrChecksum
+ stx ZpReadEnd
+ jsr WriteBytes
+ sta HdrChecksum
+ dec $c034
+ ;Fall through to send checksum byte
+
+*-------------------------------------------------
+ mx %10
+WriteBytes
+ tsx ;Init timeout
+ clc
+:Loop
+ inx ;P8Timeout++
+ bmi :Exit
+ lda IoSccCmdB ;Reg 0
+ and #%00100100 ;Chk bit 5 (ready to send) & bit 2 (HW handshake)
+ eor #%00100100
+ bne :Loop
+
+ lda 0,y ;Get byte
+ sta IoSccDataB ;Tx byte
+
+ eor ZpChecksum
+ sta ZpChecksum ;Update cksum
+
+ iny
+ cpy ZpReadEnd
+ bcc WriteBytes
+
+ rts
+
+*-------------------------------------------------
+ mx %10
+ReadOneByte
+ ldy #$C07f
+ sty ZpReadEnd
+ ;fall through to ReadBytes
+
+*-------------------------------------------------
+ mx %10
+ReadBytes
+:ReadByte
+ tsx ;Init timeout
+:Loop
+ inx ;P8Timeout++
+ bmi :Exit
+ lda IoSccCmdB ;Chk reg 0 bit 0
+ lsr
+ bcc :Loop
+
+ lda IoSccDataB ;Byte received
+ sta 0,y ;Store it
+ tax ;Save in case this is a 1 byte read
+
+ eor ZpChecksum
+ sta ZpChecksum ;Update cksum
+
+ iny
+ cpy ZpReadEnd
+ bcc :ReadByte
+
+ txa ;Return last byte read
+:Exit rts
+
+*-------------------------------------------------
+ mx %10
+ClearRx
+
+:ClearFifo
+ lda #1
+ bit IoSccCmdB ;Chk reg 0 bit 0
+ beq :Done
+
+ sta IoSccCmdB ;Read reg 1
+ lda #$30 ;Chk & Clear overrun
+ bit IoSccCmdB ;Chk bit 5 for RX OVERRUN
+ beq :NotOverrun
+ sta IoSccCmdB
+ stz IoSccCmdB
+:NotOverrun
+ lda IoSccDataB ;Byte received
+ bra :ClearFifo
+:Done
+ rts
+
+E0DriverEnd
+
+*-------------------------------------------------
+ do 0
+ org $2ec
+ dsk SccBoot1
+
+sta_di mac ; sta (]1)
+ db $92,]1&$ff
+ eom
+
+ ;org $60
+ mx %11
+BootInitScc
+ ;pea #$0300
+ ;pld
+ jsr BootInitScc1
+ dec InitMOD+1 ;&$ff
+ stz SccDataMod ;&$ff
+BootInitScc1
+ ldx #BootstrapDataEnd-BootstrapData-1
+InitSccLoop
+ lda BootstrapData,x ;&$ff,x
+InitMOD
+ sta IoSccCmdA
+ dex
+ bpl InitSccLoop
+
+BootStrap
+ clc
+ xce
+ rep #$30
+ pea #$0300
+ pld
+:Respond
+:WaitSend
+ lda (pIoSccCmdB&$ff)
+ ora #$2020!$ffff
+ inc
+ bne :WaitSend
+
+ ;Send 'GS' packet header
+ lda PacketHdr&$ff
+ sta_di pIoSccDataB ;sta (pIoSccDataB&$ff)
+
+ ;Get 'GS' response from server
+ jsr BootGetWord
+ cmp PacketHdr&$ff
+ bne :WaitSend ;If server didn't respond, then echo packet header, then retry
+
+:ReadCmd
+ ;Read xfer word length (0=exit)
+ jsr BootGetWord
+ beq :Exit
+ tax ;word length
+
+ ;Read bank & page of xfer dest
+ jsr BootGetWord
+ sta pDest+1&$ff
+
+ ;Read byte offset of xfer dest
+ jsr BootGetWord
+ tay
+
+:ReadWord
+ jsr BootGetWord
+:DestMOD
+ sta [pDest&$ff],y
+ iny
+ iny
+ dex
+ bne :ReadWord
+ bra :Respond
+
+:Exit
+ ;Push last xfer bank/page on stack and jump to Adr+1
+ pei pDest+1&$ff
+ phk
+ rtl
+
+
+BootGetWord
+ phx
+ ldx #1000 ;P8Timeout duration
+:Loop
+ dex
+ bmi :P8Timeout
+ lda (pIoSccCmdB&$ff)
+ ora #$2121!$ffff
+ inc
+ bne :Loop
+:P8Timeout
+ plx
+ lda (pIoSccDataB&$ff)
+ sta_di pIoSccDataB ;sta (pIoSccDataB&$ff)
+
+ rts
+
+PacketHdr
+ dw 'GS'
+pIoSccCmdB
+ dw IoSccCmdB
+pIoSccDataB
+ dw IoSccDataB
+
+
+BootstrapData
+ ; Read last-to-first
+ ;db %00000000, 15 ;15: no interrupts
+ db %01101010, 5 ; 5: DTR enabled; Tx on
+ db %11000001, 3 ; 3: 8 data bits, Rx on
+ ;db %00000000, 14 ;14: no loopback
+pDest
+SccDataMod
+ db %10000000, 11 ;11: external clock
+ db %01100010, 5 ; 5: DTR on, 8 data bits, no break, Tx off, RTS off
+ db %11000000, 3 ; 3: 8 data bits, auto enables off, Rx off
+ db %01000100, 4 ; 4: x16 clock, 1 stop, no parity
+BootstrapDataEnd
+ fin
+*-------------------------------------------------
+
+ do 0
+ org $300
+Begin
+ pea #*&$ff00
+ pld
+ lda (:ptr&$ff)
+ lda (:ptr&$ff),y
+ lda [:ptr&$ff],y
+
+ ; lda works, why do these fail?
+ ;adc (:ptr&$ff)
+ ;and (:ptr&$ff)
+ ;cmp (:ptr&$ff)
+ ;eor (:ptr&$ff)
+ ;ora (:ptr&$ff)
+ ;sbc (:ptr&$ff)
+ ;sta (:ptr&$ff)
+:ptr
+ dw $2000
+
+KeyClr equ $e0c010
+ lda >KeyClr
+ lda |KeyClr
+ lda KeyClr
+ sta |KeyClr
+ sta