mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-28 16:31:01 +00:00
4325cdcc78
Resource forks are included only for .rsrc files. These are DeRezzed into their data fork. 'ckid' resources, from the Projector VCS, are not included. The Tools directory, containing mostly junk, is also excluded.
1180 lines
43 KiB
Plaintext
1180 lines
43 KiB
Plaintext
;
|
|
; File: ADBDriver.aii
|
|
;
|
|
; Contains: IOP code for IOP Based ADB driver
|
|
;
|
|
; Written by: Gary G. Davidian 10-Jul-88
|
|
;
|
|
; Copyright: © 1988-1990 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <2> 1/2/90 GGD NEEDED FOR ZONE-5: General source cleanup, no code changes.
|
|
; <1.5> 11/19/89 GGD NEEDED FOR ZONE-5 Added conditional assembly option
|
|
; 'ForceWorstCase' to cause ADB to use more processor time, to
|
|
; stress test the worst case paths of the SWIM Driver. Added
|
|
; facility to control auto-polling on a device address basis so
|
|
; that the ADB Manager can select to only poll addresses that have
|
|
; device table entries.
|
|
; <1.4> 11/2/89 GGD NEEDED FOR ZONE-5 Changed the ADB Polling rate from 13.5ms to
|
|
; 11.0ms to be closer to a floppy disk sector time, and to be
|
|
; consistent with the Mac II ADB Micro poll rate.
|
|
; <1.3> 9/21/89 GGD Added ADBActivity indicator so that the disk driver can give ADB
|
|
; more priority if there was recent activity. Corrected timing
|
|
; calculation in Attn pulse (off by 5µs).
|
|
; <1.2> 7/8/89 CCH No changes. Testing in-file comments for ".aii" suffix files.
|
|
; <1.1> 6/15/89 GGD Updated to use equates for the latest rev of the IOP chip,
|
|
; re-formated tab stops in source.
|
|
; <1.0> 11/9/88 CCH Adding to EASE.
|
|
; 7/10/88 GGD Created today.
|
|
;
|
|
; To Do:
|
|
;
|
|
eject
|
|
title 'IOP ADB Driver'
|
|
; File: ADBDriver.aii - IOP code for IOP Based ADB driver.
|
|
;
|
|
;_______________________________________________________________________
|
|
;
|
|
; Copyright © Apple Computer, Inc. 1988-1989
|
|
;
|
|
; written by Gary G. Davidian 10-Jul-88
|
|
;
|
|
; This module implements the IOP side of the IOP based Apple Desktop Bus
|
|
; Driver. It performs the low level ADB transactions as well as automatic
|
|
; polling of the last device, and automatic service request polling (in
|
|
; Most Recently Used order). The Host CPU will only be interrupted, with
|
|
; a single interrupt per transaction, when there is some device input to
|
|
; be processed.
|
|
;
|
|
; This driver co-exists on the IOP that also has the SWIM Driver, and the
|
|
; SWIM chip is used to drive and receive the ADB bus.
|
|
;
|
|
; NOTE: This code was optimized for space, and also contains many cycle
|
|
; counted timing dependent routines. This may detract from its
|
|
; readability at times, but keep in mind that this code replaces a
|
|
; considerable amount of hardware and saves $$$ (profit sharing).
|
|
;
|
|
; MODIFICATION HISTORY:
|
|
;
|
|
; <10Jul88> GGD Created today.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
machine m65C02
|
|
codechk off
|
|
datachk off
|
|
longa off
|
|
longi off
|
|
print nomdir,nogen
|
|
print off
|
|
include 'IOPDefs.aii'
|
|
include 'SWIMDefs.aii'
|
|
print on
|
|
|
|
hasAltADB equ 1 ; include alternate SWIM based ADB also
|
|
ForceWorstCase equ 0 ; don't simulate worst case data length <1.5>
|
|
|
|
; Polling rate definitions
|
|
|
|
; These two time constants are used to control auto polling, and service request
|
|
; polling. Explicit commands are serviced immediatly, which may mean that if they
|
|
; are issued at a very high frequency, they may utilize more than 50% of the bus
|
|
; bandwith, and may prevent the processors in the devices from having time to
|
|
; service their device (this is the way that it is done on other machines).
|
|
; During normal AutoPolling, this situation will not occur. But it can occur during
|
|
; Service Request polling.
|
|
;
|
|
; AutoPollRate is the MINIMUM time from the START of a command to the START of
|
|
; the next command when auto polling.
|
|
;
|
|
; SRQPollDelay is the MINIMUM time from the END of a command to the START of
|
|
; the next command. This is used when polling for a device that issued a service
|
|
; request.
|
|
|
|
AutoPollRate equ (11000*TMPB1second)/1000000 ; 11.000 MS auto poll interval <1.4>
|
|
SRQPollDelay equ (00500*TMPB1second)/1000000 ; 0.500 MS delay before SRQ polls
|
|
|
|
|
|
; ADB transaction related definitions
|
|
|
|
NumADBAddrs equ 16 ; 16 addresses, 0..15
|
|
|
|
ADBCmdMask equ $0F ; mask for command/reg portion of ADB command
|
|
ADBAddrMask equ $F0 ; mask for address portion of ADB command
|
|
|
|
ResetCmd equ $00 ; ADB Bus Reset command
|
|
TalkR0Cmd equ $0C ; ADB command Talk Reg 0
|
|
|
|
MinDataLen equ 2 ; Data length can be 0, 2..8 bytes
|
|
MaxDataLen equ 8 ; Data length can be 0, 2..8 bytes
|
|
|
|
|
|
; Message Format
|
|
|
|
ADBMsg record 0,increment ; format CPU <-> IOP messages
|
|
Flags ds.b 1 ; modifier/status flags (see below)
|
|
DataCount ds.b 1 ; number of bytes of ADBData (0..8) (cmd not included)
|
|
ADBCmd ds.b 1 ; ADB command to send / command that replied
|
|
ADBData ds.b MaxDataLen ; ADB Data to be sent with command, or data received
|
|
ds.b 1 ; input data buffer (needs 1 extra byte)
|
|
endr
|
|
|
|
; ADBMsg.Flags bit definitions
|
|
|
|
ExplicitCmd equ %10000000 ; message contains an explicit commmand
|
|
AutoPollEnable equ %01000000 ; auto polling and srq polling enabled
|
|
SetPollEnables equ %00100000 ; Update auto-enable bit mask from ADBData field
|
|
ServiceRequest equ %00000100 ; service request detected
|
|
TimedOut equ %00000010 ; addressed device did not return data
|
|
|
|
|
|
; Low level message passing state and data buffer assignments
|
|
|
|
ADBXmtMsgState equ XMTMsg3State
|
|
ADBRcvMsgState equ RCVMsg3State
|
|
|
|
ADBXmtMsgData equ XMTMsg3Data
|
|
ADBRcvMsgData equ RCVMsg3Data
|
|
|
|
|
|
; Page zero variables
|
|
|
|
seg 'zdata'
|
|
ADBVarsZ record
|
|
export ADBActivity ; export activity status for disk driver
|
|
ADBActivity ds.b 1 ; status of last 8 transactions
|
|
ADBFlags ds.b 1 ; status information
|
|
ByteCount ds.b 1 ; number of bytes to send / bytes received
|
|
PollingTMPB ds.b 1 ; index of Polling Timer Param Block
|
|
MRUAddr ds.b 1 ; ADB address most recently received from
|
|
LRUAddr ds.b 1 ; ADB address least recently received from
|
|
AutoPollAddr ds.b 1 ; ADB address to auto poll
|
|
MsgPtr ds.w 1 ; pointer to xmt/rcv message buffer
|
|
Temp ds.b 1 ; general purpose temporary
|
|
SRQcount ds.b 1 ; number of devices searched during SRQ poll
|
|
endr
|
|
|
|
|
|
; Other Driver variables
|
|
|
|
seg 'data'
|
|
ADBVars record
|
|
XmtCmdAndData ds.b 1 ; command byte (must precede SendBuffer)
|
|
ds.b MaxDataLen ; output data buffer
|
|
MRUList ds.b NumADBAddrs ; list of ADB addrs in MRU order
|
|
DisableFlags ds.b NumADBAddrs ; if <> 0 then don't auto-poll this address
|
|
endr
|
|
ReceiveBuffer equ ADBXmtMsgData+ADBMsg.ADBData ; rcv directly into msg buffer
|
|
|
|
|
|
|
|
seg 'code'
|
|
ADBDrvr proc export
|
|
|
|
export HandleRCVMsg3 ; ADB driver requests use MSG 3
|
|
export HandleXMTMsg3 ; ADB driver requests use MSG 3
|
|
export InitADBDrvr ; ADB driver initialization
|
|
import GetTMPB
|
|
import CancelTMPBTimer
|
|
import StartTMPBTimer
|
|
import WaitTMPBDone
|
|
import CheckTMPBdone
|
|
import TMPBtimeH
|
|
import TMPBtimeL
|
|
|
|
with ADBVarsZ,ADBVars ; globals used throughout driver
|
|
title 'IOP ADB Driver - Initialization'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr InitADBDrvr
|
|
; Inputs: none
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, z, c
|
|
; Calls: GetTMPB
|
|
; Called by: SWIMIOP driver initialization
|
|
;
|
|
; Function: Initializes the IOP based ADB Driver variables.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
InitADBDrvr
|
|
if hasAltADB then
|
|
jsr CheckForAltADB ; patch in SWIM based ADB if present
|
|
endif
|
|
jsr GetTMPB ; get a timer parameter block pointer
|
|
sty <PollingTMPB ; save the TMPB pointer
|
|
|
|
* stz <ADBFlags ; initialize the status flags
|
|
|
|
assert (ADBXmtMsgData**$FF)=(ADBRcvMsgData**$FF)
|
|
lda #<(ADBXmtMsgData\
|
|
+ADBMsg.ADBCmd) ; get low byte of msg pointer
|
|
sta <MsgPtr ; init low byte of message pointer
|
|
|
|
; Initialize the MRU information
|
|
|
|
* stz <MRUAddr ; first entry is default MRU
|
|
* stz <AutoPollAddr ; first entry is default Poll device
|
|
ldx #NumADBAddrs-1 ; index/counter
|
|
stx <LRUAddr ; last entry is default LRU
|
|
@MRUInitLoop txa ; prepare to store count
|
|
sta MRUList-1,x ; MRUList[x] := x+1
|
|
dex ; point to prev list
|
|
bne @MRUInitLoop ; init the entire list
|
|
* stz MRUList\
|
|
+NumADBAddrs-1 ; last entry points to first
|
|
rts
|
|
title 'IOP ADB Driver - Host Message Request Handling'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr HandleRCVMsg3
|
|
; Inputs: none
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, v, z, c
|
|
; Calls: CopyMsg, ADBAction (branched to)
|
|
; Called by: IOPKernel.HandleHSTInt
|
|
;
|
|
; Function: Handles receiving new messages from the host, by copying
|
|
; the request information, and notifying the host that the
|
|
; message request has been accepted. ADBAction is then
|
|
; called to actually process the command.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
HandleRCVMsg3 ldx #>ADBRcvMsgData ; get high byte of message pointer
|
|
ldy ADBRcvMsgData\
|
|
+ADBMsg.DataCount ; get the xmt byte count
|
|
lda ADBRcvMsgData\
|
|
+ADBMsg.Flags ; get the new flags
|
|
jsr CopyMsg ; copy the message
|
|
lda #MessageCompleted ; message completed state
|
|
sta ADBRcvMsgState ; indicate that it is done
|
|
lda #MsgCompletedINT ; get the interrupt bit
|
|
sta HostControl ; interrupt the main CPU
|
|
bra ADBAction ; go run a command
|
|
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr HandleXMTMsg3
|
|
; Inputs: none
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, v, z, c
|
|
; Calls: CopyMsg, ADBAction (branched to)
|
|
; Called by: IOPKernel.HandleHSTInt
|
|
;
|
|
; Function: Handles receiving messages replies from the host, by copying
|
|
; the request information, and updating the message state to
|
|
; indicate that the message reply has been accepted.
|
|
; ADBAction is then called to actually process the command.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
HandleXMTMsg3 ldx #>ADBXmtMsgData ; get high byte of message pointer
|
|
ldy ADBXmtMsgData\
|
|
+ADBMsg.DataCount ; get the xmt byte count
|
|
lda ADBXmtMsgData\
|
|
+ADBMsg.Flags ; get the new flags
|
|
jsr CopyMsg ; copy the message
|
|
assert Idle=0
|
|
* lda #Idle ; Indicate that response was received
|
|
stz ADBXmtMsgState ; set the new message state
|
|
bra ADBAction ; go run a command
|
|
title 'IOP ADB Driver - Polling Request Handling'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jmp StartSRQPoll
|
|
; Inputs: none
|
|
; Outputs: none
|
|
; Destroys: A, X, n, z, c
|
|
; Calls: CancelPollTimer, StartPolling (branched to)
|
|
; Called by: ADBAction
|
|
;
|
|
; Function: Handles service request polling, by setting up a Talk R0
|
|
; command for the next device in MRU (Most Recently Used) order.
|
|
; It will delay for a short time before issuing the request
|
|
; so that devices on the ADB bus, and the IOP itself will not be
|
|
; saturated by this polling.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
StartSRQPoll ldx <AutoPollAddr ; get address of last device polled
|
|
@disabled lda MRUList,x ; get the next address to poll for service request
|
|
tax ; save the poll address
|
|
inc <SRQcount ; update the SRQ poll count
|
|
lda <SRQcount ; get the updated count
|
|
cpa #NumADBAddrs ; see if one pass through table completed
|
|
bge @updatePollAddr ; if all enabled addrs searched, search disabled ones
|
|
bit DisableFlags,x ; see if this address is enabled
|
|
bmi @disabled ; if disabled, skip it the first time
|
|
@updatePollAddr stx <AutoPollAddr ; change poll device to next most recently used
|
|
jsr CancelPollTimer ; cancel the autopoll timer
|
|
lda #<SRQPollDelay ; get low byte of poll delay
|
|
* (fall into) bra StartPolling ; poll the next device after a short delay
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr StartPolling
|
|
; Inputs: A - low byte of poll timer delay (high byte assumed zero)
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, v, z, c
|
|
; Calls: ADBAction (falls into)
|
|
; Called by: ADBAction, StartSRQPoll (branched to)
|
|
;
|
|
; Function: Starts running the polling timer, and returns.
|
|
;
|
|
; When the timer goes off, ADBAction will be called.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
StartPolling ldy <PollingTMPB ; get the TMPB index
|
|
sta TMPBtimeL,y ; store low into the TMPB
|
|
assert (SRQPollDelay>>8)=(AutoPollRate>>8)
|
|
lda #>AutoPollRate ; get high byte of poll rate
|
|
sta TMPBtimeH,y ; store high into the TMPB
|
|
jsr StartTMPBTimer ; start the timer
|
|
ldy <PollingTMPB ; get the TMPB index
|
|
jsr WaitTMPBdone ; wait for it to time out, return to caller
|
|
|
|
; Timer interrupt resumes us here
|
|
* (fall into) bra ADBAction ; when timer goes off, perform some ADB Action
|
|
title 'IOP ADB Driver - Perform ADB Action'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jmp ADBAction
|
|
; Inputs: none
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, v, z, c
|
|
; Calls: StartPolling, CheckTMPBdone, ADBRequest, StartSRQPoll (branched to)
|
|
; Called by: HandleRCVMsg3, HandleXMTMsg3, StartPolling (falls into)
|
|
;
|
|
; Function: Handles ADB request processing, by deciding what if anything
|
|
; should be done. While the IOP to Host transmit message is in
|
|
; use, no ADB action will be performed, since there is no way
|
|
; to notify the Host that it has completed. If an Explicit
|
|
; request is pending, it will be sent, otherwise, auto/SRQ
|
|
; polling will be done if enabled.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
ADBAction lda ADBXmtMsgState ; get the xmt message state
|
|
assert Idle=0
|
|
bne @Done ; if xmt msg in use, wait until its free
|
|
|
|
ldy <PollingTMPB ; get the TMPB index
|
|
jsr CheckTMPBdone ; see if auto poll timer timed out
|
|
bne @Done ; if not, wait until auto poll interval
|
|
lda #<AutoPollRate ; get low byte of auto poll rate
|
|
jsr StartPolling ; setup timer to wake us up later
|
|
|
|
; Figure out what to do.
|
|
|
|
assert ExplicitCmd=$80 ; n bit
|
|
assert AutoPollEnable=$40 ; v bit
|
|
bit <ADBFlags ; test explicit and auto-poll bits
|
|
bmi @SendIt ; if explicit command, go send it
|
|
bvc @Done ; if implicit, and no auto polling, do nothing
|
|
|
|
; If implicit, and polling enabled, create the auto-poll command
|
|
|
|
lda <AutoPollAddr ; get the device address to auto poll
|
|
asl a ; shift left 4 bits to position device address
|
|
asl a
|
|
asl a
|
|
asl a
|
|
ora #TalkR0Cmd ; make it a talk R0 command
|
|
sta XmtCmdAndData ; update the command
|
|
stz <ByteCount ; no data to send, now send the command
|
|
|
|
@SendIt jsr ADBRequest ; perform the ADB transaction
|
|
|
|
; Check the result of the transaction
|
|
|
|
lsr <ADBActivity ; shift in zero, assume no activity
|
|
|
|
lda <ADBFlags ; get flags
|
|
sta ADBXmtMsgData\
|
|
+ADBMsg.Flags ; return the new flags
|
|
and #ExplicitCmd\
|
|
+AutoPollEnable\
|
|
+TimedOut ; isolate just the flags that we want to check
|
|
|
|
cpa #AutoPollEnable\
|
|
+TimedOut ; test for implicit, auto, no reply
|
|
beq @CheckSRQ ; if so, don't notify host, keep on polling
|
|
|
|
; If explicit command, or reply received, Send ADB transaction result back to host
|
|
|
|
lda #$80 ; mask to set activity indication
|
|
tsb <ADBActivity ; indicate explicit or reply received activity
|
|
|
|
lda <ByteCount ; get the number of bytes received
|
|
sta ADBXmtMsgData\
|
|
+ADBMsg.DataCount ; get the xmt byte count
|
|
assert (Idle+1)=NewMessageSent
|
|
inc ADBXmtMsgState ; change message state Idle -> NewMessageSent
|
|
lda #NewMsgSentINT ; prepare to interrupt the host
|
|
sta HostControl ; interrupt the host
|
|
|
|
lda #ExplicitCmd ; prepare to clear explicit bit
|
|
trb <ADBFlags ; indicate no longer explicit
|
|
bne @Done ; if was explicit, don't check SRQ
|
|
stz <SRQcount ; if reply received, reset the SRQ count
|
|
|
|
; Check for service request, and if so, start SRQ polling
|
|
|
|
|
|
@CheckSRQ lda #ServiceRequest ; prepare to test for service request
|
|
bit <ADBFlags ; see if service request was set
|
|
bne StartSRQPoll ; if so, start/continue SRQ polling, and return
|
|
@Done rts ; otherwise, request is complete
|
|
title 'IOP ADB Driver - Utility Routines'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr CopyMsg
|
|
; Inputs: A - new flags from ADBMsg.Flags
|
|
; X - page number of message buffer
|
|
; Y - data count from ADBMsg.DataCount
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, v, z, c
|
|
; Calls: CancelPollTimer (falls into)
|
|
; Called by: HandleRCVMsg3, HandleXMTMsg3
|
|
;
|
|
; Function: If an explicit command is not already accepted, it will
|
|
; copy the flags, byte count, command and data, from the
|
|
; message whose page number was passed in, to prepare for
|
|
; starting an ADB transaction. If the new command is an
|
|
; explicit command, the poll timer is canceled, so that
|
|
; the command can run immediatly.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
CopyMsg bit <ADBFlags ; see if already have an explicit cmd
|
|
assert ExplicitCmd=$80 ; n bit
|
|
bmi @CopyDone ; if explicit pending, don't overwrite it
|
|
stx <MsgPtr+1 ; setup high byte of message pointer
|
|
sta <ADBFlags ; set new flags
|
|
stz <ByteCount ; send count is zero when implicit
|
|
and #ExplicitCmd\
|
|
+SetPollEnables ; check for explicit / SetPollEnables
|
|
assert ExplicitCmd=$80 ; n bit
|
|
bmi @Explicit ; if explicit then copy cmd and data
|
|
beq @CopyDone ; if not SetPollEnables, just return
|
|
|
|
; Process a SetPollEnables request (ignored if ExplicitCmd is also set)
|
|
trb <ADBFlags ; reset the SetPollEnables flag
|
|
ldy #2 ; 2 bytes of data (16 bit mask)
|
|
lda (MsgPtr),y ; get low byte of mask
|
|
sta <Temp ; save it
|
|
dey ; point to high byte
|
|
lda (MsgPtr),y ; get high byte of mask
|
|
ldx #NumADBAddrs-1 ; loop counter, index into DisableFlags
|
|
@EnablesLoop rol <Temp ; shift the low byte
|
|
rol a ; shift the high byte (highest bit into carry)
|
|
stz DisableFlags,x ; assume polling enabled
|
|
bcs @NextEnable ; if enable bit set, DisableFlags := $00
|
|
dec DisableFlags,x ; if enable bit clear, DisableFlags := $FF
|
|
@NextEnable dex ; update loop counter and index
|
|
bpl @EnablesLoop ; loop through all device addresses
|
|
|
|
@CopyDone rts ; all done
|
|
|
|
@Explicit cpy #MaxDataLen+1 ; see if count is reasonable
|
|
blt @CopyStart ; if in range start copying
|
|
ldy #MaxDataLen ; otherwise, peg it to the Max
|
|
@CopyStart sty <ByteCount ; init the send count
|
|
@CopyLoop lda (MsgPtr),y ; get a byte from the message
|
|
sta XmtCmdAndData,y ; copy it into the send buffer
|
|
dey ; dec index/count
|
|
bpl @CopyLoop ; copy the command and data
|
|
* (fall into) bra CancelPollTimer ; cancel the poll timer and return
|
|
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr CancelPollTimer
|
|
; Inputs: none
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, v, z, c
|
|
; Calls: CancelTMPBTimer
|
|
; Called by: StartSRQPoll, CopyMsg (falls into)
|
|
;
|
|
; Function: Cancels to Auto Polling interval timer.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
CancelPollTimer ldy <PollingTMPB ; get the TMPB index
|
|
jmp CancelTMPBTimer ; cancel the timer and return
|
|
title 'IOP ADB Driver - Bus Timing'
|
|
|
|
;_______________________________________________________________________
|
|
; Apple Desktop Bus timing definitions from ADB spec #062-0267 (Rev E)
|
|
; Clock counts based upon IOP Clock = 15.6672 MHZ / 8 = 1.9584 MHZ
|
|
;_______________________________________________________________________
|
|
|
|
;symbol clocks true clocks time meaning
|
|
Tcyc equ 196 ; 195.840 100µs bit cell time
|
|
T0 equ 127 ; 127.296 65µs "0" low time
|
|
T1 equ 69 ; 68.544 35µs "1" low time
|
|
Tattn equ 1567 ; 1566.720 800µs attention signal
|
|
Tsynch equ 127 ; 127.296 65µs synch pulse width
|
|
Tlt equ 392 ; 391.680 200µs stop to start time
|
|
Tstop equ 137 ; 137.088 70µs stop pulse width
|
|
Tsrq equ 588 ; 587.520 300µs service request
|
|
*Tres equ 5875 ; 5875.200 3ms reset signal (3ms min)
|
|
|
|
; Additionally we define the following
|
|
Tres equ 7834 ; 7833.600 4ms reset signal (40*Tcyc in Rev C)
|
|
*TsrqMin equ Tsrq-Tsrq*30/100 ; 210µs Minimum SRQ width is Tsrq - 30%
|
|
TsrqMin equ Tsrq-Tsrq*40/100 ; 180µs Minimum SRQ width is Tsrq - 40% (mouse violates spec)
|
|
TsrqMax equ Tsrq*130/100 ; 390µs Maximum SRQ width is Tsrq + 30%
|
|
TltMax equ Tlt*130/100 ; 260µs Maximum stop to start time is Tlt + 30%
|
|
T0Max equ Tcyc*130/100*65/100*105/100 ; 88.725µs Max time between data bit transitions
|
|
Tlow equ T1 ; 68.544 35µs initial low phase of bit cell
|
|
Tdata equ T0-T1 ; 58.752 30µs middle low or high phase of bit cell
|
|
Thigh equ Tcyc-T0 ; 68.544 35µs final high phase of bit cell
|
|
|
|
assert Tcyc=(T0+T1)
|
|
assert Tcyc=(Tlow+Tdata+Thigh)
|
|
|
|
; The ADB bus is normally high, a transaction is sent as follows.
|
|
|
|
; Attention signal starts the transaction
|
|
;High Bus is high when not in use
|
|
;Low Tattn Attention signal
|
|
;High Tsynch synch pulse
|
|
|
|
; The 8 bits of the command are sent, MSB first, LSB last.
|
|
;Low Tlow low phase of data bit
|
|
;L/H Tdata low if zero, high if one. Data phase of bit
|
|
;High Thigh high phase of data bit
|
|
|
|
; Stop bit follows command
|
|
;Low Tstop command stop bit
|
|
|
|
; Service requests from other devices are indicated here by pulling bus low.
|
|
;High Tlt stop bit to start bit
|
|
|
|
; data if any is as follows (otherwise bus is left high)
|
|
|
|
;Low Tlow beginning of start bit for data
|
|
;High Tdata data phase of start bit
|
|
;High Thigh high phase of start bit
|
|
|
|
; 2..8 bytes are sent, MSB first, LSB last.
|
|
;Low Tlow low phase of data bit
|
|
;L/H Tdata low if zero, high if one. Data phase of bit
|
|
;High Thigh high phase of data bit
|
|
|
|
; Stop bit follows command
|
|
;Low Tstop command stop bit
|
|
;High bus left high at end of transaction
|
|
title 'IOP ADB Driver - Bus Manipulation'
|
|
|
|
;_______________________________________________________________________
|
|
; Macros and constants used to read and write the ADB Bus. By using
|
|
; these definitions, this code can be easily modified if the polarity,
|
|
; bit position, or register addresss ever change. This would allow easy
|
|
; migration to an IOP that had direct access to the ADB bus, instead of
|
|
; accessing it through the SWIM chip.
|
|
;_______________________________________________________________________
|
|
|
|
; ADB output bit
|
|
|
|
if hasAltADB then
|
|
rAltADBoutReg equ rSetup ; SWIM register for ADB output state
|
|
wAltADBoutReg equ wSetup ; SWIM register for ADB output state
|
|
AltADBoutMask equ Select35 ; bit mask for output bit
|
|
endif
|
|
rADBoutReg equ TimerDPLLctl ; SWIM register for ADB output state
|
|
wADBoutReg equ TimerDPLLctl ; SWIM register for ADB output state
|
|
ADBoutMask equ GPOUT0 ; bit mask for output bit
|
|
|
|
; macros for modifing state of ADBoutReg when it is the Accumulator
|
|
|
|
macro
|
|
ADBoutLow ; change state to cause bus to go Low
|
|
ora #ADBoutMask ; output bit is active low
|
|
endm
|
|
|
|
macro
|
|
ADBoutHigh ; change state to cause bus to go High
|
|
and #ÅADBoutMask ; output bit is active low
|
|
endm
|
|
|
|
; ADB input bit
|
|
|
|
if hasAltADB then
|
|
AltADBinReg equ rHandshake ; SWIM register for ADB input state
|
|
AltADBinMask equ DriveSense ; bit mask for input bit
|
|
endif
|
|
ADBinReg equ TimerDPLLctl ; SWIM register for ADB input state
|
|
ADBinMask equ GPIN0 ; bit mask for input bit
|
|
|
|
; macros for branching on the state of ADBinReg after a BIT instruction
|
|
|
|
macro
|
|
brADBlo &Target ; branch if bus is low
|
|
beq &Target ; input bit is active high
|
|
endm
|
|
|
|
macro
|
|
brADBhi &Target ; branch if bus is high
|
|
bne &Target ; input bit is active high
|
|
endm
|
|
title 'IOP ADB Driver - Set Bus / Set Bus After'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr SetBus
|
|
; Inputs: c - Value to set the ADB bus to.
|
|
; Outputs: z - setup for brADBlo/brADBhi testing
|
|
; Destroys: A, n, v, z
|
|
; Calls: none
|
|
; Called by: ADBRequest
|
|
;
|
|
; Function: Sets the ADB bus output to the state specified by the
|
|
; carry bit. Carry reset means bus low, Carry set means
|
|
; bus high. After setting the bus, the bus input is read,
|
|
; and tested, ready for branching with brADBlo/brADBhi.
|
|
; This routine returns to the caller 12 clocks after the
|
|
; bus is set.
|
|
;
|
|
; The Macro SetBusAfter, is provided to allow an exact number
|
|
; of clocks to be counted before setting the bus.
|
|
; The acceptable clock counts are 27, 29..1301, 1303.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
|
|
macro
|
|
SetBusAfter &Count ; set bus to carry after "count" clocks
|
|
CallWaiting &Count-22,SetBusPlus
|
|
endm
|
|
|
|
macro
|
|
CallWaiting &Count,&Routine
|
|
lcla &q,&r
|
|
&q seta &eval(&Count)/5
|
|
&r seta &eval(&Count)//5
|
|
if &r=1 then
|
|
&q seta &q-1
|
|
&r seta &r+5
|
|
endif
|
|
if &q<1 then
|
|
aerror 'Wait value too small'
|
|
elseif &q>255 then
|
|
aerror 'Wait value too large'
|
|
else
|
|
lda #&q
|
|
jsr &Routine&r
|
|
endif
|
|
endm
|
|
|
|
if hasAltADB then
|
|
PatchBase
|
|
endif
|
|
SetBusPlus6 nop ; add 6 clocks before loop
|
|
SetBusPlus4 nop ; add 4 clocks before loop
|
|
SetBusPlus2 nop ; add 2 clocks before loop
|
|
* lda #1 ; ( 2)
|
|
* jsr SetBusHighPlus0 ; ( 8)
|
|
SetBusPlus0 dea ; (10) decrement loop counter
|
|
SetBusPlus3 bne SetBusPlus0 ; (12) loop until A=0
|
|
|
|
SetBus lda rADBoutReg ; (16) read output register
|
|
bcs @SetHigh ; (18) (19)
|
|
ADBoutLow ; (20) modify to set bus low
|
|
bra @SetBusOutput ; (23)
|
|
|
|
@SetHigh ADBoutHigh ; (21) modify to set bus high
|
|
nop ; (23)
|
|
|
|
@SetBusOutput sta wADBoutReg ; (27) set the bus high or low
|
|
lda #ADBinMask ; ( 2) prepare check bus fighting
|
|
bit ADBinReg ; ( 6) test the bus
|
|
rts ; (12) all done
|
|
if hasAltADB then
|
|
|
|
gbla &FixrADBoutReg1,&FixOutLowOp1,&FixOutLowData1,&FixOutHighOp1
|
|
gbla &FixOutHighData1,&FixwADBoutReg1,&FixADBinMask1,&FixADBinReg1
|
|
&FixrADBoutReg1 seta SetBus+1-PatchBase
|
|
&FixOutLowOp1 seta SetBus+5-PatchBase
|
|
&FixOutLowData1 seta SetBus+6-PatchBase
|
|
&FixOutHighOp1 seta @SetHigh+0-PatchBase
|
|
&FixOutHighData1 seta @SetHigh+1-PatchBase
|
|
&FixwADBoutReg1 seta @SetBusOutput+1-PatchBase
|
|
&FixADBinMask1 seta @SetBusOutput+4-PatchBase
|
|
&FixADBinReg1 seta @SetBusOutput+6-PatchBase
|
|
endif
|
|
title 'IOP ADB Driver - ADB Request Transaction'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr ADBrequest
|
|
; Inputs: XmtCmdAndData - Command byte, followed by data, if any
|
|
; ByteCount - number of data bytes to send (0..8)
|
|
; Outputs: ReceiveBuffer - data received from device
|
|
; ByteCount - number of data bytes received (0..8)
|
|
; ADBFlags.ServiceRequest - set if SRQ detected, else 0
|
|
; ADBFlags.TimedOut - set if no reply data received, else 0
|
|
; Destroys: A, X, Y, n, v, z. c
|
|
; Calls: SetBus, SetBusAfter, SendBytes, @ReceiveReply (branched to)
|
|
; Called by: ADBAction
|
|
;
|
|
; Function: Performs the low level ADB transmission, sending attention,
|
|
; sync, command byte, and stop bit. Detects and records
|
|
; service requests after command byte's stop bit. Data is
|
|
; sent if ByteCount is non-zero, preceded by a start bit,
|
|
; and followed by a stop bit.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
ADBrequest
|
|
if ForceWorstCase then ; simulate worst case data length <1.5>
|
|
ldy #10*8 ; 10 byte times @ 8 bits per byte
|
|
@delay sec ; leave bus high
|
|
setbusafter (Tcyc*130/100) ; worst case bit time
|
|
dey ; update bits remaining count
|
|
bne @delay ; loop through all bits
|
|
endif ; <1.5>
|
|
clc ; prepare to set bus low for attention pulse
|
|
jsr SetBus ; ( 12) attn is low for Tattn
|
|
lda <ADBFlags ; ( 15) Setup default result flags
|
|
and #ÅServiceRequest ; ( 17) Assume no service request
|
|
ora #TimedOut ; ( 19) Assume timeout (no receive data)
|
|
sta <ADBFlags ; ( 22)
|
|
|
|
; initialize the receive buffer while attention is being sent.
|
|
|
|
ldx #MaxDataLen ; ( 24) buffer index
|
|
lda #$01 ; ( 26) initialize receive buffer to $01 for shift loop
|
|
@RcvBufInitLoop sta ReceiveBuffer,x ; ( 31) ( 101)
|
|
dex ; ( 33) ( 103)
|
|
bne @RcvBufInitLoop ; ( 36) ( 105)
|
|
stz ReceiveBuffer ; ( 109) first byte is zero, to allow for start bit
|
|
|
|
; check for specially handled reset command
|
|
|
|
lda XmtCmdAndData ; ( 113) Get the command byte
|
|
sta ADBXmtMsgData\
|
|
+ADBMsg.ADBCmd ; ( 117) return the command
|
|
and #ADBCmdMask ; ( 119) isolate the command
|
|
assert ResetCmd=$00
|
|
* eor #ResetCmd ; test for reset command
|
|
beq @SendReset ; ( 121) ( 122) if reset command, send it
|
|
|
|
; kill some extra time because Tattn is too long for SetBusAfter range.
|
|
|
|
* ldx #0 ; X is still zero from above
|
|
@AttnLowWait dex ; ( 123) (1398)
|
|
bne @AttnLowWait ; ( 126) (1400)
|
|
|
|
; Send Sync before command byte
|
|
|
|
ldy #1 ; (1402) byte count is 1, index is 0. ADBcmd
|
|
assert Tsynch=(Tcyc-T1) ; sync is same as high phase of a 1 bit (start bit)
|
|
SetBusAfter Tattn-Tlow-1402 ; (Tattn-Tlow) (12) beginning of low phase of start bit
|
|
jsr SendBytes ; (Tlow) (18) send start bit, ADBcmd, and Stop bit
|
|
bcc @BusFite ; (20) report error if fighting (before stop bit)
|
|
brADBhi @NoSRQ ; (22) (23) if no fight then no SRQ
|
|
|
|
; An SRQ is defined as TsrqMin .. TsrqMax of low from the beginning of the stop
|
|
; bit, which was Tstop ago. So the min would be TsrqMin - Tstop.
|
|
; And the max would be TsrqMax - Tstop.
|
|
|
|
lda #ADBinMask ; (24) prepare to read the bus
|
|
ldx #(TsrqMin\ ; get min srq poll time
|
|
-Tstop\ ; Tsrq is defined from start of stop bit
|
|
-26\ ; which started its high phase 26 clocks ago
|
|
+10)/11 ; (26) Round up, Load min loop counter
|
|
@ChkSRQmin bit ADBinReg ; ( 4) test to see if SRQ went away
|
|
brADBhi @NoSRQ ; ( 6) Branch if SRQ too short
|
|
dex ; ( 8) decrement timeout count
|
|
bne @ChkSRQmin ; (11) loop
|
|
|
|
; if the SRQ was low long enough, make sure it goes back high soon enough
|
|
|
|
ldx #(TsrqMax\ ; get remaining max srq poll time
|
|
-(TsrqMin+2)\ ; adjust for min srq time already waited
|
|
+10)/11+1 ; (TsrqMin+2) Load max loop counter (1 extra due to early dec)
|
|
@ChkSRQmax dex ; ( 2) decrement timeout count
|
|
beq @BusFite ; ( 4) if timed out, SRQ too long
|
|
bit ADBinReg ; ( 8) test to see if SRQ is done
|
|
brADBlo @ChkSRQmax ; (11) loop until it goes high or times out
|
|
|
|
lda #ServiceRequest ; Flag valid SRQ detected
|
|
tsb <ADBFlags ; update status
|
|
|
|
; After the stop bit (and possibly SRQ) we wait 200µs (391 clocks) before
|
|
; the start bit that indicates the beginning of the data bytes.
|
|
|
|
@NoSRQ ldx #1 ; (25) initialize buffer index
|
|
ldy <ByteCount ; (28) get send byte count
|
|
beq @ReceiveReply ; (30) (31) if no data to send, look for a reply
|
|
|
|
; Send Start bit before data bytes
|
|
clc ; (32) prepare to set bus low
|
|
SetBusAfter Tlt-32 ; (Tlt) (12) begin start bit before sending data
|
|
jsr SendBytes ; send the transmit buffer
|
|
* (fall into) brADBhi @Done ; all done if no bus fight
|
|
|
|
@BusFite
|
|
@DataError
|
|
@TimeOut
|
|
@Done stz <ByteCount ; indicate no bytes in reply
|
|
rts ; Done
|
|
if hasAltADB then
|
|
|
|
gbla &FixADBinMask2,&FixADBinReg2,&FixADBinReg3
|
|
&FixADBinMask2 seta @ChkSRQmin-3-PatchBase
|
|
&FixADBinReg2 seta @ChkSRQmin+1-PatchBase
|
|
&FixADBinReg3 seta @ChkSRQmax+4-PatchBase
|
|
endif
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Reset is a special case command, the command byte is not sent out
|
|
; on the bus, instead, the bus is held low for Tres.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
@ResetLoopCount equ (Tres-(132-15)+1299)/1300
|
|
@ResetWait equ (Tres-(132-15))/@ResetLoopCount-(4+15)
|
|
|
|
@SendReset
|
|
* ldx #0 ; X is still zero from above
|
|
@ResetLoop inx ; ( 2) increment loop count
|
|
cpx #@ResetLoopCount ; ( 4) carry := 1 if limit reached, otherwise 0.
|
|
SetBusAfter @ResetWait ; (12) either leave the bus zero, or set it high
|
|
bcc @ResetLoop ; (15) loop until last time
|
|
rts ; all done
|
|
title 'IOP ADB Driver - Receive Reply'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr @ReceiveReply
|
|
; Inputs: ByteCount - initialized to zero
|
|
; ReceiveBuffer[0] - initialized to zero
|
|
; ReceiveBuffer[1..8] - initialized to $01
|
|
; Outputs: ReceiveBuffer - data received from device
|
|
; ByteCount - number of data bytes received (0..8)
|
|
; ADBFlags.TimedOut - set if no reply data received, else 0
|
|
; Destroys: A, X, Y, n, v, z. c
|
|
; Calls: @UpdateMRU (falls into)
|
|
; Called by: ADBRequest
|
|
;
|
|
; Function: Performs the low level ADB data reception, sending attention,
|
|
; sync, command byte, and stop bit. Detects and records
|
|
; service requests after command byte's stop bit.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
@ReceiveReply lda #ADBinMask ; ( 33) get the bit mask for testing the bus
|
|
; start bit should happen by TltMax after stop bit
|
|
ldx #-((T0Max\ ; ( 35) setup low counter/timeout
|
|
-0\ ; no extra time to reomve
|
|
+10)/11+1) ; Round up, adjust for early inc
|
|
ldy #(TltMax\ ; setup start bit timeout
|
|
-(37-7)\ ; Adjust for time before/after
|
|
+10)/11 ; ( 37) round up
|
|
@StartSearch bit ADBinReg ; ( 4) sample the bus
|
|
brADBlo @LowLoop ; ( 6) loop until it goes low
|
|
dey ; ( 8) check for timeout
|
|
bne @StartSearch ; (11) loop until start bit or timeout
|
|
rts ; no reply data if start bit timeout
|
|
|
|
|
|
@GetNextBit beq @DataError ; (20) if Shift Data is zero, start bit was zero
|
|
ldx #-((T0Max\ ; (22) setup low counter/timeout
|
|
-22\ ; adjust for cycles already consumed
|
|
+10)/11+1) ; Round up, adjust for early inc
|
|
|
|
; count number of samples when bus is low
|
|
|
|
@LowLoop inx ; ( 2) update low count/timeout
|
|
beq @TimeOut ; ( 4) if low too long
|
|
bit ADBinReg ; ( 8) sample the bus
|
|
brADBlo @LowLoop ; (11) loop until it goes high
|
|
|
|
; count number of samples when bus is high
|
|
|
|
ldy #-((T0Max\ ; ( 2) setup high counter/timeout
|
|
-2\ ; adjust for cycles already consumed
|
|
+10)/11+1) ; Round up, adjust for early inc
|
|
@HighLoop iny ; ( 2) update high count/timeout
|
|
beq @CheckEnd ; ( 4) if high too long (maybe end of data)
|
|
bit ADBinReg ; ( 8) sample the bus
|
|
brADBhi @HighLoop ; (11) loop until it goes low
|
|
|
|
; data bit is based on the higher counter
|
|
|
|
stx <Temp ; ( 3) setup for compare
|
|
cpy <Temp ; ( 6) carry := 1 if high >= low
|
|
ldx <ByteCount ; ( 9) get count/buffer index
|
|
rol ReceiveBuffer,x ; (15) shift the bit in
|
|
bcc @GetNextBit ; (17) (18) loop until entire byte is received
|
|
|
|
cpx #MaxDataLen ; (19) see if end of buffer reached
|
|
bge @DataError ; (21) report error if too many bytes received
|
|
inc <ByteCount ; (26) update count/buffer index
|
|
ldx #-((T0Max\ ; (28) setup timeout counter
|
|
-31\ ; adjust for cycles already consumed
|
|
+10)/11+1) ; Round up, adjust for early inc
|
|
bra @LowLoop ; (31) get next bit
|
|
|
|
@CheckEnd ldx <ByteCount ; get count/buffer index
|
|
dec ReceiveBuffer,x ; test for Shift Data = $01 (no bits shifted in)
|
|
bne @TimeOut ; if partial byte received, then this is a timeout
|
|
cpx #MinDataLen ; see if the 2 byte minimum was reached
|
|
blt @DataError ; if not, then the report the error
|
|
|
|
lda #TimedOut ; indicate that there is a valid reply
|
|
trb <ADBFlags ; update the flags
|
|
* (fall into) bra @UpdateMRU ; mark the device as most recent
|
|
if hasAltADB then
|
|
|
|
gbla &FixADBinMask3,&FixADBinReg4,&FixADBinReg5,&FixADBinReg6
|
|
&FixADBinMask3 seta @ReceiveReply+1-PatchBase
|
|
&FixADBinReg4 seta @StartSearch+1-PatchBase
|
|
&FixADBinReg5 seta @LowLoop+4-PatchBase
|
|
&FixADBinReg6 seta @HighLoop+4-PatchBase
|
|
endif
|
|
|
|
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr @UpdateMRU
|
|
; Inputs: XmtCmdAndData - command whose device is to be made MRU
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, v, z. c
|
|
; Calls: none
|
|
; Called by: @ReceiveReply (falls into)
|
|
;
|
|
; Function: Updates the MRU chain by making the specified device the
|
|
; most recently used, by removing it from the chain, and
|
|
; inserting it before the prior MRU entry, and marking it
|
|
; as the head of the MRU chain.
|
|
;
|
|
; When a Service Request is pending, don't update the MRU,
|
|
; because it is about to change again, and we don't want
|
|
; the MRU list to change during SRQ polling because if more
|
|
; that two devices were sending constant data, only the first
|
|
; two would get serviced.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
|
|
@UpdateMRU lda #ServiceRequest ; prepare to test service request
|
|
bit <ADBFlags ; see if it is set
|
|
bne @MRUok ; don't update MRU if SRQ pending
|
|
|
|
lda XmtCmdAndData ; get the last command sent
|
|
lsr a ; shift right 4 bits to get device address
|
|
lsr a
|
|
lsr a
|
|
lsr a
|
|
cpa <MRUAddr ; see if already MRU
|
|
beq @MRUok ; if so, no need to change anything
|
|
|
|
tax ; load last address into index reg
|
|
bit DisableFlags,x ; see if polling is disabled for this address
|
|
bmi @MRUok ; if disabled, don't update the AutoPollAddr
|
|
|
|
ldy #-1 ; loop counter/index
|
|
@MRUloop iny ; inc counter/index
|
|
cpa MRUList,y ; look for entry that points to new MRU
|
|
bne @MRUloop ; loop until it is found
|
|
|
|
cpa <LRUAddr ; see if LRU is becoming MRU
|
|
bne @DoUpdate ; if not, do normal stuff
|
|
sty <LRUAddr ; new LRU is pointer to old LRU
|
|
bra @MRUdone ; all done
|
|
|
|
@DoUpdate lda MRUList,x ; get successor of new MRU
|
|
sta MRUList,y ; remove new MRU entry from chain
|
|
ldy <LRUAddr ; get pointer to LRU entry
|
|
txa ;
|
|
sta MRUList,y ; LRU entry points to new MRU entry
|
|
lda <MRUAddr ; get pointer to old MRU entry
|
|
sta MRUList,x ; new MRU entry points to old MRU entry
|
|
@MRUdone stx <MRUAddr ; mark new entry as MRU
|
|
stx <AutoPollAddr ; mark new entry as auto poll device
|
|
|
|
@MRUok rts ; return, with valid reply
|
|
title 'IOP ADB Driver - Send Bytes'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr SendBytes
|
|
; Inputs: X - index to first byte to send from XmtCmdAndData
|
|
; Y - number of bytes to send
|
|
; Outputs: c - 0 means send aborted due to bus fighting
|
|
; 1 means send was successfull
|
|
; z - setup for brADBlo/brADBhi testing
|
|
; Destroys: A, X, Y, n, v, z, c
|
|
; Calls: SetBusAfter, brADBlo
|
|
; Called by: ADBRequest
|
|
;
|
|
; Function: Sends a start bit, the requested number of bytes, and a
|
|
; stop bit. The send will be aborted, and indicated in
|
|
; carry bit, if a bus fight occurs on any bit other than the
|
|
; stop bit. The fight status of the stop bit is returned in
|
|
; the z bit. It is assumed the SetBusAfter was called to
|
|
; set the bus low to begin the start bit right before calling
|
|
; SendBytes.
|
|
;
|
|
; This routine returns to the caller 18 clocks after setting
|
|
; the stop bit high.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
SendBytes
|
|
|
|
; Send Start bit before data bytes
|
|
|
|
stz <Temp ; (21) setup shift data for 1 bit (start bit)
|
|
sec ; (23) start bit is a one
|
|
|
|
; Send the data bytes
|
|
|
|
@NextBit SetBusAfter Tlow-23 ; (Tlow) (12) wait for end of low phase
|
|
bra @SendLoop ; (15) join common code (waste 3 clocks)
|
|
|
|
@SendLoop sec ; (17)
|
|
SetBusAfter Tdata-17 ; (Tdata) (12) set the bus high for Thigh
|
|
clc ; (14) prepare to set bus low / flag fight error
|
|
brADBlo @Error ; (16) report error if fighting
|
|
SetBusAfter Thigh-16 ; (Thigh) (12) set the bus low for Tlow
|
|
bit <Temp ; (15) just waste 3 clocks
|
|
asl <Temp ; (20) Shift the next bit into carry
|
|
bne @NextBit ; (22) (23) loop if not final bit
|
|
|
|
; drop 1 clock every byte to adjust for 195.84 vs 196.00
|
|
; missing clock ; (23)
|
|
lda XmtCmdAndData,x ; (27) get the next data byte
|
|
sec ; (29) shift in a one, so non-zero until done
|
|
rol a ; (31) Shift first bit into carry, 1 into low bit
|
|
sta <Temp ; (34) setup shift data
|
|
inx ; (36) update the buffer index
|
|
dey ; (38) update byte count
|
|
bmi @SendStop ; (40) (41) send the entire buffer
|
|
SetBusAfter Tlow-40 ; (Tlow) (12) wait for end of low phase
|
|
bra @SendLoop ; (15) join common code
|
|
|
|
; Send Stop bit after data bytes
|
|
@SendStop sec ; ( 43)
|
|
SetBusAfter Tstop-43 ; (Tstop) (12) stop bit is low for Tstop
|
|
@Error rts ; (18) then leave bus high
|
|
if hasAltADB then
|
|
title 'IOP ADB Driver - CheckForAltADB'
|
|
|
|
;_______________________________________________________________________
|
|
;
|
|
; Routine: jsr CheckForAltADB
|
|
; Inputs: none
|
|
; Outputs: none
|
|
; Destroys: A, X, Y, n, z, c
|
|
; Calls: none
|
|
; Called by: InitADBDrvr
|
|
;
|
|
; Function: If running on an old IOP chip, patch in the SWIM support.
|
|
;
|
|
;_______________________________________________________________________
|
|
|
|
CheckForAltADB ldx #-1 ; PatchTable index, pre-decremented
|
|
lda #ADBoutMask ; get the output bit mask
|
|
tsb wADBoutReg ; set the output bit
|
|
bit rADBoutReg ; see if the bit got set
|
|
beq @patchStart ; if clear, running on an old IOP chip
|
|
rts ; if set, new IOP, code is correct
|
|
|
|
; If this is an old IOP chip, we will patch our code to access the SWIM chip
|
|
; registers instead.
|
|
|
|
@addrLoop sta PatchBase,y ; change the code to use the new byte
|
|
@addrStart inx ; advance to next entry in the PatchTable
|
|
ldy PatchTable,x ; get the code offset to be changed
|
|
bne @addrLoop ; loop until end of list
|
|
|
|
@patchStart inx ; advance to next entry in the PatchTable
|
|
lda PatchTable,x ; get the new code byte to be used
|
|
bne @addrStart ; loop until end of list
|
|
rts ; code now patched for old IOP
|
|
|
|
|
|
FixrADBoutReg1 equ &FixrADBoutReg1
|
|
FixwADBoutReg1 equ &FixwADBoutReg1
|
|
FixOutLowOp1 equ &FixOutLowOp1
|
|
FixOutLowData1 equ &FixOutLowData1
|
|
FixOutHighOp1 equ &FixOutHighOp1
|
|
FixOutHighData1 equ &FixOutHighData1
|
|
FixADBinMask1 equ &FixADBinMask1
|
|
FixADBinMask2 equ &FixADBinMask2
|
|
FixADBinMask3 equ &FixADBinMask3
|
|
FixADBinReg1 equ &FixADBinReg1
|
|
FixADBinReg2 equ &FixADBinReg2
|
|
FixADBinReg3 equ &FixADBinReg3
|
|
FixADBinReg4 equ &FixADBinReg4
|
|
FixADBinReg5 equ &FixADBinReg5
|
|
FixADBinReg6 equ &FixADBinReg6
|
|
|
|
PatchTable
|
|
dc.b rAltADBoutReg**$FF ; change reads to the ADBoutReg
|
|
dc.b FixrADBoutReg1
|
|
dc.b 0
|
|
|
|
dc.b wAltADBoutReg**$FF ; change writes to the ADBoutReg
|
|
dc.b FixwADBoutReg1
|
|
dc.b 0
|
|
|
|
dc.b $29 ; change the 'ora' to an 'and'
|
|
dc.b FixOutLowOp1
|
|
dc.b 0
|
|
|
|
dc.b ÅAltADBoutMask ; active high output data
|
|
dc.b FixOutLowData1
|
|
dc.b 0
|
|
|
|
dc.b $09 ; change the 'and' to an 'ora'
|
|
dc.b FixOutHighOp1
|
|
dc.b 0
|
|
|
|
dc.b AltADBoutMask ; active high output data
|
|
dc.b FixOutHighData1
|
|
dc.b 0
|
|
|
|
dc.b AltADBinMask ; change loads of the ADBinMask
|
|
dc.b FixADBinMask1
|
|
dc.b FixADBinMask2
|
|
dc.b FixADBinMask3
|
|
dc.b 0
|
|
|
|
dc.b AltADBinReg**$FF ; change reads to the ADBinReg
|
|
dc.b FixADBinReg1
|
|
dc.b FixADBinReg2
|
|
dc.b FixADBinReg3
|
|
dc.b FixADBinReg4
|
|
dc.b FixADBinReg5
|
|
dc.b FixADBinReg6
|
|
dc.b 0
|
|
|
|
dc.b 0 ; end of table
|
|
endif
|
|
endwith
|
|
endproc
|
|
|
|
end
|
|
|