mirror of
https://github.com/elliotnunn/supermario.git
synced 2024-11-22 19:31:02 +00:00
2141 lines
64 KiB
Plaintext
2141 lines
64 KiB
Plaintext
|
;————————————————————————————————————————————————————————————————————————————————————
|
||
|
;
|
||
|
; File: HALc96.a
|
||
|
;
|
||
|
; Contains: Hardware Abstraction Layer for the 53c96 machines (Quadra + Cyclone)
|
||
|
;
|
||
|
; Written by: Paul Wolf
|
||
|
;
|
||
|
; Copyright: © 1992-1993 by Apple Computer, Inc., all rights reserved.
|
||
|
;
|
||
|
;
|
||
|
; NOTES on HALc96
|
||
|
;
|
||
|
; This HAL is written assuming at least a 68020! If we ever have a 68000 machine with
|
||
|
; a 53c96 then we have to change a few things.
|
||
|
;
|
||
|
;
|
||
|
; Change History (most recent first):
|
||
|
;
|
||
|
; <SM33> 11/22/93 pdw Rolling in from <MCxx>.
|
||
|
; <MC7> 11/8/93 pdw Added some support for unexpected disconnect. Fixed a bug in
|
||
|
; the handling of the selected-as-target Curio bug.
|
||
|
; <MC6> 11/5/93 pdw Series of attempts and re-attempts to fix various VM/FileShare
|
||
|
; problems.
|
||
|
; <MC5> 10/28/93 pdw Trivial stuff.
|
||
|
; <SM32> 11/16/93 SAM Include HardwarePrivateEqu.a
|
||
|
; <SMG2> 9/29/93 chp Substitute a 68020 addressing mode when referencing G_JmpTbl.
|
||
|
; The HAL variables have expanded enough that the old 8-bit base
|
||
|
; displacement indexed addressing mode is not sufficient.
|
||
|
; <SM30> 10/29/93 pdw Fixing build - RecordCmd is being expanded in the ROM but not in
|
||
|
; the Init in SOME places.
|
||
|
; <SM29> 10/29/93 DCB Removing a bogus clear of the gotInt flag at the start of
|
||
|
; doInitiate and SCSISelect which caused a sync wait hang.
|
||
|
; <SM28> 10/14/93 pdw <MC> roll-in.
|
||
|
; <MC4> 10/12/93 pdw Fixed error reported on initiate w/too few message out bytes.
|
||
|
; <MC3> 10/12/93 pdw Added support for Synchronous data transfers, rewrote State
|
||
|
; Machine, message handling etc.
|
||
|
; <SM27> 9/26/93 DCB SCSI Reset was not clearing the FIFO. This led to some weird
|
||
|
; crashes if the reset interrupted something that had left data
|
||
|
; there. In particular SCSI CDBs were being send instead of
|
||
|
; identify messages. Yikes.
|
||
|
; <MC2> 9/26/93 pdw Changes to G_State usage from bit flags to enumeration and other
|
||
|
; stuff.
|
||
|
; <SM26> 9/12/93 pdw Comment changes. Changed post-ResetBus delay to 250mS instead
|
||
|
; of 500mS.
|
||
|
; <SM25> 9/9/93 pdw Lots of little changes. Name changes, temporary cache_bug
|
||
|
; stuff.
|
||
|
; <SM24> 8/13/93 pdw A lot of eieios, RecordRCMDs, reworked PutXferPhase/Disconnect
|
||
|
; stuff, rewrote SCSIComplete.
|
||
|
; <SM23> 7/19/93 pdw Fixed build.
|
||
|
; <SM22> 7/19/93 pdw Added an ENDIF to fix that build warning.
|
||
|
; <SM21> 7/17/93 pdw Lots of little things.
|
||
|
; <SM20> 6/29/93 pdw Massive checkins: Change asynchronicity mechanism to CallMachine
|
||
|
; stack switching mechanism. Adding support for Cold Fusion.
|
||
|
; Rearranging HW/SW Init code. Some code optimizations. Resolving
|
||
|
; with my Ludwig sources.
|
||
|
; <SM19> 5/25/93 DCB Rollin from Ludwig. (The next item below)
|
||
|
; <LW15> 5/21/93 PW Hopefully adding ability to handle being selected while we are
|
||
|
; trying to select.
|
||
|
; <SM18> 5/5/93 PW Converted names to meanies-friendly names. Updated with latest
|
||
|
; from Ludwig stuff.
|
||
|
; <LW14> 4/30/93 DCB Make DoHalInfo a separate function so it can be stuffed into a
|
||
|
; vector.
|
||
|
; <LW12> 4/14/93 DCB Added SetParity HALAction but left it disabled for now.
|
||
|
; <LW11> 3/26/93 PW Removed useless RejectMsg stuff.
|
||
|
; <SM17> 3/29/93 PW Removed rCF3 manipulations for PDM. Now I just set it up once in
|
||
|
; HWInit for threshold 8 or not.
|
||
|
; <SM16> 3/21/93 PW Removing useless RejectMsg stuff.
|
||
|
; <LW10> 3/8/93 PW Fixed another instance of c96-FIFO-stuck bug in DoCommand by
|
||
|
; checking not only for zero bytes but for 1 byte in FIFO after
|
||
|
; interrupt.
|
||
|
; <LW9> 2/17/93 PW Removed DoBitBucket and put it in HALc96Data.a instead.
|
||
|
; <SM15> 3/20/93 PW Removed some bogus PDM stuff that causes problems on non-PDMs.
|
||
|
; <SM14> 3/20/93 PW Removed DoBitBucket and put it in HALc96Data.a instead.
|
||
|
; <LW8> 2/3/93 PW Removed initCF1 munging before and after DoReset to fix reset
|
||
|
; blowing up bug.
|
||
|
; <SM13> 1/31/93 PW Update from the latest of Ludwig. Also changes required for PDM
|
||
|
; (will update Ludwig with these as needed myself).
|
||
|
; <LW7> 1/29/93 PW Passing HALg into SetupIOPB function.
|
||
|
; <LW6> 1/27/93 PW Playing around with some interrupt stuff. Changed HALaction
|
||
|
; events to include SR (for int level).
|
||
|
; <LW5> 1/27/93 PW Changed the name of InitDataPointer to InitDataStuff (since it's
|
||
|
; more general now). Changed intEnable and intDisable calling
|
||
|
; around - now I disable going into MyDT and enable coming out and
|
||
|
; I disable going into HALAction and enable coming out.
|
||
|
; <LW4> 1/8/93 PW Removed bogusing the phase and selectorID values in HALActionPB
|
||
|
; in ReadHALAction. This fixes the problem where RestorePointers
|
||
|
; action trashes phase so following SwitchPhase breaks. Also added
|
||
|
; fixes to Initiate to handle Reselect better - moved call to
|
||
|
; InitDataPointer to after select complete and flushed FIFO after
|
||
|
; checking for a second interrupt on a r_select. Also flushed FIFO
|
||
|
; after a select is complete (for targets which dont get all of
|
||
|
; the command bytes (i.e. IBM 160 with a $90 command).
|
||
|
; <LW3> 12/18/92 PW Really fix the hanging in vSyncWait after SCSICmd bug by
|
||
|
; clearing the G_State96 bits after Ck4SCSIInt sees the interrupt.
|
||
|
; <LW2> 12/15/92 DCB Fixed SCSICmd bug with DSP running or with caches disabled by
|
||
|
; not calling Wt4S if ck4int reveals an interrupt.
|
||
|
; <SM12> 12/9/92 PW Changed SCStats record name to SCResults. Rearranged DoCommand
|
||
|
; routine to fix some MORE bugs handling SCSISelAtn/SCSIMsgOut.
|
||
|
; <SM11> 12/9/92 PW Fixed SCSIMsgOut bug by changing DMA xfer count from 3 bytes to
|
||
|
; 2.
|
||
|
; <SM10> 12/5/92 PW Changed some names and fixed the DoReset routine so that it
|
||
|
; works when Reset interrupt reporting is on.
|
||
|
; <SM9> 11/12/92 PW Changed beq.s and bra.s to beq.w and bra.w to work when
|
||
|
; RECORD_rCMD is turned on.
|
||
|
; <SM8> 10/30/92 DCB Added Setup and Teardown routines to support Direct DMA into a
|
||
|
; user buffer
|
||
|
; <SM7> 10/8/92 PW Added GrossError checks. Some trivial name changes. Added test
|
||
|
; for out of bounds xferType. (cb) Fixed .w vs .l direction
|
||
|
; parameter bug in calling of StartDMA.
|
||
|
; <SM6> 9/11/92 DCB Rolled in Paul's fix for message out during initiate
|
||
|
; <SM5> 8/31/92 PW Changed register and command definitions to reflect changes to
|
||
|
; SCSIEqu53c96. Also added SelWAtnStop stuff to send 2 and 4 or
|
||
|
; more byte messages out in DoInitiate.
|
||
|
; <SM4> 8/30/92 PW Added DoAssertATN and fixed SendMsg bugs (it couldn't handle
|
||
|
; multiple-byte msg non-SelWAtn case).
|
||
|
; <SM3> 8/20/92 DCB Added Select w/o Atn and fixed SCSI Reset
|
||
|
; <SM2> 7/28/92 PW Resolved differences in sources.
|
||
|
; <SM1> 7/27/92 PW Initial check-in.
|
||
|
;
|
||
|
;____________________________________________________________________________________
|
||
|
|
||
|
|
||
|
MACHINE MC68020 ; '020-level
|
||
|
BLANKS ON ; assembler accepts spaces & tabs in operand field
|
||
|
PRINT OFF ; do not send subsequent lines to the listing file
|
||
|
; don't print includes
|
||
|
|
||
|
|
||
|
INCLUDE 'SysEqu.a'
|
||
|
wholeErrors equ 1
|
||
|
INCLUDE 'SysErr.a'
|
||
|
INCLUDE 'HardwarePrivateEqu.a'
|
||
|
INCLUDE 'Debug.a' ; for NAME macro
|
||
|
|
||
|
INCLUDE 'SCSI.a'
|
||
|
INCLUDE 'SCSIStandard.a'
|
||
|
INCLUDE 'SCSIEqu53c96.a'
|
||
|
INCLUDE 'ACAM.a'
|
||
|
INCLUDE 'SIMCoreEqu.a'
|
||
|
|
||
|
INCLUDE 'HALc96equ.a'
|
||
|
|
||
|
PRINT ON ; do send subsequent lines to the listing files
|
||
|
|
||
|
CASE OBJECT
|
||
|
|
||
|
IMPORT Xfer1Byte96, Wt4SCSIInt
|
||
|
IMPORT Ck4SCSIInt
|
||
|
IMPORT GetSelectInfo, GetReconnectInfo
|
||
|
|
||
|
IMPORT InitDataStuff
|
||
|
IMPORT GetHalInfo
|
||
|
|
||
|
IMPORT RecordEvent, Ck4DREQ
|
||
|
|
||
|
IMPORT AsmInit53c9xHW
|
||
|
IMPORT Disconnected, UnexpectedDisc
|
||
|
|
||
|
;====================================================================================
|
||
|
|
||
|
;************************************************************************************
|
||
|
;
|
||
|
; HALaction - main entry point for HAL (called by SIMCore)
|
||
|
;
|
||
|
; This routine gets handed 1 parameter on the stack - a pointer to a HALactionPB.
|
||
|
; It establishes the following register convention and then calls the requested action.
|
||
|
;
|
||
|
; A0 - current SCSI_IO parameter block ptr
|
||
|
; A3 - ptr to 53c96 base address
|
||
|
; A4 - ptr to the HALactionPB (passed in as parameter on stack)
|
||
|
; A5 - HALg (ptr to the HALglobals)
|
||
|
;
|
||
|
; These register conventions are used throughout the HAL. Any routine that uses
|
||
|
; any of these registers must save/restore them.There are no conventions for
|
||
|
; Dx registers.
|
||
|
;
|
||
|
; The action is specified in the HALactionPB.action parameter. We use the handy
|
||
|
; jump table to find and call the appropriate routine.
|
||
|
;
|
||
|
; When we return from the requested HALaction, the phase is checked to see if some
|
||
|
; additional work is needed before returning to the SIM. If Bus Free, then we need
|
||
|
; to do some housework associated with Disconnecting. If MsgIn phase, the we will go
|
||
|
; ahead and get the message for the SIM but we won't accept it unless we know what to
|
||
|
; do with it.
|
||
|
;
|
||
|
;====================================================================================
|
||
|
|
||
|
HALaction PROC EXPORT
|
||
|
;————————————————————————————————————————————————————————————————————————————————————
|
||
|
|
||
|
regsToSave REG D3-D7/A2-A5
|
||
|
numRegsToSave EQU 9
|
||
|
|
||
|
WITH HALactions
|
||
|
WITH HALc96GlobalRecord
|
||
|
WITH SCSIPhase
|
||
|
|
||
|
movem.l regsToSave, -(sp)
|
||
|
|
||
|
move.l numRegsToSave*4+4(sp), A4 ; get the one parameter from stack (HALactionPB)
|
||
|
move.l HALactionPB.HALstaticPtr(A4), A5 ; and get the staticPtr
|
||
|
|
||
|
; Initialize the values in the HALactionPB
|
||
|
|
||
|
clr.w HALactionPB.result(A4) ; assume noErr, Action will change if needed
|
||
|
|
||
|
; Get stuff out of PB into our world
|
||
|
|
||
|
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
|
||
|
|
||
|
move.w HALactionPB.action(A4), D0 ; get Action from HALactionPB
|
||
|
|
||
|
cmp.w #kNumHALaction, D0 ; is scsiSelector higher than last one?
|
||
|
bhs.s @Unknown ; yes - unknown
|
||
|
|
||
|
move.l (G_JmpTbl, A5, D0.w*4), A1 ; get action routine from jump table
|
||
|
|
||
|
IF RECORD_ON THEN
|
||
|
pea 'HAL-'
|
||
|
move.b HALactionPB.action+1(A4), D3
|
||
|
lsl.l #8, D3
|
||
|
move.b HALactionPB.msgOutLen(A4), D3
|
||
|
lsl.l #8, D3
|
||
|
move.b HALactionPB.msg(A4), D3
|
||
|
lsl.l #8, D3
|
||
|
move.b currentPhase(A5), D3
|
||
|
move.l D3, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
|
||
|
;…………………………… Call the selected routine ……………………………………
|
||
|
|
||
|
move.l HALactionPB.ioPtr(A4), A0 ; load A0 with ptr to SCSI_IO pb
|
||
|
jsr (A1) ; and go to requested action routine
|
||
|
|
||
|
;…………………………………………………………………………………………………………………………………………
|
||
|
|
||
|
move.b currentPhase(A5), D0
|
||
|
@ck4msgIn
|
||
|
cmp.b #kMessageInPhase, D0
|
||
|
bne.s @ck4busFree
|
||
|
jsr ([jvAutoMsgIn, A5])
|
||
|
move.b currentPhase(A5), D0
|
||
|
@ck4busFree
|
||
|
cmp.b #kBusFreePhase, D0
|
||
|
bne.s @normalPhase
|
||
|
bsr Disconnected
|
||
|
@normalPhase
|
||
|
move.b D0, HALactionPB.phase(A4)
|
||
|
|
||
|
IF RECORD_ON THEN
|
||
|
pea '-HAL'
|
||
|
move.b HALactionPB.action+1(A4), D3
|
||
|
lsl.l #8, D3
|
||
|
move.b HALactionPB.result+1(A4), D3
|
||
|
lsl.l #8, D3
|
||
|
move.b HALactionPB.msg(A4), D3
|
||
|
lsl.l #8, D3
|
||
|
move.b HALactionPB.phase(A4), D3
|
||
|
move.l D3, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
|
||
|
movem.l (sp)+, regsToSave
|
||
|
rts
|
||
|
|
||
|
|
||
|
@Unknown
|
||
|
IfDebugStr 'HAL action selector too high'
|
||
|
moveq #dsIOCoreErr, D0
|
||
|
_SysError
|
||
|
|
||
|
bra.s *
|
||
|
|
||
|
RTSNAME 'HALaction'
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
|
||
|
HALc96 PROC EXPORT
|
||
|
;——————————————————————————————————————————————————————————————————————————
|
||
|
|
||
|
EXPORT DoInitiate, Wt4SelectComplete, HandleBusInt
|
||
|
EXPORT DoAcceptMsg
|
||
|
EXPORT DoMsgOut
|
||
|
EXPORT DoStatus
|
||
|
EXPORT DoComplete
|
||
|
EXPORT DoSelect
|
||
|
EXPORT DoCommand
|
||
|
EXPORT SetParity
|
||
|
EXPORT CyclePhase
|
||
|
EXPORT AutoMsgIn
|
||
|
|
||
|
EXPORT HALResetBus, HALAssertATN, HALTeardownIO
|
||
|
EXPORT HALSyncConfig
|
||
|
EXPORT DoAssertATN
|
||
|
EXPORT SetupIONoDMA, TeardownIONoDMA
|
||
|
EXPORT DoReset
|
||
|
|
||
|
WITH HALc96GlobalRecord
|
||
|
WITH SCSI_IO, HALactions, SCSIPhase
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
Unimplemented
|
||
|
IfDebugStr 'Unknown HAL action selector'
|
||
|
moveq #dsIOCoreErr, D0
|
||
|
_SysError
|
||
|
|
||
|
;——————————————————————————————————————————————————————————————————————————
|
||
|
rts
|
||
|
|
||
|
NAME 'Unimplemented'
|
||
|
|
||
|
|
||
|
;################################################################################
|
||
|
;********** HALActions *********
|
||
|
;################################################################################
|
||
|
|
||
|
IF 0 THEN
|
||
|
;========================================================================
|
||
|
Initiate a connection
|
||
|
Arbitrate, Select and send [Identify message and] CDB to target
|
||
|
|
||
|
Description:
|
||
|
Once DMA is setup to do CDB and c96 is setup to do Arb+Select+Identify+CDB,
|
||
|
it can end up several ways:
|
||
|
• Arbitration failed
|
||
|
SCSI Int - ??
|
||
|
no DMA int
|
||
|
• Select failed
|
||
|
SCSI Int - ??
|
||
|
no DMA int
|
||
|
• Select w/Atn but didn't go into MessageOut phase
|
||
|
SCSI Int - ??
|
||
|
no DMA int
|
||
|
• didn't go into Command phase
|
||
|
SCSI Int - ??
|
||
|
no DMA int
|
||
|
• only sent part of CDB before target went out of Command phase
|
||
|
SCSI Int - ??
|
||
|
no DMA int
|
||
|
• sent CDB but didn't get out of Command phase
|
||
|
SCSI Int - Function Complete + ??
|
||
|
DMA int - xfer complete
|
||
|
c96 will bitblast 00 out until !Command phase. Can/can't?? tell it happened.
|
||
|
• all OK - send MsgOut and Command out and went into a different phase
|
||
|
SCSI Int - Function Complete + Bus Service, rSEQ=??
|
||
|
DMA int - xfer complete
|
||
|
|
||
|
Flow:
|
||
|
Setup c96 to do a Select w/Atn with Identify msg in FIFO and CDB in DMA
|
||
|
Setup DMA for CDB
|
||
|
Return to caller and wait for interrupt from c96 and DMA
|
||
|
Int c96:
|
||
|
get status, fifo seq and interrupt regs
|
||
|
all cool?
|
||
|
yes: DMA already int?
|
||
|
no: rts - wait for DMA_complete int
|
||
|
yes: call InitiateComplete(success)
|
||
|
no: find out what went wrong
|
||
|
terminate DMA
|
||
|
call InitiateComplete(failed)
|
||
|
Int DMA:
|
||
|
SCSI already int?
|
||
|
no: rts - wait for SCSI int
|
||
|
yes: check
|
||
|
;
|
||
|
ENDIF
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
; Initiate
|
||
|
; - Arbitrate, Select, Send Message(s) (optional), Send CDB (command bytes, optional)
|
||
|
;
|
||
|
; In the 5396, arbitration, selection and command-send operations are integrated operations.
|
||
|
; We need the target id and the actual command descriptor block in order to exploit the
|
||
|
; capabilities of the chip. Unfortunately, the old SCSI manager was structured for separate
|
||
|
; such operations. This proc is an attempt to remain compatible to that type of operation.
|
||
|
; Our goal is to select a target and report the success or failure of that operation.
|
||
|
; This is accomplished by:
|
||
|
; 1) Loading transfer count, TC, with one in order to activate the select process
|
||
|
; 2) Using DMA mode in order to allow us to send the actual CDB during DoSCSICmd proc.
|
||
|
;
|
||
|
; Upon exit, we should be in transfer phase waiting for the client to perform either a
|
||
|
; command send or msg-out--if select w/ ATN. The c96 would be ready and waiting for the
|
||
|
; CDB or message byte because we told it to expect at least 1 byte of data.
|
||
|
;
|
||
|
; Select w/ ATN asserts the ATTENTION line during selection process. This allows the
|
||
|
; client to perform a 1 byte msg-out via SCSIMsgOut. The ATN line is deasserted
|
||
|
; prior to sending the msg byte.
|
||
|
;
|
||
|
; A4 - ptr to HALaction pb
|
||
|
; A3 - SCSI read base address
|
||
|
; A5 - ptr to SCSI Mgr globals
|
||
|
;
|
||
|
;--------------------------------------------------------------------------
|
||
|
DoInitiate
|
||
|
IF RECORD_ON THEN
|
||
|
move.l D0, -(sp)
|
||
|
pea 'Init'
|
||
|
moveq #'0', D0
|
||
|
add.b scsiDevice.targetID(A0), D0 ; ID
|
||
|
move.l D0, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
move.l (sp)+, D0
|
||
|
ENDIF
|
||
|
|
||
|
|
||
|
move.b rSTA(A3), D1 ; interrupt?
|
||
|
bmi.w @getBusInt ; if we got an int from the bus, go check it out
|
||
|
;
|
||
|
; Set up chip for select process (init dest ID)
|
||
|
;
|
||
|
move.b scsiDevice.targetID(A0), rDID(A3) ; tell chip which target ID to select
|
||
|
|
||
|
;—————————————————————————————————————————————————————————
|
||
|
;
|
||
|
; Check scsiDisableSelectWAtn flag and number of msg_out bytes needed to determine what kind
|
||
|
; of Select operation we need to do.
|
||
|
;
|
||
|
move.w SCSI_IO.scsiIOFlags(A0), D0 ; Get the flags field
|
||
|
and.w #scsiDisableSelectWAtn,D0 ; Are we doing select with attention?
|
||
|
bne @useNoAtnSel ; nope, don't send an identify message
|
||
|
|
||
|
;
|
||
|
; How many message bytes are there? This will determine what Select command
|
||
|
; we will issue to the c96.
|
||
|
;
|
||
|
moveq.l #0, D0
|
||
|
move.b HALactionPB.msgOutLen(A4), D0
|
||
|
IF DEBUGGING THEN
|
||
|
bne.s @99 ; if no msg bytes to send, we're toast!!!
|
||
|
DebugStr 'DoInitiate:SelectWAtn but no msg'
|
||
|
ENDIF
|
||
|
@99 cmp.b #1, D0 ; 1 message byte?
|
||
|
bne.s @ck3byteSel ; no->ck for 3 bytes
|
||
|
|
||
|
|
||
|
|
||
|
;—————————————————————————————————————————————————————————
|
||
|
;
|
||
|
; If there is 1 message out byte, we can stuff it and the CDB into the
|
||
|
; FIFO then send a SelWAtn command.
|
||
|
;
|
||
|
|
||
|
@use1byteSel
|
||
|
move.b HALactionPB.msg(A4), rFIFO(A3) ; move message into FIFO
|
||
|
|
||
|
tst.b HALactionPB.sendCDB(A4) ; are we sposed to send CDB too?
|
||
|
beq.s @skipCDB1 ; no->skip it
|
||
|
bsr MoveCDBintoFIFO ; yes: stuff it and check for bus int
|
||
|
bmi.w @getBusInt ; if we got an int, go check it out
|
||
|
@skipCDB1
|
||
|
RecCmd $42, 'A',$08
|
||
|
eieio
|
||
|
move.b #cSelWAtn, rCMD(A3) ; issue Select w/ Atn cmd (non-DMA)
|
||
|
eieio
|
||
|
bra.w @SelStarted
|
||
|
|
||
|
|
||
|
|
||
|
;—————————————————————————————————————————————————————————
|
||
|
;
|
||
|
; If there are 3 message bytes to send, use a SelWAtn3 command.
|
||
|
;
|
||
|
@ck3byteSel
|
||
|
cmp.b #3, D0 ; 3 message bytes?
|
||
|
bne.s @doSelAndStop
|
||
|
|
||
|
@use3byteSel
|
||
|
lea.l HALactionPB.msg(A4), A1
|
||
|
move.b (A1)+, rFIFO(A3) ; move message into FIFO
|
||
|
move.b (A1)+, rFIFO(A3) ; move message into FIFO
|
||
|
move.b (A1)+, rFIFO(A3) ; move message into FIFO
|
||
|
move.b rSTA(A3), D1 ; interrupt?
|
||
|
bmi.w @getBusInt ; if we got an int, go find out what it is
|
||
|
|
||
|
tst.b HALactionPB.sendCDB(A4) ; are we sposed to send CDB too?
|
||
|
beq.s @skipCDB3 ; no->skip it
|
||
|
bsr MoveCDBintoFIFO ; yes: stuff it and check for bus int
|
||
|
bmi.w @getBusInt ; if we got an int, go check it out
|
||
|
@skipCDB3
|
||
|
RecCmd $46, 'A',$0a
|
||
|
eieio ; flush all writes out before issuing cmd
|
||
|
move.b #cSelWAtn3, rCMD(a3) ; issue Select w/ Atn3 cmd (non-DMA)
|
||
|
eieio
|
||
|
|
||
|
bra.w @SelStarted
|
||
|
|
||
|
|
||
|
;—————————————————————————————————————————————————————————
|
||
|
;
|
||
|
; If there are other than 1 or 3 message out bytes, we have to do a SelAndStop command
|
||
|
; followed by cIOXfer of the remainder of the message then cIOXfer of the command bytes.
|
||
|
;
|
||
|
@doSelAndStop
|
||
|
lea.l HALactionPB.msg(A4), A1
|
||
|
move.b (A1)+, rFIFO(A3) ; move 1st message byte into FIFO
|
||
|
eieio
|
||
|
|
||
|
RecCmd $41, 'A',$00
|
||
|
move.b #cSelWATNStop, rCMD(a3) ; do Select w/Atn and stop (after 1 msg-out)
|
||
|
eieio
|
||
|
jsrv jvWt4SelectComplete, A2
|
||
|
bne.w @exit ; if we didn't select, exit
|
||
|
|
||
|
;
|
||
|
; Check phase and/or check FIFO: if we didn't send the 1 message byte out, set a flag
|
||
|
; indicating that. If we did but we aren't still in msg_out phz, set a different flag.
|
||
|
; If we did and we are still in msg_out phase - jolly good - stuff the rest of the msg
|
||
|
; into the FIFO.
|
||
|
;
|
||
|
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
|
||
|
and.b int_rFIFOflags(A5), D1 ; is the byte still in the FIFO?
|
||
|
beq.s @sendRestOfMsg ; no -> send rest of message
|
||
|
|
||
|
bra.w @selIncompleteMsg ;
|
||
|
|
||
|
@sendRestOfMsg
|
||
|
cmpi.b #kMessageOutPhase, currentPhase(A5) ; are we in MsgOut phase?
|
||
|
beq.s @inMsgOutPhase ; yes->send rest of bytes
|
||
|
|
||
|
move.b #1, HALactionPB.msgOutLen(A4) ; no: we only sent 1 msg byte
|
||
|
bra.w @selIncMsgNoCalc
|
||
|
|
||
|
@inMsgOutPhase
|
||
|
moveq.l #0, D0
|
||
|
move.b HALactionPB.msgOutLen(A4), D0
|
||
|
subq.w #2, D0 ; 1 for missing dbra, 1 for 1st msg byte
|
||
|
@lp
|
||
|
move.b (A1)+, rFIFO(A3) ; move message into FIFO
|
||
|
dbra D0, @lp
|
||
|
eieio
|
||
|
|
||
|
;
|
||
|
; Do the IOxfer and check the results (FIFO count and phase). Note if we didn't get all
|
||
|
; of our message bytes out (and clear them out with FlushFIFO).
|
||
|
;
|
||
|
RecCmd $10, 'A',$04
|
||
|
move.b #cIOXfer, rCMD(a3) ; load Transfer cmd byte in CMD regr
|
||
|
eieio
|
||
|
|
||
|
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
|
||
|
|
||
|
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
|
||
|
and.b int_rFIFOflags(A5), D1 ; are there bytes still in the FIFO?
|
||
|
beq.s @ck4CmdPhase ; no -> see if we're in cmd Phase
|
||
|
; we didn't send all of our message out
|
||
|
bra @selIncompleteMsg
|
||
|
|
||
|
@ck4CmdPhase
|
||
|
tst.b HALactionPB.sendCDB(A4) ; are we sposed to send CDB too?
|
||
|
beq.w @selComplete ; no->we're done
|
||
|
|
||
|
cmpi.b #kCommandPhase, currentPhase(A5) ; are we in Command phase?
|
||
|
bne.w @selNoCommand ; no->we missed Command phase
|
||
|
|
||
|
@inCommandPhase
|
||
|
bsr MoveCDBintoFIFO ; yes: stuff it and check for bus int
|
||
|
|
||
|
RecCmd $10, 'A',$06
|
||
|
move.b #cIOXfer, rCMD(a3) ; load Transfer cmd byte in CMD regr
|
||
|
eieio
|
||
|
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
|
||
|
bne UnexpectedDisc ; bus free? -> exit
|
||
|
|
||
|
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
|
||
|
and.b int_rFIFOflags(A5), D1 ; are there bytes still in the FIFO?
|
||
|
beq.w @selComplete ; no -> select is complete
|
||
|
bra.s @selIncompleteCommand ; yes-> sent too few Command bytes
|
||
|
|
||
|
|
||
|
;—————————————————————————————————————————————————————————
|
||
|
;
|
||
|
; If we aren't supposed to Select w/Atn, then we don't have any message bytes
|
||
|
; to send
|
||
|
;
|
||
|
@useNoAtnSel
|
||
|
bsr MoveCDBintoFIFO
|
||
|
bmi @getBusInt ; if we got an int, go check it out
|
||
|
|
||
|
RecCmd $41, 'A',$0c
|
||
|
move.b #cSelWOATN, rCMD(a3) ; issue Select w/o Atn cmd (non-DMA)
|
||
|
eieio
|
||
|
|
||
|
|
||
|
;—————————————————————————————————————————————————————————
|
||
|
|
||
|
@SelStarted
|
||
|
jsrv jvWt4SelectComplete, A2 ; wt 4 something to happen
|
||
|
bne.w @selectDidnt ; reselect/bus free -> didn't select
|
||
|
|
||
|
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
|
||
|
and.b int_rFIFOflags(A5), D1 ; are there bytes still in the FIFO?
|
||
|
beq.w @selComplete
|
||
|
|
||
|
tst.b HALactionPB.sendCDB(A4)
|
||
|
beq.s @selIncompleteMsg
|
||
|
|
||
|
sub.b scsiCDBLength(A0), D1 ; how does fifo count compare to cdb len?
|
||
|
beq.s @selNoCommand ; same? -> no command
|
||
|
bcs.s @selIncompleteCommand ; cdb>fifo count? -> incomplete cmd
|
||
|
|
||
|
@selIncompleteMsg
|
||
|
sub.w D1, HALactionPB.msgOutLen(A4) ; calc xferred bytes
|
||
|
@selIncMsgNoCalc
|
||
|
IF ERR_RECORD_ON THEN
|
||
|
move.l D0, -(sp)
|
||
|
pea 'Err!'
|
||
|
move.l #'msg0', D0
|
||
|
add.b HALactionPB.msgOutLen(A4), D0
|
||
|
move.l D0, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
move.l (sp)+, D0
|
||
|
ENDIF
|
||
|
move.w #HALresult.kHALpartialMsgOut, HALactionPB.result(A4)
|
||
|
bra.s @exitWFlush
|
||
|
@selIncompleteCommand
|
||
|
IF ERR_RECORD_ON THEN
|
||
|
pea 'Err!'
|
||
|
pea 'cmdx'
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
move.w #HALresult.kHALpartialCommand, HALactionPB.result(A4)
|
||
|
bra.s @exitWFlush
|
||
|
@selNoCommand
|
||
|
IF ERR_RECORD_ON THEN
|
||
|
pea 'Err!'
|
||
|
pea 'cmd0'
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
move.w #HALresult.kHALnoCommand, HALactionPB.result(A4)
|
||
|
@exitWFlush
|
||
|
RecCmd $01, 'A',$0e
|
||
|
move.b #cFlushFIFO, rCMD(A3) ; yes - get rid of them
|
||
|
eieio
|
||
|
@selectDidnt
|
||
|
@selComplete
|
||
|
@exit
|
||
|
rts
|
||
|
|
||
|
@getBusInt
|
||
|
jsrv jvHandleBusInt, A2
|
||
|
rts
|
||
|
|
||
|
|
||
|
;———————————————————
|
||
|
|
||
|
|
||
|
NAME 'DoInitiate'
|
||
|
|
||
|
|
||
|
|
||
|
;——————————————————————————————————————————————————————————————————————————————————————
|
||
|
;———————————————————————————————————————————
|
||
|
|
||
|
Wt4SelectComplete
|
||
|
|
||
|
bsr InitDataStuff ; set up saved and current data pointers
|
||
|
;
|
||
|
; OK - first we need to setup any buffers for DMA
|
||
|
;
|
||
|
; The reason we are setting up the buffers here instead of somewhere else is that a select will typically
|
||
|
; take a fair amount of time. Instead of giving that time back to the client we will use it to do a lock
|
||
|
; memory. This optimizes for transaction performance rather than asynchronicity. <SM8>
|
||
|
;
|
||
|
move.l A0, -(sp) ; pb that gets setup
|
||
|
jsrv jvSetupIO, A2
|
||
|
move.l (sp)+, A0 ; get rid of parm and restore A0
|
||
|
|
||
|
|
||
|
;————————————————————————
|
||
|
HandleBusInt
|
||
|
|
||
|
; Check for an int - either Disconnected (fld select) or Bus Service/Func. Cmplt (good select)
|
||
|
|
||
|
bsr Wt4SCSIInt
|
||
|
;
|
||
|
; We got an interrupt, it means that the select command is complete. Either the target did
|
||
|
; not respond (i.e. didn't exist) or it was selected and either finished the message out
|
||
|
; and command phases then saw a REQ or it went to an unexpected phase. (OR A RESELECT !)
|
||
|
;
|
||
|
cmp.b #mFuncComplete+mBusService, int_rINT(A5) ; was interrupt a FuncComplete/BusService ?
|
||
|
bne.s @ck4reselect ; no -> check disconnect, reselect etc.
|
||
|
|
||
|
@exitDidSelect
|
||
|
moveq.l #0, D0 ; yes: successful select
|
||
|
rts
|
||
|
|
||
|
|
||
|
;——— Was it a Reconnect (during select)?
|
||
|
@ck4reselect
|
||
|
btst #bReselected, int_rINT(A5) ; was it a Reselect?
|
||
|
beq.s @1
|
||
|
bsr Ck4SCSIInt ; check for another int (in case of illegal cmd)
|
||
|
|
||
|
move.b #cFlushFIFO, rCMD(A3) ; wipe misc. msg and CDB that we stuffed
|
||
|
eieio
|
||
|
jsrv jvGetReconnectInfo, A2
|
||
|
@exitDidntSelect
|
||
|
moveq.l #1, D0 ; didn't select result code
|
||
|
rts
|
||
|
|
||
|
;——— Was it a bus-initiated Select (during our select)?
|
||
|
@1 btst #bSelected, int_rINT(A5) ; selected int?
|
||
|
beq.s @2
|
||
|
jsrv jvGetReconnectInfo, A2
|
||
|
bra.s @exitDidntSelect
|
||
|
|
||
|
;——— Was it a failed select? (i.e. a disconnect interrupt)
|
||
|
@2 btst #bDisconnected, int_rINT(A5) ; (i.e. timed-out then bus free)
|
||
|
beq.s @unknownInt
|
||
|
|
||
|
move.w #HALresult.kHALselectFld, HALactionPB.result(A4) ; select timeout
|
||
|
bra.s @exitDidntSelect
|
||
|
|
||
|
;——— It was an unknown interrupt
|
||
|
@unknownInt
|
||
|
DebugStr 'Unknown interrupt on Initiate'
|
||
|
bra.s @exitDidSelect
|
||
|
|
||
|
RTSNAME 'Wt4SelectComplete'
|
||
|
|
||
|
|
||
|
;———————————————————————————————————————————
|
||
|
|
||
|
MoveCDBintoFIFO
|
||
|
move.l SCSI_IO.scsiFlags(A0), D0
|
||
|
and.l #scsiCDBIsPointer, D0
|
||
|
beq.s @CDBisReal
|
||
|
move.l scsiCDB(A0), A1 ; get CDB from io pb
|
||
|
bra.s @moveBytes
|
||
|
@CDBisReal
|
||
|
lea.l scsiCDB(A0), A1 ; get CDB from io pb
|
||
|
@moveBytes
|
||
|
moveq.l #0, D0 ; clear upper part of D0 for dbra
|
||
|
move.b scsiCDBLength(A0), D0 ; get len of CDB from io pb
|
||
|
IF RECORD_ON THEN
|
||
|
move.l 0(A1),-(sp) ; CDB bytes 0-3
|
||
|
move.l 4(A1),-(sp) ; CDB bytes 4-7
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
|
||
|
bra.s @cdbLpBtm
|
||
|
@cdbLoop
|
||
|
move.b (A1)+, rFIFO(a3)
|
||
|
@cdbLpBtm
|
||
|
move.b rSTA(A3), D1 ; interrupt?
|
||
|
dbmi D0, @cdbLoop ; if so, fall thru, else, dec and bra
|
||
|
|
||
|
eieio
|
||
|
rts ; <SM5> pdw from prev
|
||
|
|
||
|
NAME 'MoveCDBintoFIFO'
|
||
|
|
||
|
|
||
|
;——————————————————————————————————————————————————————————————————————————————————————
|
||
|
;
|
||
|
; FUNCTION SCSISelect(TargID:INTEGER): INTEGER;
|
||
|
; (8) (10)
|
||
|
;
|
||
|
; Select the target on the bus. Returns 0 for success, or error.
|
||
|
; Selection can be done with or without the ATN line.
|
||
|
;
|
||
|
|
||
|
DoSelect
|
||
|
|
||
|
; Set up chip for select process (init dest ID)
|
||
|
|
||
|
move.b scsiDevice.targetID(A0), rDID(A3) ; tell chip which target ID to select
|
||
|
; delayed eieio
|
||
|
IF DEBUGGING THEN
|
||
|
tst.b HBAhasPseudoDMA(A5) ; if we have pseudoDMA ...
|
||
|
bne.s @DREQable ;
|
||
|
tst.b HBAhasDMA(A5) ; or real DMA ...
|
||
|
bne.s @DREQable ; ... use this routine
|
||
|
|
||
|
IfDebugStr 'bad hwDesc - no DMA or pDMA'
|
||
|
moveq #dsIOCoreErr, D0
|
||
|
_SysError
|
||
|
|
||
|
@DREQable
|
||
|
ENDIF
|
||
|
|
||
|
cmp.w #scsiSelAtn, scsiSelector(A0) ; Select w/Atn?
|
||
|
beq.s @withAtn ; yes->set up for msg byte expected
|
||
|
|
||
|
; If Select w/o Atn then set up for 2 DMA bytes (last bytes of command block) and start process
|
||
|
|
||
|
@withoutATN
|
||
|
eieio
|
||
|
move.b #NeedCmdSent, G_State96(A5) ; flag=expect to see a COMMAND phase next
|
||
|
clr.b rXCM(a3) ; tell chip that we will be sending 2
|
||
|
move.b #2, rXCL(a3) ; DMA bytes (in command phase)
|
||
|
move.b #kCommandPhase, currentPhase(A5) ; fake out command phase
|
||
|
|
||
|
RecCmd $c1, 'A',$10
|
||
|
move.b #cDMASelWOAtn, rCMD(a3) ; issue Select w/o Atn cmd
|
||
|
eieio
|
||
|
bra.s @0
|
||
|
|
||
|
; If Select w/Atn then set up for 2 DMA bytes (msg_out byte + last byte of command block)
|
||
|
|
||
|
@withATN
|
||
|
eieio
|
||
|
move.b #NeedMsgOut, G_State96(A5) ; flag=expect to see a MESSAGE_OUT phase next
|
||
|
clr.b rXCM(a3) ; tell chip that we will be sending 1
|
||
|
move.b #2, rXCL(a3) ; DMA bytes (1 in msg_out, 2 in command)
|
||
|
move.b #kMessageOutPhase, currentPhase(A5) ; fake out MessageOut phas
|
||
|
|
||
|
RecCmd $c2, 'A',$12
|
||
|
move.b #cDMASelWAtn, rCMD(a3) ; issue Select w/ Atn cmd
|
||
|
eieio
|
||
|
@0
|
||
|
|
||
|
|
||
|
; Set up >512mS timeout for select operation to get somewhere (probably more like 4 seconds)
|
||
|
|
||
|
moveq.l #0, d1 ; clear upper word
|
||
|
move.w TimeSCSIDB, d1 ; get # of DBRAs
|
||
|
lsl.l #8, d1 ; multiply by 256
|
||
|
move.l d1, d2 ; 4-16 sec wait for overall watchdog
|
||
|
swap d2
|
||
|
|
||
|
|
||
|
; We have told the chip to start it, now we wait for an indication that it has completed a
|
||
|
; selection. Several things can happen:
|
||
|
; - the target at the requested ID may not exist or may not respond to the select. In
|
||
|
; this case we will receive a Disconnect interrupt from the chip.
|
||
|
; - the target may select OK but go into something other than Command Phase (if Sel w/o Atn)
|
||
|
; or Message_Out Phase (if Sel w/Atn). Here we will see a Function Complete/Bus Service
|
||
|
; interrupt.
|
||
|
; - the target may select OK and go into the expected Phase - the SUCCESS case. When this
|
||
|
; happens, the chip will assert DREQ because it wants the Command (or Msg_Out) byte.
|
||
|
; - the bus may be hung and the chip is unable to arbitrate. We detect this by timing
|
||
|
; out on the whole process.
|
||
|
;
|
||
|
; So basically, this is a 3-way wait for:
|
||
|
; 1) DREQ asserted
|
||
|
; 2) interrupt
|
||
|
; 3) loop timed out
|
||
|
|
||
|
;———————————————————
|
||
|
@waitLoop
|
||
|
; Check for a REQ from the target (within valid phase)
|
||
|
bsr Ck4DREQ ; DREQ?
|
||
|
bne.s @gotDREQ ; yes-> we have a REQ for MsgOut or Cmd byte
|
||
|
|
||
|
; Check for an int - Disconnected, good select, reselected or selected
|
||
|
tst.b gotInt(A5) ; check for an int
|
||
|
bne.s @doneWithSel ;
|
||
|
tst.b rSTA(A3) ; interrupt?
|
||
|
dbmi D1, @waitLoop ;
|
||
|
dbmi D2, @waitLoop ; loop until count exhausted or intrp detected
|
||
|
; count is up or intrp detected so we're outta' here
|
||
|
bpl.s @timedOut ; if not interrupt
|
||
|
|
||
|
;———————————————————
|
||
|
|
||
|
; If we got an interrupt, it means that the select command is complete. Either the target did
|
||
|
; not respond (i.e. didn't exist) or it was selected but went to an unexpected phase.
|
||
|
|
||
|
@doneWithSel ; got an interrupt
|
||
|
clr.b G_State96(A5) ; not waiting for anything
|
||
|
|
||
|
jsrv jvHandleBusInt, A2
|
||
|
rts
|
||
|
|
||
|
;———
|
||
|
@gotDREQ
|
||
|
bsr InitDataStuff ; set up saved and current data pointers
|
||
|
rts
|
||
|
|
||
|
NAME 'Select'
|
||
|
|
||
|
|
||
|
;———————————————————
|
||
|
|
||
|
@timedOut
|
||
|
IF ERR_RECORD_ON THEN
|
||
|
pea 'STmO'
|
||
|
move.w busID(A5), -(sp)
|
||
|
move.w int_rINT(A5), -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
move.w #scArbNBErr, HALactionPB.result(A4) ; arbitration timeout (1/2 second or so)
|
||
|
|
||
|
;
|
||
|
; Check for CURIO Target mode bug (where it goes into DMA mode halfway through
|
||
|
; receiving the command bytes.
|
||
|
;
|
||
|
cmp.b #$0a, rSTA(A3) ; cmd_xfer_cmplt + cmd phz
|
||
|
bne.s @exit ; not same value -> not the bug
|
||
|
cmp.b #$30, rFIFOflags(A3) ; no bytes in FIFO
|
||
|
bne.s @exit
|
||
|
cmp.b #$c1, rSQS(A3) ; sequence step == C1
|
||
|
bne.s @exit
|
||
|
cmp.b #$c1, rCMD(A3) ; last command was our DMA select
|
||
|
bne.s @exit
|
||
|
|
||
|
IfDebugStr 'AMD shines again!'
|
||
|
|
||
|
IF ERR_RECORD_ON THEN
|
||
|
pea 'Err!'
|
||
|
pea 'AMD!'
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
bsr AsmInit53c9xHW ; reset this chip and start over!
|
||
|
move.b #kBusFreePhase, currentPhase(A5)
|
||
|
move.w #HALresult.kHALselectedAsTargetFld, HALactionPB.result(A4) ; select timeout
|
||
|
@exit
|
||
|
rts
|
||
|
|
||
|
NAME 'DoSelect_excptns'
|
||
|
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; Send Command.
|
||
|
;
|
||
|
; A0, A3, A5 - usual HAL conventions
|
||
|
;
|
||
|
; Sends the CDB bytes that are specified in the IOpb (A0). There are two ways of
|
||
|
; doing this, depending on whether we are working on an old API or new API transaction.
|
||
|
; In both cases, we stuff all of the CDB except 2 bytes and then, depending on whether
|
||
|
; it's old or new, we do different things for the last two bytes - see details below.
|
||
|
;
|
||
|
;
|
||
|
|
||
|
DoCommand
|
||
|
;---- Load the FIFO with ALMOST all of the bytes
|
||
|
|
||
|
@sendBytes
|
||
|
move.l SCSI_IO.scsiFlags(A0), D0
|
||
|
and.l #scsiCDBIsPointer, D0
|
||
|
beq.s @CDBisReal
|
||
|
move.l scsiCDB(A0), A1 ; get CDB from io pb
|
||
|
bra.s @1
|
||
|
@CDBisReal
|
||
|
lea.l scsiCDB(A0), A1 ; get CDB from io pb
|
||
|
@1
|
||
|
moveq.l #0, D2 ; clear upper part of D2 for dbra
|
||
|
move.b scsiCDBLength(A0), D2 ; get len of CDB from io pb
|
||
|
subq.l #2, D2 ; adjust for DMA of last bytes
|
||
|
bge.s @btmLoadFIFO ; bra to dbra for zero case (2 byte CDB)
|
||
|
bra @oneByteCDB
|
||
|
@loadFIFO ; loading the FIFO w/o pseudo-DMA will simulate
|
||
|
move.b (A1)+, rFIFO(A3) ; preloading of the FIFO...we then pDMA the
|
||
|
@btmLoadFIFO ;
|
||
|
dbra D2, @loadFIFO
|
||
|
eieio
|
||
|
|
||
|
;---- send the last 2 bytes
|
||
|
|
||
|
@oldAPIorNewAPI
|
||
|
tst.b G_State96(A5) ; are we doing a Select operation?
|
||
|
beq @newAPIcmd ; no -> new API: rFIFO last 2, IOXfer
|
||
|
; yes: old API: rDMA(), no cmd
|
||
|
|
||
|
;————— Old API Last 2 bytes ————————————————
|
||
|
;
|
||
|
;---- Handle the Select operation that's in progress
|
||
|
|
||
|
; If the NeedCmdSent condition is true, that means that we are in the middle of an old-API
|
||
|
; transaction which means that we are sitting right in the middle of a c96 SelW(O)Atn
|
||
|
; process which means that all we have to do is stuff the last two bytes into the FIFO
|
||
|
; with pseudo-DMA or real DMA. No command needs to be issued to the c96 since it is
|
||
|
; working on the Select command.
|
||
|
;
|
||
|
@lastCmdBytes
|
||
|
tst.b HBAhasPseudoDMA(A5)
|
||
|
beq.s @ck4hasDMA
|
||
|
move.w (A1)+, rDMA(A3) ; Use Pseudo DMA to load last bytes
|
||
|
bra.s @sentAll
|
||
|
eieio
|
||
|
|
||
|
@ck4hasDMA
|
||
|
tst.b HBAhasDMA(A5)
|
||
|
bne.s @hasDMA
|
||
|
|
||
|
IfDebugStr 'Bad hwDesc - no DMA or pDMA'
|
||
|
moveq #dsIOCoreErr, D0
|
||
|
_SysError
|
||
|
|
||
|
@hasDMA
|
||
|
move.w (a1)+, ([logicalCopyBuffer,A5]) ; put last bytes into our DMA buffer
|
||
|
|
||
|
move.w #false, -(sp) ; false = out
|
||
|
move.l #2, -(sp)
|
||
|
move.l physicalCopyBuffer(A5), -(sp)
|
||
|
jsr ([jvStartDMA,A5])
|
||
|
lea 10(sp), sp
|
||
|
jsr ([jvWt4DMAComplete,A5])
|
||
|
@sentAll
|
||
|
move.b #FCIntPend,G_State96(A5) ; now we can expect a FunctionCmplt interrupt
|
||
|
|
||
|
;---- Wait for either FIFO empty (c96 sent the bytes) or an interrupt (target bailed early)
|
||
|
|
||
|
@wt4EmptyOrInt
|
||
|
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
|
||
|
and.b rFIFOflags(A3), D1 ; how many bytes left in FIFO?
|
||
|
beq.s @wt4int ; if none, return out to caller, we'll wait
|
||
|
; for int at start of next call (in XPT)
|
||
|
bsr Ck4SCSIInt ; if not empty, did we get an interrupt?
|
||
|
beq.s @wt4EmptyOrInt
|
||
|
|
||
|
; Did we send all the bytes?
|
||
|
moveq.l #mFIFOCount, D1 ; use mask to get FIFO flag field
|
||
|
and.b rFIFOflags(A3), D1 ; how many bytes left in FIFO?
|
||
|
beq.s @gotSelInt ; ->if none then we're cool
|
||
|
|
||
|
RecCmd $01, 'A',$83
|
||
|
move.b #cFlushFIFO, rCMD(a3) ; if bytes in FIFO, wipe them out
|
||
|
|
||
|
cmp.b #1, D1 ; check for c96 FIFO-gets-stuck bug
|
||
|
beq.s @gotSelInt ; ->if 1 then we're cool too (probably)
|
||
|
bra.s @phaseErr ; if >1 byte left, then target bailed early
|
||
|
|
||
|
@wt4int ; <L2> pdw
|
||
|
;---- Wait till we get an interrupt (indicating a REQ beyond Command Phz)
|
||
|
bsr.w Wt4SCSIInt
|
||
|
|
||
|
@gotSelInt
|
||
|
;
|
||
|
; We have to flush the FIFO because of another bug in the c96 where it leaves a byte
|
||
|
; in the FIFO (or at least the count is nonzero) after a cSelWOAtn operation (that
|
||
|
; was sent during a SCSISelect call). This caused a later SCSIComplete
|
||
|
; to read in a bogus Status byte before reading in the real Status byte (which was
|
||
|
; thought to be the Message byte). The null Status byte is usually OK on hard disks and
|
||
|
; such but when polling for a CD-ROM, we are supposed to be getting 02 (check condition)
|
||
|
; and when the CD-ROM driver sees a null, it posts a bogus DiskInsert event.
|
||
|
;
|
||
|
@flushAndExit
|
||
|
RecCmd $01, 'A',$86
|
||
|
move.b #cFlushFIFO, rCMD(A3) ; Flush FIFO - REMEMBER THE CD-ROM BUG!!!
|
||
|
eieio
|
||
|
@noErrRet
|
||
|
clr.b G_State96(A5) ; not waiting for anything
|
||
|
cmp.b #kBusFreePhase, currentPhase(A5)
|
||
|
beq UnexpectedDisc ; bus free? -> exit
|
||
|
rts
|
||
|
|
||
|
|
||
|
;————— New API Last 2 bytes ————————————————
|
||
|
;
|
||
|
; If we didn't have the NeedCmdSent condition, that means that we aren't doing an old-API
|
||
|
; transaction which means that we aren't sitting in the middle of a c96 cSelectWOAtn
|
||
|
; process. This means that we need to stuff the last two bytes into the FIFO using the
|
||
|
; regular byte-wide rFIFO register (not DMA) and issue a cIOXfer command to the c96 to
|
||
|
; actually send the whole FIFO full of CDB bytes.
|
||
|
;
|
||
|
@newAPIcmd
|
||
|
move.b (a1)+, rFIFO(A3) ; load last 2 bytes
|
||
|
move.b (a1)+, rFIFO(A3)
|
||
|
eieio
|
||
|
RecCmd $10, 'A',$13
|
||
|
move.b #cIOXfer, rCMD(A3) ; issue IOXfer command
|
||
|
eieio
|
||
|
bra.s @wt4int
|
||
|
|
||
|
RTSNAME 'DoCommand'
|
||
|
|
||
|
|
||
|
;————— Exceptions ————————————————
|
||
|
|
||
|
@oneByteCDB
|
||
|
move.b (a1), d0
|
||
|
lsl.w #8, D0
|
||
|
move.b (a1), d0 ;_debugger CAN't DO THIS ON A CYCLONE!!!!%%%
|
||
|
move.w D0, rDMA(a3) ; Use Pseudo DMA to load only byte
|
||
|
; do a word to satisfy c96's DMA counter
|
||
|
eieio
|
||
|
bra.s @sentAll
|
||
|
|
||
|
@phaseErr
|
||
|
IF ERR_RECORD_ON THEN
|
||
|
pea 'Err!'
|
||
|
pea 'CPz2'
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
@2
|
||
|
moveq.l #scPhaseErr, d0 ; no error
|
||
|
move.w D0, HALactionPB.result(A4) ; with whatever err
|
||
|
bra.s @flushAndExit
|
||
|
|
||
|
RTSNAME 'DoCommand_excptns'
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; FUNCTION SCSIComplete(VAR Stat, Message: INTEGER; wait:LongInt): INTEGER;
|
||
|
; (16) (12) (8) (20)
|
||
|
;
|
||
|
; Complete the SCSI command by:
|
||
|
; 1) Sending command complete sequence byte to get status & msg bytes from target
|
||
|
; 2) Sending message accepted command to complete the cycle
|
||
|
;
|
||
|
; Return Codes:
|
||
|
; noErr, scCommErr, scPhaseErr, scComplPhaseErr
|
||
|
|
||
|
DoStatus
|
||
|
DoComplete
|
||
|
@chkPhase
|
||
|
cmpi.b #kStatusPhase, currentPhase(A5) ; are we in status phase?
|
||
|
beq.s @inStatusPhase ;
|
||
|
|
||
|
cmp.b #kBusFreePhase, currentPhase(A5)
|
||
|
beq @scsiComplPhaseErr ;
|
||
|
|
||
|
@notInStatusPhase ; only called for Complete phase errors
|
||
|
bsr CyclePhase
|
||
|
bra.s @chkPhase
|
||
|
|
||
|
@inStatusPhase
|
||
|
RecCmd $11, 'A',$14
|
||
|
move.b #cCmdComplete, rCMD(a3) ; load cmd complete code
|
||
|
eieio
|
||
|
bsr Ck4SCSIInt ; Check for intrp
|
||
|
bne.s @gotStatus ; got it -> good
|
||
|
bsr Ck4SCSIInt ; Check for intrp
|
||
|
bne.s @gotStatus ; got it -> good
|
||
|
bsr Wt4SCSIInt ; no, try again and wait for it
|
||
|
@gotStatus
|
||
|
move.b rFIFO(a3), D2 ; read status byte from FIFO
|
||
|
move.b D2, scsiSCSIstatus(A0) ; return status byte
|
||
|
|
||
|
moveq.l #mFIFOCount, d1 ; use mask to get FIFO flag field
|
||
|
and.b rFIFOflags(a3), d1 ; bytes left in FIFO?
|
||
|
bne.s @gotMsg ; ->if so, it's the message byte
|
||
|
cmp.b #kBusFreePhase, currentPhase(A5) ;
|
||
|
beq.s @scsiComplPhaseErr
|
||
|
@gotMsg
|
||
|
move.b rFIFO(A3), D2 ; read msg byte from FIFO
|
||
|
move.b D2, scsiSCSImessage(A0) ; and return message byte in PB also
|
||
|
move.b #1, HALactionPB.msgInLen(A4) ; say we returned 1 byte
|
||
|
|
||
|
RecCmd $12, 'A',$16
|
||
|
move.b #cMsgAccept, rCMD(a3) ; load msg accepted code which de-asserts *ACK
|
||
|
eieio
|
||
|
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
|
||
|
@check4BusFree
|
||
|
cmp.b #kBusFreePhase, currentPhase(A5)
|
||
|
beq.s @disconnected ; if disconnected -> we're done
|
||
|
@badAcpt
|
||
|
bsr Ck4SCSIInt ; Check for intrp (bouncy REQ)
|
||
|
bne.s @check4BusFree ; got it -> go back to check for busfree
|
||
|
@scsiComplPhaseErr
|
||
|
move.w #SCResults.scsiSequenceFailed, D0 ; bad
|
||
|
@exitComplete
|
||
|
move.w D0, HALactionPB.result(A4) ; with whatever err
|
||
|
@disconnected ;
|
||
|
rts
|
||
|
|
||
|
NAME 'DoSCSIComplete'
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; CyclePhase -- we may have to discard data or write filler bytes to get to
|
||
|
; the desired phase, status phase.
|
||
|
;
|
||
|
; This routine is broken into two main sections; standard I/O and Pseudo-DMA. The DMA
|
||
|
; sequence is used in case we are in the middle of a failed DMA transfer which left the
|
||
|
; transfer count nonzero. We only have to handle Pseudo-DMA in data phase. All other
|
||
|
; phases (and normal I/O mode data phase) are handled 1 byte at a time by individual
|
||
|
; phase handling code with, after each byte, returns to check the next phase to see
|
||
|
; where to go next.
|
||
|
;
|
||
|
; Phase Action
|
||
|
; ————— ——————
|
||
|
; Command: We send as many EE bytes as needed to get out of phase. If the select sequence
|
||
|
; flag 'NeedCmdSent' is set, it turns out that the chip will do the fill by itself
|
||
|
; once we send 1 rDMA byte (thereby completing the transfer) using
|
||
|
; rDMA. We also set the flag 'FCIntPend' bit if 'NeedCmdSent' was set.
|
||
|
;
|
||
|
; Msg_Out: We send as many 08(NOP) bytes as needed to get out of phase. If the select
|
||
|
; sequence flag 'NeedMsgOut' flag is set we set the flag 'NeedCmdSent' and continue.
|
||
|
;
|
||
|
; Data_In: We bitbucket as many bytes as needed to clear phase.
|
||
|
;
|
||
|
; Data_Out: We send as many EE bytes as needed to get out of phase.
|
||
|
;
|
||
|
;
|
||
|
; Note: We need to check if the SCSIMgr is busy in order to differentiate between
|
||
|
; IDLE bus phase and DATA OUT phase. They both have phase value = 0.
|
||
|
;
|
||
|
; Uses: d0
|
||
|
|
||
|
CyclePhase ; (accessed thru jvCyclePhase)
|
||
|
@checkNextPhase ;
|
||
|
move.b currentPhase(A5), d0 ; get phase value
|
||
|
|
||
|
cmp.b #kDataInPhase, d0 ;
|
||
|
beq.s @dumpDataIn ;
|
||
|
|
||
|
cmp.b #kDataOutPhase, d0 ;
|
||
|
beq.s @shoveDataOut ;
|
||
|
|
||
|
cmp.b #kCommandPhase, d0 ;
|
||
|
beq.w @shoveCommand ;
|
||
|
|
||
|
cmp.b #kMessageOutPhase, d0 ;
|
||
|
beq.w @shoveMsgOut ;
|
||
|
|
||
|
cmp.b #kMessageInPhase, d0 ;
|
||
|
beq.w @bitbucketMsgIn ;
|
||
|
|
||
|
cmp.b #kStatusPhase, d0 ;
|
||
|
bne.s @xferErr
|
||
|
@okExit
|
||
|
move.w #scComplPhaseErr, d0 ; tell SCSIComplete we had to read/write junk
|
||
|
rts ; err code is saved
|
||
|
|
||
|
@xferErr ;
|
||
|
clr.l d0 ; no recovery
|
||
|
rts
|
||
|
|
||
|
NAME 'CyclePhaseTOP'
|
||
|
|
||
|
;
|
||
|
; Data Phases - note that we no longer support the (pseudo) DMA bitbucketing here because
|
||
|
; the buserr handler should completely clean itself up before exiting out of the data
|
||
|
; routine/call.
|
||
|
;
|
||
|
; Data_In ------
|
||
|
;
|
||
|
@dumpDataIn
|
||
|
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
|
||
|
move.b rFIFO(A3), D0 ; just empty the FIFO
|
||
|
bra.s @checkNextPhase
|
||
|
|
||
|
;
|
||
|
; Data_Out ------
|
||
|
;
|
||
|
@shoveDataOut
|
||
|
; DebugStr 'Old API bitbucketing'
|
||
|
move.b #$EE, rFIFO(a3) ; load filler byte into FIFO
|
||
|
eieio
|
||
|
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
|
||
|
bra.s @checkNextPhase
|
||
|
|
||
|
|
||
|
;
|
||
|
; Command ------
|
||
|
;
|
||
|
@shoveCommand
|
||
|
tst.b G_State96(A5) ; did we expect this?
|
||
|
beq.s @cmdNonDMA ; no - bra, do xfer using FIFO
|
||
|
|
||
|
tst.b HBAhasPseudoDMA(A5)
|
||
|
beq.s @ck4hasDMA
|
||
|
move.w #$EEEE, rDMA(a3) ; use pseudo DMA (since chip is waiting for it)
|
||
|
eieio
|
||
|
bra.s @sentCmd
|
||
|
|
||
|
@ck4hasDMA
|
||
|
tst.b HBAhasDMA(A5)
|
||
|
bne.s @hasDMA
|
||
|
|
||
|
IfDebugStr 'Bad hwDesc - no DMA or pDMA'
|
||
|
moveq #dsIOCoreErr, D0
|
||
|
_SysError
|
||
|
|
||
|
@hasDMA
|
||
|
move.w #$EEEE, ([logicalCopyBuffer,A5]) ; put last bytes into our DMA buffer
|
||
|
|
||
|
move.w #false, -(sp) ; false = out
|
||
|
move.l #2, -(sp) ; send 2 bytes
|
||
|
move.l physicalCopyBuffer(A5), -(sp) ; starting at this physical address
|
||
|
jsr ([jvStartDMA,A5])
|
||
|
lea 10(sp), sp
|
||
|
jsr ([jvWt4DMAComplete,A5])
|
||
|
|
||
|
@sentCmd
|
||
|
bsr.w Wt4SCSIInt
|
||
|
;
|
||
|
; We have to flush the FIFO because of a bug in the c96. See the DoCommand routine for
|
||
|
; further information
|
||
|
;
|
||
|
@flushAndExit
|
||
|
RecCmd $01, 'A',$17
|
||
|
move.b #cFlushFIFO, rCMD(A3) ; Flush FIFO - REMEMBER THE CD-ROM BUG!!!
|
||
|
eieio
|
||
|
clr.b G_State96(A5)
|
||
|
bra.w @checkNextPhase
|
||
|
|
||
|
@cmdNonDMA
|
||
|
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
|
||
|
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
|
||
|
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
|
||
|
move.b #$EE, rFIFO(A3) ; load filler byte into FIFO
|
||
|
eieio
|
||
|
bsr Xfer1Byte96 ; send cmd and wait for intrp w/o timeout
|
||
|
bra.s @flushAndExit
|
||
|
|
||
|
|
||
|
;
|
||
|
; Message_Out ------
|
||
|
;
|
||
|
@shoveMsgOut
|
||
|
tst.b G_State96(A5) ; are we in cSelW(O)Atn process?
|
||
|
bne.s @ck4hasDMA ; yes-> go to cmd phase routine
|
||
|
move.b #$08, rFIFO(A3) ; load filler byte into FIFO (NOP message)
|
||
|
eieio
|
||
|
@needXferCmd
|
||
|
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
|
||
|
bra.w @checkNextPhase
|
||
|
|
||
|
|
||
|
;
|
||
|
; Message-In ------
|
||
|
;
|
||
|
@bitbucketMsgIn
|
||
|
bsr Xfer1Byte96 ; xfer 1 byte and wait for intrp w/o timeout
|
||
|
move.b rFIFO(A3), D0 ; just empty the FIFO
|
||
|
|
||
|
RecCmd $12, 'A',$18
|
||
|
move.b #cMsgAccept, rCMD(a3) ; load msg accepted code which de-asserts ACK
|
||
|
eieio
|
||
|
|
||
|
bsr Wt4SCSIInt ; Wait for intrp w/o timeout
|
||
|
|
||
|
bra.w @checkNextPhase
|
||
|
|
||
|
|
||
|
RTSNAME 'CyclePhaseBOTTOM'
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; AutoMsgIn
|
||
|
;
|
||
|
; Get message in bytes. If a HAL-recognized message, do what we need to do then
|
||
|
; return to caller (HALaction). If not, put entire message into buffer - either
|
||
|
; 2 bytes if msg=$2x, or extended message if 1st msg=01 (2+length bytes), or 1
|
||
|
; byte.
|
||
|
;
|
||
|
; Note: This routine, not being a HALaction proper, is not allowed to return an
|
||
|
; error in HALaction.result!
|
||
|
;
|
||
|
AutoMsgIn
|
||
|
@0
|
||
|
RecCmd $10, 'A',$24
|
||
|
move.b #cIOXfer, rCMD(A3)
|
||
|
eieio
|
||
|
bsr Wt4SCSIInt
|
||
|
bne UnexpectedDisc ; bus free? -> exit
|
||
|
|
||
|
moveq.l #0, D0
|
||
|
move.b rFIFO(A3), D0 ; retrieve first message from FIFO
|
||
|
|
||
|
IF RECORD_ON THEN
|
||
|
pea 'AMsg'
|
||
|
move.l D0, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
|
||
|
;
|
||
|
; Check for a one byte message that we recognize.
|
||
|
;
|
||
|
@ck4SaveDP
|
||
|
cmp.b #kSaveDataPointerMsg, D0
|
||
|
bne.s @ck4RestoreDP
|
||
|
|
||
|
RecCmd $12, 'A',$28
|
||
|
move.b #cMsgAccept, rCMD(A3) ; de-assert ACK
|
||
|
eieio
|
||
|
|
||
|
jsrv jvSaveDataPointer, A1 ;
|
||
|
bra.s @wt4acceptComp
|
||
|
|
||
|
@ck4RestoreDP
|
||
|
cmp.b #kRestorePointersMsg, D0
|
||
|
bne.s @ck4ExtendedMsg
|
||
|
|
||
|
RecCmd $12, 'A',$2c
|
||
|
move.b #cMsgAccept, rCMD(A3) ; de-assert ACK
|
||
|
eieio
|
||
|
|
||
|
jsrv jvRestorePointers, A1 ;
|
||
|
@wt4acceptComp
|
||
|
bsr Wt4SCSIInt
|
||
|
|
||
|
cmp.b #kMessageInPhase, currentPhase(A5) ; still in msg phase?
|
||
|
beq.w @0 ; yes-> go back and get next msg
|
||
|
bra @outOfPhase ; no: return to SIM w/new phase
|
||
|
|
||
|
;
|
||
|
; Check for extended message
|
||
|
;
|
||
|
@ck4ExtendedMsg
|
||
|
lea HALactionPB.msg(A4), A0
|
||
|
move.b D0, (A0)+ ; put the message in bfr
|
||
|
move.b #1, HALactionPB.msgInLen(A4) ;
|
||
|
|
||
|
cmp.b #kExtendedMsg, D0 ; extended msg?
|
||
|
bne @ck2byteMsg ; no->check 4 2-byte message
|
||
|
|
||
|
;
|
||
|
; Extended Msg: Accept 1st message, get 2nd message byte (length) then, for each
|
||
|
; byte in length, accept previous byte then get the next. This leaves ACK for
|
||
|
; last byte.
|
||
|
;
|
||
|
@get2ndMsg
|
||
|
bsr DoAcceptMsg
|
||
|
|
||
|
cmp.b #kMessageInPhase, currentPhase(A5)
|
||
|
bne @outOfPhase
|
||
|
|
||
|
RecCmd $10, 'A',$30
|
||
|
move.b #cIOXfer, rCMD(A3)
|
||
|
eieio
|
||
|
bsr Wt4SCSIInt
|
||
|
bne UnexpectedDisc ; bus free? -> exit
|
||
|
|
||
|
moveq.l #0, D0
|
||
|
move.b rFIFO(A3), D0 ; retrieve 2nd message from FIFO
|
||
|
move.b D0, (A0)+
|
||
|
bne.s @lpEnd ; non-zero-> byte is # of bytes left
|
||
|
move.w #$100, D0 ; zero-> 256 bytes left
|
||
|
bra.s @lpEnd ; loop: ack prev byte, get next
|
||
|
@lpTop
|
||
|
bsr DoAcceptMsg ; drop ACK, where does phase go?
|
||
|
|
||
|
cmp.b #kMessageInPhase, currentPhase(A5) ; still messageIn?
|
||
|
bne.s @outOfPhase ; no->out of here
|
||
|
|
||
|
RecCmd $10, 'A',$38
|
||
|
move.b #cIOXfer, rCMD(A3) ; get the byte (assert ACK)
|
||
|
eieio
|
||
|
bsr Wt4SCSIInt
|
||
|
bne UnexpectedDisc ; bus free? -> exit
|
||
|
|
||
|
move.b rFIFO(A3), (A0)+ ; retrieve next message from FIFO
|
||
|
addq.b #1, HALactionPB.msgInLen(A4) ;
|
||
|
@lpEnd
|
||
|
dbra D0, @lpTop
|
||
|
|
||
|
IF RECORD_ON THEN
|
||
|
pea 'XMsg'
|
||
|
move.l HALactionPB.msg(A4), -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
@inPhase
|
||
|
move.b #kMessageInPhaseNACK, currentPhase(A5)
|
||
|
@outOfPhase
|
||
|
rts
|
||
|
|
||
|
;
|
||
|
; Check for a 2-byte message - this includes all messages of the form $2x. We don't
|
||
|
; interpret any 2-byte messages in the HAL so just get them and return.
|
||
|
;
|
||
|
@ck2byteMsg
|
||
|
and.b #$F0, D0
|
||
|
cmp.b #$20, D0 ; msg = $2x?
|
||
|
bne.s @inPhase ; no-> we're done
|
||
|
|
||
|
;
|
||
|
; If 2-byte msg, accept 1st byte then get second byte and return to caller
|
||
|
;
|
||
|
bsr.s DoAcceptMsg
|
||
|
|
||
|
cmp.b #kMessageInPhase, currentPhase(A5)
|
||
|
bne.s @outOfPhase
|
||
|
|
||
|
RecCmd $10, 'A',$40
|
||
|
move.b #cIOXfer, rCMD(A3)
|
||
|
eieio
|
||
|
bsr Wt4SCSIInt
|
||
|
bne UnexpectedDisc ; bus free? -> exit
|
||
|
|
||
|
moveq.l #0, D0
|
||
|
move.b rFIFO(A3), (A0)+ ; retrieve next message from FIFO
|
||
|
move.b #2, HALactionPB.msgInLen(A4) ; inc count
|
||
|
bra.s @inPhase
|
||
|
|
||
|
RTSNAME 'AutoMsgIn'
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; AcceptMsg - accept a message
|
||
|
;
|
||
|
DoAcceptMsg
|
||
|
RecCmd $12, 'A',$44
|
||
|
move.b #cMsgAccept, rCMD(A3) ; de-assert ACK
|
||
|
eieio
|
||
|
|
||
|
bsr Wt4SCSIInt
|
||
|
rts ; don't touch result
|
||
|
|
||
|
NAME 'DoAcceptMsg'
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; DoMsgOut - Send a message byte to the target
|
||
|
;
|
||
|
; Send the HALactionPB.msgLen message bytes in HALactionPB.msg[]. Don't change
|
||
|
; result (noErr) if all bytes sent, else, return err and indicate how many bytes
|
||
|
; WEREN'T sent in HALactionPB.msgOutLen. We will only be called if we are IN msg
|
||
|
; out phase already.
|
||
|
;
|
||
|
|
||
|
DoMsgOut
|
||
|
lea HALactionPB.msg(A4), A1 ; where the message is
|
||
|
|
||
|
tst.b G_State96(A5) ; Is this part of an old API Select w/ATN?
|
||
|
bne.s @oldAPI ; yes->
|
||
|
|
||
|
;
|
||
|
; If we didn't send a SelWAtn, then we need to stuff the FIFO full of the message bytes
|
||
|
; that we need to send then issue a xferInfo command which will drop ATN during the
|
||
|
; last byte. Hole: what about more than 16 message out bytes? HA!
|
||
|
;
|
||
|
@needXfer
|
||
|
moveq.l #0, D0
|
||
|
move.b HALactionPB.msgOutLen(A4), D0
|
||
|
bne.s @loopBtm
|
||
|
bra.s @goodExit
|
||
|
@loopTop
|
||
|
move.b (A1)+, rFIFO(A3) ; move msg byte into FIFO
|
||
|
@loopBtm
|
||
|
dbra D0, @loopTop ;
|
||
|
eieio
|
||
|
; now we sent all of the message bytes
|
||
|
|
||
|
RecCmd $10, 'A',$48
|
||
|
move.b #cIOXfer, rCMD(A3) ; load IO transfer cmd & begin xfers
|
||
|
eieio
|
||
|
bsr.w Wt4SCSIInt ; Wait for intrp w/o timeout
|
||
|
|
||
|
moveq.l #mFIFOCount, D0
|
||
|
and.b int_rFIFOflags(A5), D0 ; how many bytes left?
|
||
|
bne.s @phaseChange
|
||
|
@goodExit
|
||
|
rts
|
||
|
|
||
|
|
||
|
;
|
||
|
; If we sent a SelWAtn, we only need to stick the message byte (only 1) into the FIFO.
|
||
|
; The c96 and the target continue from there.
|
||
|
;
|
||
|
@oldAPI
|
||
|
move.b #NeedCmdSent, G_State96(A5) ; we will expect to see command phz
|
||
|
move.b #kCommandPhase, currentPhase(A5) ; pretend like we're there already
|
||
|
|
||
|
move.b (A1), rFIFO(A3) ; xfer msg byte
|
||
|
eieio
|
||
|
bra.s @goodExit ; don't wait for int - CDB needed first
|
||
|
|
||
|
|
||
|
@phaseChange
|
||
|
sub.b D0, HALactionPB.msgOutLen(A4) ; calc how many bytes were xferred
|
||
|
move.w #HALresult.kHALpartialMsgOut, HALactionPB.result(A4)
|
||
|
rts
|
||
|
|
||
|
NAME 'DoMsgOut'
|
||
|
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; SetParity - Set the parity bit in the c96 configuration register2
|
||
|
; so that parity errors will be reported. Note that we
|
||
|
; turn this off at each disconnect to prevent problems on
|
||
|
; reconnects from devices that don't support parity.
|
||
|
;
|
||
|
;
|
||
|
SetParity
|
||
|
IF PARITY_ENABLED THEN
|
||
|
move.l HALactionPB.ioPtr(A4), A0 ; ptr to SCSI_IO pb
|
||
|
move.w SCSI_IO.scsiIOFlags(A0), D0 ; Get the flags field
|
||
|
and.w #scsiNoParityCheck,D0 ; Are we doing parity?
|
||
|
bne.s @noParity ; nope-> don't send an identify message
|
||
|
or.b #mCF1_EnableParity,rCF1(a3) ; set the parity bit
|
||
|
@noParity
|
||
|
ENDIF
|
||
|
rts
|
||
|
|
||
|
NAME 'SetParity'
|
||
|
|
||
|
|
||
|
|
||
|
;################################################################################
|
||
|
;********** Non-HALActions *********
|
||
|
;################################################################################
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; HALSyncConfig - Configure registers for Synchronous Data Transfer
|
||
|
; 4 8 12
|
||
|
; void HALSyncConfig( offset, periodFactor, HALc96Globals * HALg );
|
||
|
;
|
||
|
HALSyncConfig
|
||
|
move.l A3, -(sp)
|
||
|
move.l A5, -(sp)
|
||
|
|
||
|
move.l 20(sp), A5 ; get HALg
|
||
|
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
|
||
|
|
||
|
IF RECORD_ON THEN
|
||
|
pea 'SCfg'
|
||
|
move.w 22(sp), -(sp)
|
||
|
move.w 22(sp), -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
|
||
|
move.l 16(sp), D0 ; get periodFactor
|
||
|
move.b (periodTable, D0.w), D1
|
||
|
bmi.s @illegalValue
|
||
|
and.b #$1f, D1
|
||
|
move.b D1, rSyncPeriod(A3)
|
||
|
|
||
|
cmp.b #50, D0 ; are we in Fast range?
|
||
|
bcc.s @notFast
|
||
|
or.b #mCF3_FastSCSI, rCF3(A3) ; set fast bit
|
||
|
bra.s @1
|
||
|
@notFast
|
||
|
and.b #~mCF3_FastSCSI, rCF3(A3) ; clr fast bit
|
||
|
@1
|
||
|
move.l 12(sp), D1 ; get offset
|
||
|
move.b D1, rSyncOffset(A3)
|
||
|
|
||
|
@illegalValue
|
||
|
move.l (sp)+, A5
|
||
|
move.l (sp)+, A3
|
||
|
rts
|
||
|
|
||
|
NAME 'HALSyncConfig'
|
||
|
|
||
|
|
||
|
;……………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
; set period 25
|
||
|
; loop
|
||
|
; if {period}<100
|
||
|
; echo -n "@0{period} "
|
||
|
; else
|
||
|
; echo -n "@{period} "
|
||
|
; end
|
||
|
; echo -n "dc.b "
|
||
|
; evaluate -h {period}*1000 div 625 div 10
|
||
|
; evaluate period+=1
|
||
|
; break if {period}==256
|
||
|
; end
|
||
|
;
|
||
|
;……………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
periodTable
|
||
|
@0 dc.b $80, $80, $80, $80, $80, $80, $80, $80
|
||
|
@8 dc.b $80, $80, $80, $80, $80, $80, $80, $80
|
||
|
@16 dc.b $80, $80, $80, $80, $80, $80, $80, $80
|
||
|
@24 dc.b $80
|
||
|
|
||
|
@025 dc.b $04
|
||
|
@026 dc.b $04
|
||
|
@027 dc.b $04
|
||
|
@028 dc.b $04
|
||
|
@029 dc.b $04
|
||
|
@030 dc.b $04
|
||
|
@031 dc.b $04
|
||
|
@032 dc.b $05
|
||
|
@033 dc.b $05
|
||
|
@034 dc.b $05
|
||
|
@035 dc.b $05
|
||
|
@036 dc.b $05
|
||
|
@037 dc.b $05
|
||
|
@038 dc.b $06
|
||
|
@039 dc.b $06
|
||
|
@040 dc.b $06
|
||
|
@041 dc.b $06
|
||
|
@042 dc.b $06
|
||
|
@043 dc.b $06
|
||
|
@044 dc.b $07
|
||
|
@045 dc.b $07
|
||
|
@046 dc.b $07 ; -
|
||
|
@047 dc.b $07 ; -
|
||
|
@048 dc.b $07 ; -
|
||
|
@049 dc.b $07 ; Fast SCSI bit set
|
||
|
|
||
|
@050 dc.b $08 ; Fast SCSI bit clr
|
||
|
@051 dc.b $08 ; -
|
||
|
@052 dc.b $08 ; -
|
||
|
@053 dc.b $08 ; -
|
||
|
@054 dc.b $08
|
||
|
@055 dc.b $08
|
||
|
@056 dc.b $08
|
||
|
@057 dc.b $09
|
||
|
@058 dc.b $09
|
||
|
@059 dc.b $09
|
||
|
@060 dc.b $09
|
||
|
@061 dc.b $09
|
||
|
@062 dc.b $09
|
||
|
@063 dc.b $0a
|
||
|
@064 dc.b $0a
|
||
|
@065 dc.b $0a
|
||
|
@066 dc.b $0a
|
||
|
@067 dc.b $0a
|
||
|
@068 dc.b $0a
|
||
|
@069 dc.b $0b
|
||
|
@070 dc.b $0b
|
||
|
@071 dc.b $0b
|
||
|
@072 dc.b $0b
|
||
|
@073 dc.b $0b
|
||
|
@074 dc.b $0b
|
||
|
@075 dc.b $0c
|
||
|
@076 dc.b $0c
|
||
|
@077 dc.b $0c
|
||
|
@078 dc.b $0c
|
||
|
@079 dc.b $0c
|
||
|
@080 dc.b $0c
|
||
|
@081 dc.b $0c
|
||
|
@082 dc.b $0d
|
||
|
@083 dc.b $0d
|
||
|
@084 dc.b $0d
|
||
|
@085 dc.b $0d
|
||
|
@086 dc.b $0d
|
||
|
@087 dc.b $0d
|
||
|
@088 dc.b $0e
|
||
|
@089 dc.b $0e
|
||
|
@090 dc.b $0e
|
||
|
@091 dc.b $0e
|
||
|
@092 dc.b $0e
|
||
|
@093 dc.b $0e
|
||
|
@094 dc.b $0f
|
||
|
@095 dc.b $0f
|
||
|
@096 dc.b $0f
|
||
|
@097 dc.b $0f
|
||
|
@098 dc.b $0f
|
||
|
@099 dc.b $0f
|
||
|
@100 dc.b $10
|
||
|
@101 dc.b $10
|
||
|
@102 dc.b $10
|
||
|
@103 dc.b $10
|
||
|
@104 dc.b $10
|
||
|
@105 dc.b $10
|
||
|
@106 dc.b $10
|
||
|
@107 dc.b $11
|
||
|
@108 dc.b $11
|
||
|
@109 dc.b $11
|
||
|
@110 dc.b $11
|
||
|
@111 dc.b $11
|
||
|
@112 dc.b $11
|
||
|
@113 dc.b $12
|
||
|
@114 dc.b $12
|
||
|
@115 dc.b $12
|
||
|
@116 dc.b $12
|
||
|
@117 dc.b $12
|
||
|
@118 dc.b $12
|
||
|
@119 dc.b $13
|
||
|
@120 dc.b $13
|
||
|
@121 dc.b $13
|
||
|
@122 dc.b $13
|
||
|
@123 dc.b $13
|
||
|
@124 dc.b $13
|
||
|
@125 dc.b $14
|
||
|
@126 dc.b $14
|
||
|
@127 dc.b $14
|
||
|
@128 dc.b $14
|
||
|
@129 dc.b $14
|
||
|
@130 dc.b $14
|
||
|
@131 dc.b $14
|
||
|
@132 dc.b $15
|
||
|
@133 dc.b $15
|
||
|
@134 dc.b $15
|
||
|
@135 dc.b $15
|
||
|
@136 dc.b $15
|
||
|
@137 dc.b $15
|
||
|
@138 dc.b $16
|
||
|
@139 dc.b $16
|
||
|
@140 dc.b $16
|
||
|
@141 dc.b $16
|
||
|
@142 dc.b $16
|
||
|
@143 dc.b $16
|
||
|
@144 dc.b $17
|
||
|
@145 dc.b $17
|
||
|
@146 dc.b $17
|
||
|
@147 dc.b $17
|
||
|
@148 dc.b $17
|
||
|
@149 dc.b $17
|
||
|
@150 dc.b $18
|
||
|
@151 dc.b $18
|
||
|
@152 dc.b $18
|
||
|
@153 dc.b $18
|
||
|
@154 dc.b $18
|
||
|
@155 dc.b $18
|
||
|
@156 dc.b $18
|
||
|
@157 dc.b $19
|
||
|
@158 dc.b $19
|
||
|
@159 dc.b $19
|
||
|
@160 dc.b $19
|
||
|
@161 dc.b $19
|
||
|
@162 dc.b $19
|
||
|
@163 dc.b $1a
|
||
|
@164 dc.b $1a
|
||
|
@165 dc.b $1a
|
||
|
@166 dc.b $1a
|
||
|
@167 dc.b $1a
|
||
|
@168 dc.b $1a
|
||
|
@169 dc.b $1b
|
||
|
@170 dc.b $1b
|
||
|
@171 dc.b $1b
|
||
|
@172 dc.b $1b
|
||
|
@173 dc.b $1b
|
||
|
@174 dc.b $1b
|
||
|
@175 dc.b $1c
|
||
|
@176 dc.b $1c
|
||
|
@177 dc.b $1c
|
||
|
@178 dc.b $1c
|
||
|
@179 dc.b $1c
|
||
|
@180 dc.b $1c
|
||
|
@181 dc.b $1c
|
||
|
@182 dc.b $1d
|
||
|
@183 dc.b $1d
|
||
|
@184 dc.b $1d
|
||
|
@185 dc.b $1d
|
||
|
@186 dc.b $1d
|
||
|
@187 dc.b $1d
|
||
|
@188 dc.b $1e
|
||
|
@189 dc.b $1e
|
||
|
@190 dc.b $1e
|
||
|
@191 dc.b $1e
|
||
|
@192 dc.b $1e
|
||
|
@193 dc.b $1e
|
||
|
@194 dc.b $1f
|
||
|
@195 dc.b $1f
|
||
|
@196 dc.b $1f
|
||
|
@197 dc.b $1f
|
||
|
@198 dc.b $1f
|
||
|
@199 dc.b $1f
|
||
|
@200 dc.b $00
|
||
|
@201 dc.b $00
|
||
|
@202 dc.b $00
|
||
|
@203 dc.b $00
|
||
|
@204 dc.b $00
|
||
|
@205 dc.b $00
|
||
|
@206 dc.b $00
|
||
|
@207 dc.b $01
|
||
|
@208 dc.b $01
|
||
|
@209 dc.b $01
|
||
|
@210 dc.b $01
|
||
|
@211 dc.b $01
|
||
|
@212 dc.b $01
|
||
|
@213 dc.b $02
|
||
|
@214 dc.b $02
|
||
|
@215 dc.b $02
|
||
|
@216 dc.b $02
|
||
|
@217 dc.b $02
|
||
|
@218 dc.b $02
|
||
|
@219 dc.b $03
|
||
|
@220 dc.b $03
|
||
|
@221 dc.b $03
|
||
|
@222 dc.b $03
|
||
|
@223 dc.b $03
|
||
|
@224 dc.b $03
|
||
|
|
||
|
@225 dc.b $84
|
||
|
@226 dc.b $84
|
||
|
@227 dc.b $84
|
||
|
@228 dc.b $84
|
||
|
@229 dc.b $84
|
||
|
@230 dc.b $84
|
||
|
@231 dc.b $84
|
||
|
@232 dc.b $85
|
||
|
@233 dc.b $85
|
||
|
@234 dc.b $85
|
||
|
@235 dc.b $85
|
||
|
@236 dc.b $85
|
||
|
@237 dc.b $85
|
||
|
@238 dc.b $86
|
||
|
@239 dc.b $86
|
||
|
@240 dc.b $86
|
||
|
@241 dc.b $86
|
||
|
@242 dc.b $86
|
||
|
@243 dc.b $86
|
||
|
@244 dc.b $87
|
||
|
@245 dc.b $87
|
||
|
@246 dc.b $87
|
||
|
@247 dc.b $87
|
||
|
@248 dc.b $87
|
||
|
@249 dc.b $87
|
||
|
@250 dc.b $88
|
||
|
@251 dc.b $88
|
||
|
@252 dc.b $88
|
||
|
@253 dc.b $88
|
||
|
@254 dc.b $88
|
||
|
@255 dc.b $88
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; HALResetBus - Reset the scsi bus
|
||
|
;
|
||
|
; void HALResetBus( HALc96Globals * HALg );
|
||
|
;
|
||
|
HALResetBus
|
||
|
move.l A3, -(sp)
|
||
|
move.l A5, -(sp)
|
||
|
|
||
|
move.l 12(sp), A5 ; get HALg
|
||
|
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
|
||
|
|
||
|
; move.w sr, -(sp) ; Block interrupts
|
||
|
; or.w #$0700, sr
|
||
|
|
||
|
IF RECORD_ON THEN
|
||
|
pea 'RstB'
|
||
|
move.l A1, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
|
||
|
jsrv jvResetBus, A1
|
||
|
|
||
|
; move.w (sp)+, sr ; restore interrupt level
|
||
|
|
||
|
move.l (sp)+, A5
|
||
|
move.l (sp)+, A3
|
||
|
rts
|
||
|
|
||
|
NAME 'HALResetBus'
|
||
|
|
||
|
;……………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
;
|
||
|
; DoReset - Reset the scsi bus
|
||
|
;
|
||
|
DoReset
|
||
|
; move.b #initCF1+mResetIntrpDisable, rCF1(A3) ; load init config value which affects:
|
||
|
; busID, SCSI reset reporting & parity checking
|
||
|
eieio
|
||
|
|
||
|
RecCmd $03, 'A',$4c
|
||
|
move.b #cResetSCSIBus, rCMD(A3) ; load reset scsi bus cmd - no int generated
|
||
|
; except that ResetO goes to ResetI which
|
||
|
; DOES generate an interrupt
|
||
|
eieio
|
||
|
;
|
||
|
; Just for the fun of it, we're going to wait 128mS, then reset that CF1 register
|
||
|
; then wait another 128mS and see if we got an interrupt - Just for the heck of it.
|
||
|
;
|
||
|
moveq.l #0, D0 ; clear upper word
|
||
|
move.w TimeDBRA, D0 ; get # of DBRAs per mS
|
||
|
lsl.l #7, D0 ; multiply by 128
|
||
|
move.l D0, D1 ; ...a 128mS wait
|
||
|
swap D1
|
||
|
@1 dbra D0, @1 ; D0 low word of counter
|
||
|
dbra D1, @1 ; D1 high word
|
||
|
|
||
|
; move.b #initCF1, rCF1(A3) ; reload init config value
|
||
|
eieio
|
||
|
|
||
|
moveq.l #0, D0 ; clear upper word
|
||
|
move.w TimeDBRA, D0 ; get # of DBRAs per mS
|
||
|
lsl.l #7, D0 ; multiply by 128
|
||
|
move.l D0, D1 ; ...a 128mS wait
|
||
|
swap D1
|
||
|
@2 dbra D0, @2 ; D0 low word of counter
|
||
|
dbra D1, @2 ; D1 high word
|
||
|
|
||
|
|
||
|
bsr Ck4SCSIInt ; did we get an interrupt?
|
||
|
; Did we? Who cares? I don't.
|
||
|
|
||
|
RecCmd $01, 'A',$50
|
||
|
move.b #cFlushFIFO, rCMD(a3) ; reset doesn't flush the @#$%^&! fifo!
|
||
|
eieio
|
||
|
|
||
|
move.b #kBusFreePhase, currentPhase(A5) ; in Bus Free Phase now
|
||
|
|
||
|
rts
|
||
|
|
||
|
NAME 'DoReset'
|
||
|
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; HALAssertATN - Assert the ATN signal on the scsi bus <SM4> pdw
|
||
|
; 4
|
||
|
; void HALAssertATN( HALc96Globals * HALg );
|
||
|
;
|
||
|
HALAssertATN
|
||
|
move.l A3, -(sp)
|
||
|
move.l A5, -(sp)
|
||
|
|
||
|
move.l 12(sp), A5 ; get HALg
|
||
|
move.l baseRegAddr(A5), A3 ; load A3 with base addr of 53c96
|
||
|
|
||
|
move.l jvAssertATN(A5), A1
|
||
|
IF RECORD_ON THEN
|
||
|
pea 'AAtn'
|
||
|
move.l A1, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
|
||
|
jsr (A1)
|
||
|
|
||
|
move.l (sp)+, A5
|
||
|
move.l (sp)+, A3
|
||
|
rts
|
||
|
|
||
|
NAME 'HALAssertATN'
|
||
|
|
||
|
;……………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
;
|
||
|
DoAssertATN
|
||
|
RecCmd $1a, 'A',$54
|
||
|
move.b #cSetAtn, rCMD(A3)
|
||
|
eieio
|
||
|
|
||
|
rts
|
||
|
|
||
|
NAME 'DoAssertATN'
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
; HALTeardownIO -
|
||
|
; 8 4
|
||
|
; void HALTeardownIO( SCSI_IO * ioPtr, HALc96Globals * HALg );
|
||
|
;
|
||
|
HALTeardownIO
|
||
|
move.l 8(sp), A0 ; get HALg
|
||
|
move.l jvTeardownIO(A0), A0
|
||
|
IF RECORD_ON THEN
|
||
|
pea 'tdIO'
|
||
|
move.l A0, -(sp)
|
||
|
bsr RecordEvent
|
||
|
addq.l #8, sp
|
||
|
ENDIF
|
||
|
jmp (A0) ; calling through to a C routine so
|
||
|
; we leave parms as is on the stack
|
||
|
|
||
|
RTSNAME 'HALAssertATN'
|
||
|
|
||
|
;……………………………………………………………………………………………………………………………………………………………………………………………………
|
||
|
;
|
||
|
SetupIONoDMA
|
||
|
TeardownIONoDMA
|
||
|
|
||
|
rts
|
||
|
|
||
|
NAME 'Set/TearIONoDMA'
|
||
|
|
||
|
|
||
|
;################################################################################
|
||
|
;********** Utilities *********
|
||
|
;################################################################################
|
||
|
|
||
|
;==========================================================================
|
||
|
;
|
||
|
MoveSmallBlock
|
||
|
; D0 = number of bytes
|
||
|
; A1 = source
|
||
|
; A2 = dest
|
||
|
move.l @table(D0.w*4), D0
|
||
|
jmp @table(D0.w)
|
||
|
|
||
|
@table
|
||
|
dc.l @0-@table
|
||
|
dc.l @1-@table
|
||
|
dc.l @2-@table
|
||
|
dc.l @3-@table
|
||
|
dc.l @4-@table
|
||
|
dc.l @5-@table
|
||
|
dc.l @6-@table
|
||
|
dc.l @7-@table
|
||
|
dc.l @8-@table
|
||
|
dc.l @9-@table
|
||
|
dc.l @10-@table
|
||
|
dc.l @11-@table
|
||
|
dc.l @12-@table
|
||
|
dc.l @13-@table
|
||
|
dc.l @14-@table
|
||
|
dc.l @15-@table
|
||
|
dc.l @16-@table
|
||
|
|
||
|
@13
|
||
|
move.l (A1)+, (A2)+
|
||
|
@9
|
||
|
move.l (A1)+, (A2)+
|
||
|
@5
|
||
|
move.l (A1)+, (A2)+
|
||
|
@1
|
||
|
move.b (A1)+, (A2)+
|
||
|
@0
|
||
|
rts
|
||
|
|
||
|
@14
|
||
|
move.l (A1)+, (A2)+
|
||
|
@10
|
||
|
move.l (A1)+, (A2)+
|
||
|
@6
|
||
|
move.l (A1)+, (A2)+
|
||
|
@2
|
||
|
move.w (A1)+, (A2)+
|
||
|
rts
|
||
|
|
||
|
|
||
|
@15
|
||
|
move.l (A1)+, (A2)+
|
||
|
@11
|
||
|
move.l (A1)+, (A2)+
|
||
|
@7
|
||
|
move.l (A1)+, (A2)+
|
||
|
@3
|
||
|
move.w (A1)+, (A2)+
|
||
|
move.b (A1)+, (A2)+
|
||
|
rts
|
||
|
|
||
|
@16
|
||
|
move.l (A1)+, (A2)+
|
||
|
@12
|
||
|
move.l (A1)+, (A2)+
|
||
|
@8
|
||
|
move.l (A1)+, (A2)+
|
||
|
@4
|
||
|
move.l (A1)+, (A2)+
|
||
|
rts
|
||
|
|
||
|
NAME 'MoveSmallBlock'
|
||
|
|
||
|
ENDWITH
|
||
|
|
||
|
ENDPROC
|
||
|
END
|