mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-12-29 07:29:15 +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.
2730 lines
88 KiB
Plaintext
2730 lines
88 KiB
Plaintext
;
|
|
; File: Mace.a
|
|
;
|
|
; Contains: Routines to support MACE when coupled with a PSC-style DMA model.
|
|
;
|
|
; Written by: Mark A. Law ,3-March-92
|
|
;
|
|
; Copyright: © 1992-1993 by Apple Computer, Inc. All rights reserved.
|
|
;
|
|
; This file is used in these builds: Mac32
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <SM10> 7/26/93 mal Fixed bug where drvr can fail to open if VM on and logical to
|
|
; physical address mapping of recv buffers are not 1 to 1. See
|
|
; GetPkt().
|
|
; <SM9> 6/14/93 kc Roll in Ludwig.
|
|
; <LW9> 5/14/93 mal #1084946 Fixed race between xmit interrupt and non-interrupt
|
|
; rtns. that could result in sending out-of-order packets.
|
|
; <LW8> 5/3/93 mal #1082628 Fixed race between deferred task and int. hndlr. rtns.
|
|
; See MaceRecv:@exit for details.
|
|
; <LW7> 5/1/93 mal #1082434 Changed calling sequence to GetMem/FreeMem (see
|
|
; MaceEnet.a). Removed PSC debugging code, we support ONLY most
|
|
; current PSC, ³ upgraded EVT5.
|
|
; <LW6> 3/21/93 mal Fix last checkin bug in WriteLAF where MACE_MAC_CONFIG must be
|
|
; saved.
|
|
; <LW5> 3/21/93 mal Remove Curio A2 support, ie. evt3 support. Removed use of
|
|
; _SetIntMask. Write-once on bug-fixed PSC.
|
|
; <LW4> 3/16/93 chp Replace references to the obsolete PSCIntTbl lomem with
|
|
; references to the equivalent field in ExpandMem.
|
|
; <LW3> 2/17/93 mal Moved receive chain/buffer headers out of unused portion of DMA
|
|
; buffer and into separate memory block.
|
|
; <LW2> 1/27/93 mal Added MACEecfg rsrc support. Changed promiscuous mode support to
|
|
; lower main codepath risk.
|
|
; <SM8> 12/4/92 mal Turned off debug code; promiscuous change to MaceRecv(); no
|
|
; longer deliver pkts with overflow error; added RCVCO counter;
|
|
; improved error handling if TranslateAddress fails.
|
|
; <SM7> 11/19/92 mal Added PSC-bug recv DMA chnl checks; made ResetMace more robust;
|
|
; chg'd alignment method on recv buffers; added rcv collision cnt;
|
|
; chg'd MaceHalt to dequeue DT
|
|
; <SM6> 11/10/92 mal Fixed bug in Mace open that could corrupt memory byte off A3;
|
|
; Corrected reporting of Recv FIFO overflow to
|
|
; InternalMacRecvError.
|
|
; <SM5> 10/30/92 mal Fixed race cond. between deferred task & int. hndlr to give
|
|
; better recv perf.; added cmd/stat reg debug cuz of psc hw bug;
|
|
; disable all ints at end of ResetMace; call FreeMemory if error
|
|
; in MaceInit; misc global cleanup; misc comment cleanup.
|
|
; <SM4> 10/26/92 mal Updated to ESD's latest stats equs.
|
|
; <SM3> 10/26/92 mal Fixed some bugs and modified recv/xmit buffer memory allocation
|
|
; loop in open().
|
|
; <SM2> 10/13/92 mal -perf. improvement: removed all memory indirect preindexed ea's;
|
|
; -changed status to lw and always deliver to RecvRtn; -added temp
|
|
; code to handle PSC addr/cnt bug on 33 Mhz evt4.
|
|
; <1> 10/6/92 GDW New location for ROMLink tool.
|
|
; <SM6> 9/14/92 mal -Updated SNMP counters; -added temp code to handle all Curio
|
|
; revs up to B0
|
|
; <SM5> 7/27/92 mal Added temp code to handle version 1 'ebfr's.
|
|
; <SM4> 7/25/92 mal Added support for HW's maximum receive buffer configuration.
|
|
; Fixed xmit path bug where pkts could be sent out of order
|
|
; (stress). Fixed recv path bug to ensure correct reg set primed
|
|
; when only 1 chain available (heavy stress). Added recv/xmit
|
|
; bus error handlers. Improved MACEHALT routine.
|
|
; <SM3> 6/26/92 mal Expanded # of maceinit parms saved in globals.
|
|
; <SM2> 6/22/92 mal New drvr to support PSC2's (EVT2) Ethernet DMA receive model.
|
|
; <SM1> 5/21/92 RB Removed the inclusion of VMCalls.a, got rid of a warning
|
|
; branch to next instruction and included InternalOnlyEqu.a
|
|
; <P3> 5/5/92 mal Removed some unused global vars
|
|
; <P2> 4/30/92 mal Expanded interface between MaceEnet.a and Mace.a.
|
|
;
|
|
; To Do:
|
|
;
|
|
; Notes: Initial version provides support for Cyclone builtin Ethernet.
|
|
;
|
|
;
|
|
|
|
PRINT OFF
|
|
INCLUDE 'SysEqu.a' ; System definitions
|
|
INCLUDE 'SysErr.a' ; System errors
|
|
INCLUDE 'Traps.a' ; Traps definitions
|
|
INCLUDE 'GestaltEqu.a'
|
|
INCLUDE 'InternalOnlyEqu.a' ; lowmem globals
|
|
INCLUDE 'HardwarePrivateEqu.a'
|
|
INCLUDE 'UniversalEqu.a' ; lowmem global records
|
|
INCLUDE 'ATalkMacros.a' ; Nifty Macros
|
|
INCLUDE 'SysPrivateEqu.a' ; ExpandMem defs
|
|
|
|
; Conditional compile equates
|
|
COUNTERS EQU 0
|
|
BUFDEBUG EQU 0
|
|
DEBUG EQU 0
|
|
SETDEBUG EQU 0
|
|
SETDEBUGFAIL EQU 0
|
|
SETCSDEBUG EQU 0
|
|
SETCSDEBUGFAIL EQU 0
|
|
USEDEFERREDTASK EQU 1
|
|
PROM EQU 1
|
|
|
|
PRINT NOGEN,NOMDIR,ON
|
|
INCLUDE 'MaceEqu.a' ; Mace definitions
|
|
INCLUDE 'PSCEqu.a' ; PSC definitions
|
|
INCLUDE 'ENETEqu.a' ; Driver definitions
|
|
INCLUDE 'SNMPLAP.a' ; SNMP definitions
|
|
EJECT
|
|
|
|
;_______________________________________
|
|
;
|
|
; Misc definitions
|
|
;_______________________________________
|
|
|
|
OneWdsSz EQU 8 ; single fragment wds size
|
|
INTLockOut EQU $0700 ; SR value to disable ALL interrupts
|
|
DMALockOut EQU $0400 ; SR value to disable PSC DMA interrupts
|
|
NeedDefer EQU 5 ; bit indicates VM is running
|
|
; ¥¥¥¥ warning, MaxChns should NOT be set > 64. It could make some calcs in the
|
|
; ¥¥¥¥ MaceInit rtn overflow the 16 bit low-order word!
|
|
MaxChns EQU 64 ; max number of chains
|
|
OneChn EQU 1 ; one chain, minimum too
|
|
DefChns EQU 4 ; default number of chains
|
|
MaxBufpChn EQU 1023 ; max number of buffers per chain
|
|
DefTxBuffs EQU 8 ; default number of xmit buffers
|
|
DefRxBuffs EQU 16 ; default number of recv buffers
|
|
MinBufpChn EQU 2 ; min number of buffers per chain
|
|
;MACERevA2 EQU $0941
|
|
MACERevB0 EQU $0940
|
|
|
|
MaceVars RECORD 0 ; our variables
|
|
MACEmem DS.l 1 ; ptr to memory block with recv & xmit buffers
|
|
RecvBuffMem DS.l 1 ; aligned recv buffer mem
|
|
XmitBuffMem DS.l 1 ; aligned xmit buffer mem
|
|
RecvXmitMemSz DS.l 1 ; need size of aligned mem if need to free it
|
|
ChnDescrMem DS.l 1 ; recv chain descriptor mem
|
|
MACEBase DS.l 1 ; MACE base address
|
|
PSCBase DS.l 1 ; PSC base address
|
|
DTQE DS.b dtQElSize ; Deferred task queue element
|
|
DTInstalled DS.b 1 ; flag, non-zero if DT installed
|
|
DS.b 1 ; fill
|
|
MACEChipID DS.w 1 ; MACE revision
|
|
ALIGN 4
|
|
; ¥¥¥ parms saved from MaceInit call
|
|
RcvRtn DS.l 1 ; users recv rtn
|
|
RcvParm DS.l 1 ; users recv rtn parm
|
|
XmtDnRtn DS.l 1 ; users xmit completion rtn
|
|
XmtDnParm DS.l 1 ; users xmit completion rtn parm
|
|
MCfg DS.l 1 ; ptr to MACE config record
|
|
Dot3StatPtr DS.l 1 ; ptr to 802.3 statistics counters
|
|
LAPMIBStatPtr DS.l 1 ; ptr to LAP MIB statistics counters
|
|
OurAddrPtr DS.l 1 ; ptr to ethernet address
|
|
MemMove DS.l 1 ; ptr to fast memory move rtn
|
|
; ¥¥¥ end parms
|
|
; ActRecvSet is REQUIRED since it enables the Recv processing to ensures that recv
|
|
; pkts are processed IN ORDER.
|
|
ActRecvSet DS.w 1 ; offset to active recv reg set
|
|
; ActXmitSet helps, ie. not necessary, the Xmit DONE processing by pting to the "oldest" reg
|
|
; set that has completed a xmit. For cases where both sets have a xmit done int, this
|
|
; will make available the next set that can perform a xmit, the "oldest".
|
|
; NxtXmitSet is REQUIRED since it enables the Xmit PRIME processing to ensures that xmit
|
|
; pkts are sent IN ORDER.
|
|
ActXmitSet DS.w 1 ; offset to active xmit reg set
|
|
NxtXmitSet DS.w 1 ; offset to xmit reg set for next xmit
|
|
; ¥¥¥¥¥ WARNING: Do NOT add or delete any parms in this range
|
|
; The offsets between RxChainSet0,RxChainSet1 &
|
|
; TxBuffSet0,TxBuffSet1 MUST be maintained
|
|
CntlRegSetByte EQU $0001 ; AND with cntrl reg to get inactive set
|
|
RegSet1Offset EQU $10 ; Reg Set1 offset from Channel base
|
|
ALIGN 4
|
|
RxChainSet0 DS.l 1 ; Log addr of chain assigned to Set0
|
|
FreeRxChain DS.l 1 ; head of free recv chain list
|
|
InUseRxHead DS.l 1 ; head of InUse recv chain list
|
|
InUseRxTail DS.l 1 ; tail of InUse recv chain list
|
|
RxChainSet1 DS.l 1 ; Log addr of chain assigned to Set1
|
|
TxBuffSet0 DS.l 1 ; Log addr of buffer assigned to Set0
|
|
FreeXmtBuff DS.l 1 ; head of free xmit buffers list
|
|
InUseTxHead DS.l 1 ; head of InUse xmit buffers list
|
|
InUseTxTail DS.l 1 ; tail of InUse xmit buffers list
|
|
TxBuffSet1 DS.l 1 ; Log addr of buffer assigned to Set1
|
|
; ¥¥¥¥¥ END WARNING
|
|
COLLCnt DS.l 1 ; recv frames with collision error
|
|
; Transmit Frame Status Register counters
|
|
XmtStatINV DS.l 1 ; xmit ints with xmit status invalid
|
|
XmtLCOL DS.l 1 ; late collision
|
|
XmtRTRYCnt DS.l 1 ; total number of retries
|
|
; Interrupt Register counter
|
|
RCVCOCnt DS.l 1 ; *256 to get # collisions on net
|
|
MPCOCnt DS.l 1 ; *256 to get # of missed packets due to
|
|
; RcvOFLO, receiver disabled, or excessive
|
|
; receive frame count (RcvFC)
|
|
;
|
|
RecvBerr DS.w 1 ; recv chnl bus error being processed
|
|
XmitBerr DS.w 1 ; xmit chnl bus error being processed
|
|
IF COUNTERS THEN
|
|
RcvInts DS.l 1 ; # of times MACE int rtn called for a recvint
|
|
PSCIntCnt DS.l 1 ; # of times PSC Int Rtn called
|
|
MaceIntCnt DS.l 1 ; # of times MACE Int Rtn called
|
|
MaceRcvCnt DS.l 1 ; # of times Deferred Recv Task called
|
|
; ¥¥¥¥¥ WARNING: Do NOT add or delete any parms in this range
|
|
; The offsets between RecvSet0Cnt,RecvSet1Cnt; DTprimeSet0,DTprimeSet1; &
|
|
; XmitSet0Cnt,XmitSet1Cnt MUST be maintained
|
|
RecvSet0Cnt DS.l 1 ; # of recv frames on set 0
|
|
DTprimeSet0 DS.l 1 ; # of times DT primed reg set 0
|
|
XmitSet0Cnt DS.l 1 ; # of xmit frames on set 0
|
|
NoFreeChains DS.l 1 ; # of times no free chains available
|
|
RecvSet1Cnt DS.l 1 ; # of recv frames on set 1
|
|
DTprimeSet1 DS.l 1 ; # of times DT primed reg set 0
|
|
XmitSet1Cnt DS.l 1 ; # of xmit frames on set 1
|
|
; ¥¥¥¥¥ END WARNING
|
|
XmitRSFull DS.l 1 ; Cnt of RegSets full on MaceXmit, -> InUse
|
|
InUseXmit DS.l 1 ; Cnt of xmits done from InUse Queue
|
|
InUseXmitD DS.l 1 ; Cnt of xmits removed from InUse Queue
|
|
XmitPend DS.l 1 ; Cnt of DoWrite calls from MaceXmitDone
|
|
noDTInstall DS.l 1 ; # of times didn't install deferred task
|
|
; since it was already installed
|
|
ChnFlushed DS.l 1 ; # of times a chn was flushed
|
|
RecvBerrCnt DS.l 1 ; # of bus error's on recv chnl
|
|
XmitBerrCnt DS.l 1 ; # of bus error's on xmit chnl
|
|
ENDIF
|
|
IF BUFDEBUG THEN
|
|
RecvBerrAddr DS.l 1 ; addr that caused bus error on recv chnl
|
|
RecvBerrCntl DS.w 1 ; Cntl reg, look at set byte
|
|
XmitBerrAddr DS.l 1 ; addr that caused bus error on xmit chnl
|
|
XmitBerrCntl DS.w 1 ; Cntl reg, look at set byte
|
|
XmtDnActive DS.l 1
|
|
CurrRecv DS.l 1
|
|
ENDIF
|
|
IF SETDEBUG THEN
|
|
hasNewPSC DS.b 1 ; non-zero = new psc, 0 = old psc
|
|
ALIGN 4
|
|
ENDIF
|
|
LogAddrFltr DS.b 8 ; Copy of MACE Logical Address Filter
|
|
; bit order 63-56, 55-48, ... 7-0
|
|
LAFHashTbl DS.b 64 ; Tbl of counts of number multicasts addresses
|
|
; that hash to each bit
|
|
MaceVarSz EQU * ; End of variables
|
|
ENDR
|
|
|
|
;
|
|
; Transmit Buffer template
|
|
; -ensure 1st one is quad-aligned and all the rest will be
|
|
XmitBuff Record 0
|
|
Next DS.l 1 ; Ptr to next buffer
|
|
Prev DS.l 1 ; Ptr to previous buffer
|
|
LogBufPtr DS.l 1 ; Logical address of packet data area
|
|
WDSptr EQU * ; Address of 1 entry WDS
|
|
Len DS.w 1 ; Packet length
|
|
PhyBufPtr DS.l 1 ; Physical address of packet data area
|
|
Status DS.b 1
|
|
ALIGN 16
|
|
LogBufOff EQU LogBufPtr - * ; Offset from packet data area
|
|
; to Logical address of packet data area
|
|
HdrBufOff EQU XmitBuff - * ; Offset from buffer header
|
|
; to packet data area
|
|
Packet DS.b Max_Pkt_Size ; packet data area
|
|
ALIGN 16
|
|
TxBuffSz EQU *
|
|
EndR
|
|
;
|
|
; Receive Buffer template
|
|
; -ensure 1st one is quad-aligned and all the rest will be
|
|
RecvBuff Record 0
|
|
MaceStat DS.b 8 ; Recv'd pkt status from Mace
|
|
DS.b 8 ; fill, PSC DMAs quad-lw chunks
|
|
Packet DS.b Max_Pkt_Size ; packet data area
|
|
ALIGN 2048
|
|
RxBuffSz EQU *
|
|
EndR
|
|
|
|
;
|
|
; Receive Chain Descriptor template
|
|
;
|
|
RxChnDescr Record 0
|
|
NextChn DS.l 1 ; ptr to next chain descr
|
|
PhyChnPtr DS.l 1 ; Physical address of chain
|
|
LogChnPtr DS.l 1 ; Logical address of chain
|
|
State DS.b 1 ; state of this chain
|
|
DS.b 1 ; fill
|
|
OnOffSet EQU 0 ; bit 0: 0-not on, 1-on reg set
|
|
Flushed EQU 1 ; bit 1: 0-no flush, 1-flush occurred
|
|
Berred EQU 2 ; bit 2: 0-no berr, 1-berr occurred
|
|
Limit DS.w 1 ; # of buffers in this chain
|
|
Out DS.w 1 ; # of next buffer to drain
|
|
In DS.w 1 ; # of next buffer to be filled with pkt
|
|
; only valid when chain OFF reg set
|
|
savedLimit DS.w 1 ; only needed after flush done on chain
|
|
RxChnDescrSz EQU *
|
|
EndR
|
|
|
|
EJECT
|
|
|
|
STRING PASCAL
|
|
MACHINE MC68020
|
|
|
|
MaceData PROC
|
|
ENTRY MaceVarPtr
|
|
MaceVarPtr Dc.l 1 ; Contains ptr to my variables
|
|
ENDP
|
|
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; RecoverXmitBuffs - move any xmit buffers from DMA chnl to free queue.
|
|
;
|
|
; Call: A2 - globals
|
|
; Return: none
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
RecoverXmitBuffs PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL
|
|
|
|
; Put transmit buffs back on freelist
|
|
MoveQ #0, D0 ; reg set 0 offset
|
|
@chgsets Move.l TxBuffSet0(A2,D0), D1
|
|
Beq.s @nobuff
|
|
Clr.l TxBuffSet0(A2,D0)
|
|
MoveA.l D1, A0
|
|
Move.l FreeXmtBuff(A2), XmitBuff.Next(A0) ; Make us pt to head of freelist
|
|
Move.l A0, FreeXmtBuff(A2) ; Make us head of freelist
|
|
@nobuff BChg #4, D0
|
|
Beq.s @chgsets
|
|
|
|
Rts
|
|
|
|
ENDP
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; ResetXmitChnl - reset PSC's MACE DMA xmit channel, reset MACE xmit FIFO,
|
|
; move any xmit buffers from DMA chnl to free queue.
|
|
;
|
|
; Call: A2 - globals
|
|
; Return: none
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
ResetXmitChnl PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL
|
|
|
|
; Reset PSC DMA xmit chnl
|
|
; -leaves chnl paused
|
|
; -clears set ENABLE's
|
|
MoveA.l PSCBase(A2), A0
|
|
Move #(1<<SENSE)+(1<<SWRESET), PSC_MACE_XMIT_CNTL(A0)
|
|
|
|
MoveA.l MACEBase(A2), A1
|
|
Move.b MACE_MAC_CNFG(A1), D0 ; get current MACE mac config
|
|
Move.b D0, -(SP) ; save it
|
|
BClr #ENXMT, D0
|
|
Move.b D0, MACE_MAC_CNFG(A1) ; Disable xmit
|
|
|
|
Move.b MACE_FIFO_CNFG(A1), D0 ; Get current MACE FIFO config
|
|
OrI.b #(1<<XMTFWR), D0
|
|
Move.b D0, MACE_FIFO_CNFG(A1) ; Reset MACE xmit FIFO
|
|
|
|
Bsr.s RecoverXmitBuffs
|
|
|
|
Move #0, ActXmitSet(A2) ; reset offset to active xmit reg set
|
|
Move #0, NxtXmitSet(A2) ; reset offset to next reg set to xmit on
|
|
|
|
MoveA.l PSCBase(A2), A0
|
|
Move #(1<<PAUSE), PSC_MACE_XMIT_CNTL(A0) ; UnPause the DMA xmit channel
|
|
|
|
Move.b (SP)+, D0 ; get previous config
|
|
MoveA.l MACEBase(A2), A0
|
|
Move.b D0, MACE_MAC_CNFG(A0) ; restore config
|
|
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; Initialize A SINGLE Recv DMA Channel Register Set
|
|
; Call:
|
|
; A1 - Receive Buffer Descriptor address
|
|
; A2 - globals
|
|
; A3 - DMA recv chnl base
|
|
; D4 - offset to reg set
|
|
; Return: none
|
|
;________________________________________________________________________
|
|
|
|
InitRecv PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
|
|
|
|
Move #(1<<IF), CmdStat(A3,D4) ; Clear interrupt
|
|
|
|
Move.l A1, RxChainSet0(A2,D4) ; Save addr of recv chain descriptor
|
|
|
|
IF SETDEBUG THEN
|
|
IF not SETDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a01 ; go to old PSC patch
|
|
Move.l PhyChnPtr(A1), Addr(A3,D4) ; Set DMA dest addr to phys addr of chain
|
|
Bra.s @aaa1
|
|
@a01
|
|
ENDIF
|
|
Move.l PhyChnPtr(A1), D0
|
|
And.l #$FFFFF000, D0 ; 2K aligned addr
|
|
@a1 Move.l PhyChnPtr(A1), Addr(A3,D4) ; Set DMA dest addr to phys addr of chain
|
|
Move.l Addr(A3,D4), D1
|
|
And.l #$FFFFF000, D1 ; 2K aligned addr
|
|
Cmp.l D0, D1
|
|
IF SETDEBUGFAIL THEN
|
|
Beq.s @aa1
|
|
_Debugger
|
|
Bra.s @a1
|
|
@aa1
|
|
ELSE
|
|
Bne.s @a1
|
|
@aaa1
|
|
ENDIF
|
|
ELSE
|
|
Move.l PhyChnPtr(A1), Addr(A3,D4) ; Set DMA dest addr to phys addr of chain
|
|
ENDIF
|
|
|
|
MoveQ #0, D0 ; init D0
|
|
Move savedLimit(A1), Limit(A1)
|
|
Move Limit(A1), D0
|
|
|
|
IF SETDEBUG THEN
|
|
IF not SETDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a02 ; go to old PSC patch
|
|
Move.l D0, Cnt(A3,D4) ; Set DMA count to # of segments in chain
|
|
Bra.s @aaa2
|
|
@a02
|
|
ENDIF
|
|
@a2 Move.l D0, Cnt(A3,D4) ; Set DMA count to # of segments in chain
|
|
Move.l Cnt(A3,D4), D1
|
|
Cmp.l D0, D1
|
|
IF SETDEBUGFAIL THEN
|
|
Beq.s @aa2
|
|
_Debugger
|
|
Bra.s @a2
|
|
@aa2
|
|
ELSE
|
|
Bne.s @a2
|
|
@aaa2
|
|
ENDIF
|
|
ELSE
|
|
Move.l D0, Cnt(A3,D4) ; Set DMA count to # of segments in chain
|
|
ENDIF
|
|
|
|
Move #0, Out(A1) ; Initialize Out
|
|
IF BUFDEBUG THEN
|
|
Move #0, In(A1) ; Initialize In
|
|
ENDIF
|
|
Move.b #(1<<OnOffSet), State(A1) ; Set chain's state to ON reg set and
|
|
; clear flush indication
|
|
|
|
IF SETCSDEBUG THEN
|
|
IF not SETCSDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a03 ; go to old PSC patch
|
|
Move #(1<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A3,D4)
|
|
Bra.s @aaa3
|
|
@a03
|
|
ENDIF
|
|
@a3 Move #(1<<SENSE)+(1<<IE), CmdStat(A3,D4)
|
|
Move CmdStat(A3,D4), D0
|
|
BTst #IE, D0
|
|
IF SETCSDEBUGFAIL THEN
|
|
Bne.s @aa3
|
|
_Debugger
|
|
Bra.s @a3
|
|
@aa3
|
|
ELSE
|
|
Beq.s @a3
|
|
ENDIF
|
|
Move #(1<<SENSE)+(1<<ENABLED), CmdStat(A3,D4)
|
|
@aaa3
|
|
ELSE
|
|
Move #(1<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A3,D4)
|
|
ENDIF
|
|
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; InitRecvChl - Initialize BOTH Recv DMA Channel Register Sets
|
|
; Call: A2 - globals
|
|
; Return: none
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
InitRecvChl PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
|
|
|
|
MoveM.l A3/D4, -(SP)
|
|
MoveQ #0, D4 ; init reg set offset
|
|
MoveA.l PSCBase(A2), A3
|
|
Lea PSC_MACE_RECV(A3), A3 ; A3-> Mace Recv DMA channel
|
|
|
|
@initset Move.l FreeRxChain(A2), D0 ; Dequeue next available recv chain
|
|
Beq.s @nocando ; none available, leave
|
|
MoveA.l D0, A1
|
|
Move.l NextChn(A1), FreeRxChain(A2)
|
|
Clr.l NextChn(A1)
|
|
|
|
IF SETDEBUG THEN
|
|
Bsr InitRecv ; Prime Register Set
|
|
ELSE
|
|
Bsr.s InitRecv ; Prime Register Set
|
|
ENDIF
|
|
|
|
BChg #4, D4 ; Toggle reg sets
|
|
Beq.s @initset ; if D2 was $0 (set 0), init set 1
|
|
@nocando
|
|
MoveM.l (SP)+, A3/D4
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; PrimeRecv - Prime reg set with chain from free queue
|
|
;
|
|
; Call:
|
|
; A2 - our variables
|
|
; A3 - Receive DMA Channel Reg Set base address
|
|
; D4 - Register set offset
|
|
;
|
|
; Return: none
|
|
;
|
|
; Notes:
|
|
; -can trash C scratch regs: A0-A1,D0-D2
|
|
;________________________________________________________________________
|
|
|
|
PrimeRecv PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
|
|
MoveA.l RxChainSet0(A2,D4), A0 ; get active chain descriptor ptr
|
|
IF BUFDEBUG THEN
|
|
Move.l A0, D1
|
|
Bne.s @noprob
|
|
_Debugger
|
|
@noprob
|
|
ENDIF
|
|
Clr.l RxChainSet0(A2,D4) ; indicate no chain on reg set
|
|
BClr #OnOffSet, State(A0) ; indicate this chain NOT on reg set
|
|
;
|
|
; Put this recv chain on InUse queue
|
|
;
|
|
Move.l InUseRxTail(A2), D1 ; Something on the queue?
|
|
Bne.s @61 ; Yes
|
|
; Empty queue
|
|
Move.l A0, InUseRxTail(A2) ; Point tail at us
|
|
Move.l A0, InUseRxHead(A2) ; Point head at us
|
|
Bra.s @62
|
|
@61 ; Items on queue
|
|
Move.l D1, A1 ; Get tail
|
|
Move.l A0, NextChn(A1) ; Put on end of queue
|
|
Move.l A0, InUseRxTail(A2) ; Make tail pt to us
|
|
@62
|
|
Clr.l NextChn(A0)
|
|
;
|
|
; Setup offset to active chain for DT. Since all buffers in chain are full or we flushed,
|
|
; PSC will have switched to other reg set.
|
|
;
|
|
BChg #4, D4 ; toggle reg set offset
|
|
Move D4, ActRecvSet(A2) ; chg offset to active reg set
|
|
BChg #4, D4 ; toggle back reg set offset
|
|
|
|
Tst.b RecvBerr(A2) ; are we're processing buserror?
|
|
Bne.s @bye ; yes, leave
|
|
|
|
;
|
|
; Dequeue next available recv chain
|
|
;
|
|
Move.l FreeRxChain(A2), D1
|
|
IF COUNTERS THEN
|
|
Bne.s @getfreechain
|
|
AddQ.l #1, NoFreeChains(A2) ; no chains available
|
|
Bra.s @bye
|
|
@getfreechain
|
|
ELSE
|
|
Beq.s @bye ; no chains available
|
|
ENDIF
|
|
MoveA.l D1, A1 ; A1->addr of recv chain descriptor
|
|
Move.l NextChn(A1), FreeRxChain(A2) ; Dequeue from free list
|
|
Clr.l NextChn(A1)
|
|
|
|
Bsr InitRecv ; prime reg set with this chain
|
|
|
|
@bye Rts ; leave
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; ResetMACE - Reset PSC & MACE FIFOs and disable recv & xmit paths and reset MACE
|
|
;
|
|
; Call: A2 - drvr vars
|
|
;
|
|
; Return: none
|
|
;
|
|
; Destroys: A1,D0,D1
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
ResetMACE PROC EXPORT
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL
|
|
|
|
; reset & disable MACE -> PSC receive path
|
|
MoveA.l MACEBase(A2), A0 ; A0-> base address of MACE regs
|
|
MoveA.l PSCBase(A2), A1 ; A1-> base address of PSC regs
|
|
|
|
Move.b #0, MACE_MAC_CNFG(A0) ; Disable MACE recv, xmit, et. al.
|
|
|
|
Move.b MACE_FIFO_CNFG(A0), D0 ; Get current FIFO config
|
|
OrI.b #(1<<RCVFWR), D0 ; Keep current FIFO's watermarks
|
|
Move.b D0, MACE_FIFO_CNFG(A0) ; Reset MACE recv FIFO
|
|
|
|
Move #(1<<SENSE)+(1<<SWRESET), PSC_MACE_RECV_CNTL(A1) ; Reset recv chnl
|
|
Move #(1<<CIE), PSC_MACE_RECV_CNTL(A1) ; Clear channel int enable
|
|
Move #(1<<IE)+(1<<IF), MACE_RECV_CMDSTAT0(A1) ; Clear set int & int enable
|
|
Move #(1<<IE)+(1<<IF), MACE_RECV_CMDSTAT1(A1) ; Clear set int & int enable
|
|
|
|
; reset & disable PSC -> MACE transmit path
|
|
Move #(1<<SENSE)+(1<<SWRESET), PSC_MACE_XMIT_CNTL(A1) ; Reset xmit chnl
|
|
Move #(1<<CIE), PSC_MACE_XMIT_CNTL(A1) ; Clear channel int enable
|
|
Move #(1<<IE)+(1<<IF), MACE_XMIT_CMDSTAT0(A1) ; Clear set int & int enable
|
|
Move #(1<<IE)+(1<<IF), MACE_XMIT_CMDSTAT1(A1) ; Clear set int & int enable
|
|
|
|
|
|
Move.b MACE_FIFO_CNFG(A0), D0 ; Get current FIFO config
|
|
OrI.b #(1<<XMTFWR), D0 ; Keep current FIFO's watermarks
|
|
Move.b D0, MACE_FIFO_CNFG(A0) ; Reset MACE xmit FIFO
|
|
|
|
; Reset MACE
|
|
Move.b #(1<<MACERESET), MACE_BIU_CNFG(A0) ; reset MACE
|
|
@wait Move.b MACE_BIU_CNFG(A0), D0
|
|
BTst #MACERESET, D0
|
|
Bne.s @wait ; loop until reset complete
|
|
|
|
Move.b #0, MACE_MAC_CNFG(A0) ; make sure MACE disabled
|
|
Move.b #MaceIntMask, MACE_INT_MSK(A0) ; Disable all MACE ints.
|
|
|
|
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; FreeMACEMem - free all memory
|
|
;
|
|
; Call: A2 - our globals
|
|
;
|
|
; Return: none
|
|
;
|
|
; Destroys: A0
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
FreeMACEMem PROC
|
|
|
|
IMPORT FreeMemory
|
|
WITH MaceVars,FreeMem
|
|
|
|
Tst.l MaceVarPtr ; Mace var pointer
|
|
Beq.s @57 ; no mem allocated
|
|
|
|
Tst.l MACEmem(A2)
|
|
Beq.s @55 ; DMA buffer mem not allocated
|
|
|
|
Sub.l #FreeMemSz, SP ; room for parms
|
|
Move.l MACEmem(A2), memptr(SP) ; ptr to memmgr blk to free
|
|
Move.l RecvBuffMem(A2), memptra(SP) ; ptr to mem to unlock
|
|
Move.l RecvXmitMemSz(A2), memptrasz(SP) ; size of mem to unlock
|
|
Move.l #(1<<Locked)+(1<<Contig)+(1<<CacheOff), memoptions(SP) ; specify options
|
|
Lea FreeMemory, A0
|
|
Jsr (A0) ; free DMA buffer memory
|
|
Add.l #FreeMemSz, SP ; pop parms
|
|
@55
|
|
Tst.l ChnDescrMem(A2)
|
|
Beq.s @56 ; Chain Descriptor buffer mem not allocated
|
|
Sub.l #FreeMemSz, SP ; room for parms
|
|
Move.l ChnDescrMem(A2), memptr(SP) ; ptr to memmgr blk to free
|
|
Move.l #0, memoptions(SP) ; specify options
|
|
Lea FreeMemory, A0
|
|
Jsr (A0) ; free MACE var memory
|
|
Add.l #FreeMemSz, SP ; pop parms
|
|
@56
|
|
Sub.l #FreeMemSz, SP ; room for parms
|
|
Lea MaceVarPtr, A0
|
|
Move.l (A0), memptr(SP) ; ptr to memmgr blk to free
|
|
Clr.l (A0) ; Clear MaceVarPtr contents
|
|
Move.l #0, memoptions(SP) ; specify options
|
|
Lea FreeMemory, A0
|
|
Jsr (A0) ; free MACE var memory
|
|
Add.l #FreeMemSz, SP ; pop parms
|
|
@57
|
|
Rts
|
|
|
|
ENDWITH
|
|
ENDP
|
|
EJECT
|
|
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; MACEHalt - HALT the MACE, remove interrupt handlers, free all memory
|
|
;
|
|
; Call: none
|
|
;
|
|
; Return: none
|
|
;
|
|
; Destroys: A1,D0,D1
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
MACEHalt PROC EXPORT
|
|
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,PSC_INT_TBL
|
|
|
|
Move.l A2, -(SP) ; save regs
|
|
MoveA.l MaceVarPtr, A2 ; Get ptr to my vars
|
|
|
|
Move SR,-(SP) ; Save interrupt mask level
|
|
OrI #DMALockOut, SR ; Disable DMA ints.
|
|
|
|
Bsr ResetMACE
|
|
|
|
; Remove PSC DMA handlers for Mace Recv & Xmit channels
|
|
WITH ExpandMemRec
|
|
MoveA.l ([ExpandMem],emDMADispatchGlobals), A0; A0-> PSC Interrupt table ptr
|
|
ENDWITH
|
|
MoveQ #0, D0
|
|
Move.l D0, MACE_RECVhndlr(A0)
|
|
Move.l D0, MACE_RECVparm(A0)
|
|
Move.l D0, MACE_XMIThndlr(A0)
|
|
Move.l D0, MACE_XMITparm(A0)
|
|
|
|
; Install Mace Interrupt handler, called at Level 3
|
|
Move.l PSCBase(A2), A1 ; Base address of PSC
|
|
Move.b #(1<<MACE), L3IER(A1) ; Disable MACE interrupts
|
|
Move.l D0, MACEhndlr(A0)
|
|
Move.l D0, MACEparm(A0) ; MaceVarPtr passed back in A1
|
|
|
|
OrI #INTLockOut, SR ; Disable ALL ints.
|
|
|
|
; If deferred task installed, remove it.
|
|
Tst.b DTInstalled(A2) ; is Deferred Task installed?
|
|
Beq.s @nodq ; nope
|
|
IF DEBUG THEN
|
|
_Debugger
|
|
ENDIF
|
|
Lea DTQE(A2), A0 ; get ptr to queue entry
|
|
LEA DTQueue, A1 ; get ptr to queue
|
|
_Dequeue ; remove from deferred task queue
|
|
|
|
@nodq
|
|
Move (SP)+, SR ; Restore SR
|
|
|
|
; Free MACE buffer and var memory
|
|
; ¥¥¥¥
|
|
; ¥¥¥¥ WARNING: upper layer handlers better be done with packets cause we're
|
|
; ¥¥¥¥ freeing the mem the packets are in!
|
|
; ¥¥¥¥
|
|
Bsr FreeMACEMem ; Free, and unlock if needed, all mem blks
|
|
|
|
Move.l (SP)+, A2 ; restore regs
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
IF PROM THEN
|
|
;________________________________________________________________________
|
|
;
|
|
; MACESetProm - put Promiscuous receive routine in global var: RcvRtn
|
|
; and enable promicuous mode.
|
|
;
|
|
; Call: 4(SP) - Promiscuous recv routine address
|
|
;
|
|
; Return: none
|
|
;
|
|
; Destroys: A0, A1
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
MACESetProm PROC EXPORT
|
|
|
|
WITH MACERegs,MaceVars
|
|
|
|
MoveA.l MaceVarPtr, A1 ; Get ptr to my vars
|
|
|
|
Move.l 4(SP), D0 ; get new recv rtn
|
|
|
|
Move SR,-(SP) ; Save SR
|
|
OrI #INTLockOut, SR ; disable all ints
|
|
|
|
Move.l D0, RcvRtn(A1) ; install new recv rtn
|
|
MoveA.l MACEBase(A1), A1
|
|
Move.b MACE_MAC_CNFG(A1), D0 ; get current MACE config
|
|
OrI.b #(1<<PROMISC), D0
|
|
Move.b D0, MACE_MAC_CNFG(A1) ; enable MACE promiscous mode
|
|
|
|
Move (SP)+, SR ; Restore SR
|
|
Rts
|
|
|
|
ENDP
|
|
ENDIF
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; FlushRecvChn - "flushes" a chain from a recv DMA chnl reg set by computing a
|
|
; false "limit", then calls PrimeRecv to put chain on InUse
|
|
; and reprime reg set.
|
|
;
|
|
; Call: A2 - drvr vars
|
|
;
|
|
; Return: none
|
|
;
|
|
; Destroys: A0,D0,D1
|
|
;
|
|
; Notes: on entry, MACE packet reception MUST BE disabled via MAC Config reg
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
FlushRecvChn PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
|
|
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, ChnFlushed(A2)
|
|
ENDIF
|
|
MoveM.l A3/D4, -(SP) ; Save C regs
|
|
|
|
Move ActRecvSet(A2), D4 ; offset to active reg set
|
|
MoveA.l RxChainSet0(A2,D4), A0 ; get ptr to active chain descr
|
|
BSet #Flushed, State(A0) ; Indicate flush done on chain
|
|
|
|
Tst.b RecvBerr(A2) ; are we processing a bus error?
|
|
Beq.s @noberr ; no
|
|
BSet #Berred, State(A0) ; Indicate bus error on chain
|
|
@noberr
|
|
MoveA.l PSCBase(A2), A3
|
|
Lea PSC_MACE_RECV(A3), A3 ; Recv Channel base address
|
|
Move.l Cnt(A3,D4), D1 ; Get current cnt
|
|
Move Limit(A0), D0
|
|
Sub D1, D0 ; compute temp "flush" limit
|
|
Move D0, Limit(A0) ; set temp "flush" limit
|
|
; pass A3 & D4
|
|
Bsr PrimeRecv ; Put chain on InUse and reprime set
|
|
MoveM.l (SP)+, A3/D4 ; Restore C regs
|
|
RTS
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; FlushRecvRegSet - Reset MACE recv FIFO and flush PSC recv FIFO,
|
|
; and reprogram affected register set.
|
|
;
|
|
; Call: A2 - drvr vars
|
|
;
|
|
; Return: none
|
|
;
|
|
; Destroys: A1,D0,D1
|
|
;
|
|
; Notes: on entry, MACE packet reception MUST BE disabled via MAC Config reg
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
FlushRecvRegSet PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL
|
|
|
|
; Reset, ie. flush, MACE Recv FIFO
|
|
;???? AMD question: are there any states where doing this reset will cause an "interesting"
|
|
; line chng to the PSC, who may be in the middle of reading the recv fifo?
|
|
MoveA.l MACEBase(A2), A1
|
|
Move.b MACE_FIFO_CNFG(A1), D0 ; Get current FIFO config
|
|
OrI.b #(1<<RCVFWR), D0
|
|
Move.b D0, MACE_FIFO_CNFG(A1) ; Reset MACE recv FIFO
|
|
|
|
Tst.b RecvBerr(A2) ; are we processing a bus error?
|
|
Bne.s @buserr ; yes, don't flush
|
|
|
|
MoveA.l PSCBase(A2), A1
|
|
Move #(1<<SENSE)+(1<<DMAFLUSH), PSC_MACE_RECV_CNTL(A1) ; Flush PSC Recv FIFO
|
|
@chkflush Move PSC_MACE_RECV_CNTL(A1), D0
|
|
BTst #DMAFLUSH, D0 ; Is flush complete?
|
|
Bne.s @chkflush ; no
|
|
@buserr
|
|
Bsr.s FlushRecvChn ; flush the chain
|
|
|
|
Tst.b RecvBerr(A2) ; are we processing a bus error?
|
|
Bne.s @buserr1 ; yes, don't unpause
|
|
; UnPause the DMA recv channel
|
|
MoveA.l PSCBase(A2), A1
|
|
Move #(1<<PAUSE), PSC_MACE_RECV_CNTL(A1)
|
|
@buserr1
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; NormAddr - convert IEEE address to normal format
|
|
;
|
|
; Call: D0 bit-inverted address byte from Address Prom
|
|
;
|
|
; Return: D0 bit-inverted address byte
|
|
;
|
|
; Destroys: D1
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
NormAddr PROC EXPORT
|
|
MoveM.l D2,-(SP)
|
|
Clr.b D1
|
|
MoveQ #7,D2
|
|
@loop
|
|
Lsl.b #1,D1 ; get ready for next bit
|
|
Lsr.b #1,D0 ; get a bit from source
|
|
Bcc.s @lb ; non there
|
|
AddQ.b #1,D1
|
|
@lb
|
|
DBra D2,@loop
|
|
Move.b D1,D0 ; D0=converted value
|
|
MoveM.l (SP)+,D2
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; DoCRC - compute Ethernet CRC on address field
|
|
;
|
|
; Call:
|
|
; D1 = first two bytes of address
|
|
; D3 = last four bytes of address
|
|
;
|
|
; Return:
|
|
; D0 = 6 bit hash into Logical Address Filter
|
|
;
|
|
; Uses: D0,D1
|
|
;
|
|
; The CRC-32 of a sequence of bits views that sequence as the co-efficients of a (long!)
|
|
; polynomial. This polynomial is multiplied by x^32, then divided by the CRC polynomial
|
|
; x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 +x+1.
|
|
; It is the remainder of this division (of degree <= x^31), considered as a 32 bit sequence,
|
|
; that is the CRC. In the calculation, the initial value of the "remainder" is all 1's.
|
|
;
|
|
;________________________________________________________________________
|
|
|
|
CRCPoly EQU %00000100110000010001110110110111
|
|
; Co-efficients after a shift left
|
|
|
|
DoCRC PROC
|
|
Move.l D2, -(SP)
|
|
MoveQ #-1,D2 ; D2 = current value of CRC
|
|
Bsr.s @10 ; Compute over D1, address bits 47-32
|
|
Move.l D3,D1 ; D1 = rest to do
|
|
Swap D1 ; Get high word of D3 into D1
|
|
Bsr.s @10 ; Compute over D1, address bits 31-16
|
|
Swap D1 ; Get low word of D3 into D1
|
|
Bsr.s @10 ; Compute over D1, address bits 15-0
|
|
|
|
And #%111111, D2 ; Get six hash bits in low byte
|
|
|
|
Move D2, D0
|
|
Bsr NormAddr ; D0 = bit inverted hash
|
|
Lsr.b #2, D0 ; Move 6 msb's to 6 lsb's
|
|
Move.l (SP)+, D2
|
|
Rts ; Exit DoCRC
|
|
|
|
;
|
|
; Accumulate the CRC over the low 16 bits of D1 (starting with high byte bit 0!)
|
|
;
|
|
@10 MoveQ #16,D0 ; D0 = no. of bits to do
|
|
Ror #8,D1 ; Do high byte first
|
|
@15 Lsl.L #1,D2 ; Shift CRC, clear low bit, old hi bit in C
|
|
;
|
|
; If (CRC-hi-bit XOR D1-current-bit) = 1, we complement bits specified by the CRC polynomial
|
|
; (this is the equivalent of a subtract operation in the long division process, I think)
|
|
;
|
|
Bcc.s @30 ; Branch if CRC hi bit clear
|
|
Ror #1,D1 ; Shift D1, low bit in C
|
|
Bcs.s @50 ; (1 XOR 1) = 0: don't compl; low bit = 0
|
|
Bra.s @40 ; Go complement
|
|
|
|
@30 Ror #1,D1 ; Shift D1, high bit in C
|
|
Bcc.s @50 ; (0 XOR 0) = 0: don't compl; low bit = 0
|
|
@40 Eor.l #CRCPoly,D2 ; Complement some bits; set low bit
|
|
@50 SubQ #1,D0 ; Decrement count of bits to do
|
|
Bne.s @15 ; Do all 16 bits
|
|
Rts ; That's it if done them all
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;________________________________________________________________________
|
|
;
|
|
; WriteLAF - update MACE Logical Address Filter (LAF) from copy in drvr globals
|
|
;
|
|
; Call:
|
|
; A2 -> my variables
|
|
;
|
|
; Return:
|
|
; none
|
|
;
|
|
; Uses:
|
|
; A1, D0
|
|
;
|
|
; The LAF can not be updated while MACE recv is enabled. Disable MACE pkt
|
|
; reception. If frames in MACE Recv FIFO, reset MACE Recv FIFO (possible pkt
|
|
; loss), flush PSC recv FIFO, and reprime affected DMA Reg. Set. Finally,
|
|
; update the LAF.
|
|
;________________________________________________________________________
|
|
|
|
WriteLAF PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL
|
|
MoveA.l MACEBase(A2), A1
|
|
|
|
Move.b MACE_MAC_CNFG(A1), -(SP) ; Save current config
|
|
|
|
Move.b #(1<<ADDRCHG), MACE_ADDR_CNFG(A1) ; Set address change bit
|
|
@wait1 Move.b MACE_ADDR_CNFG(A1), D0 ; wait for MACE to clear it
|
|
BTst #ADDRCHG, D0
|
|
Bne.s @wait1
|
|
|
|
Lea LogAddrFltr(A2), A0 ; A0-> copy of logical address filter
|
|
Move.b #(1<<LOGADDR), MACE_ADDR_CNFG(A1) ; Select logical address
|
|
MoveQ #7, D0
|
|
@laf Move.b (A0,D0.w), MACE_LOG_ADDR(A1) ; Set appropriate bits in Log. Addr Filter
|
|
DBra D0, @laf
|
|
|
|
Move.b (SP)+, MACE_MAC_CNFG(A1) ; restore MACE mac config
|
|
RTS
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; MaceAddMulti - add a multicast address to the list
|
|
;
|
|
; Call:
|
|
; D1 = first two bytes of address
|
|
; D3 = last four bytes of address
|
|
;
|
|
; Return:
|
|
; none
|
|
;
|
|
; Computes the hash for this multicast address and increments hash count in
|
|
; the Logical Address Filter (LAF) Table. If hash count now = 1, sets
|
|
; appropriate bit in the MACE LAF.
|
|
;___________________________________________________________________________
|
|
|
|
MaceAddMulti PROC EXPORT
|
|
WITH MACERegs,MaceVars
|
|
|
|
Move.l A2, -(SP) ; Save used C regs
|
|
MoveA.l MaceVarPtr, A2 ; Get ptr to my vars
|
|
|
|
Bsr DoCRC ; D0-> 6 bit hash into LAF
|
|
AddQ.b #1, (LAFHashTbl,A2,D0) ; Inc. # of multi's with this hash
|
|
CmpI.b #1, (LAFHashTbl,A2,D0) ; Multiaddr hash bit already in LAF?
|
|
Bhi @bye ; yes, do nothing
|
|
|
|
Lea LogAddrFltr(A2), A0 ; A0-> copy of log. addr. filter
|
|
Cmp.b #31, D0 ; Hash > 31?
|
|
Bhi.s @b63to32 ; yes
|
|
Move.l 4(A0), D1 ; no, get LAF bits 31-0
|
|
BSet.l D0, D1 ; Is this hash bit already set?
|
|
Bne @bye ; yes, nothing to do
|
|
Move.l D1, 4(A0) ; Save modified LAF bits 31-0
|
|
Bra.s @doit
|
|
|
|
@b63to32 Sub.b #32, D0 ; Convert hash for use on LAF bits 63-32
|
|
Move.l (A0), D1 ; Get LAF bits 63-32
|
|
BSet.l D0, D1 ; Is this hash bit already set?
|
|
Bne @bye ; yes, nothing to do
|
|
Move.l D1, (A0) ; Save modified LAF bits 63-32
|
|
|
|
@doit Bsr WriteLAF ; Write the new LAF
|
|
|
|
@bye Move.l (SP)+, A2 ; Restore used C regs
|
|
Rts
|
|
ENDP
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; MaceDelMulti - Delete a multicast address HASH from the LAF
|
|
;
|
|
; Call:
|
|
; D1 = first two bytes of address
|
|
; D3 = last four bytes of address
|
|
;
|
|
; Return:
|
|
; none
|
|
;
|
|
; Computes the hash for this multicast address and decrements the LAF
|
|
; Table hash count for the given Multicast address. If new hash count = 0,
|
|
; clears appropriate bit in MACE LAF.
|
|
; Depends on caller to ensure not called for a multicast's hash that hasn't
|
|
; already been inc'd in LAFHashTbl.
|
|
;___________________________________________________________________________
|
|
|
|
MaceDelMulti PROC EXPORT
|
|
WITH MACERegs,MaceVars
|
|
|
|
Move.l A2, -(SP) ; Save used C regs
|
|
MoveA.l MaceVarPtr, A2 ; Get ptr to my vars
|
|
|
|
Bsr DoCRC ; D0-> 6 bit hash into LAF
|
|
SubQ.b #1, (LAFHashTbl,A2,D0) ; Dec. # of multi's with this hash
|
|
Bne @bye ; Do nothing if hash table cnt non-zero
|
|
|
|
; Clear this bit in LAF since no other
|
|
; multiaddr's hash to this bit
|
|
Lea LogAddrFltr(A2), A0 ; A0-> copy of log. addr. filter
|
|
Cmp.b #31, D0 ; Hash > 31?
|
|
Bhi.s @b63to32 ; yes
|
|
Move.l 4(A0), D1 ; no, get LAF bits 31-0
|
|
BClr.l D0, D1 ; Clear this hash bit
|
|
IF DEBUG THEN
|
|
Beq @huh ; if LAFHashTbl correct, D1 should
|
|
ELSE ; have D0 bit set!
|
|
Beq @bye ; do nothing hash bit already clear!
|
|
ENDIF
|
|
Move.l D1, 4(A0) ; Save modified LAF bits 31-0
|
|
Bra.s @doit
|
|
|
|
@b63to32 Sub.b #32, D0 ; Convert hash for use on LAF bits 63-32
|
|
Move.l (A0), D1 ; Get LAF bits 63-32
|
|
BClr.l D0, D1 ; Clear this hash bit
|
|
IF DEBUG THEN
|
|
Beq @huh ; if LAFHashTbl correct, D1 should
|
|
ELSE ; have D0 bit set!
|
|
Beq @bye ; do nothing hash bit already clear!
|
|
ENDIF
|
|
Move.l D1, (A0) ; Save modified LAF bits 63-32
|
|
|
|
@doit Bsr WriteLAF ; Write the new LAF
|
|
|
|
@bye Move.l (SP)+, A2 ; Restore used C regs
|
|
Rts
|
|
|
|
IF DEBUG THEN
|
|
@huh _Debugger ; nothing to do 'cause hash bit
|
|
Bra.s @bye ; was already clear
|
|
ENDIF
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; PrimeXmitRS - Prime Reg Set with transmit packet info.
|
|
;
|
|
; Call:
|
|
; 4(SP) - xmit buffer ptr
|
|
; A2 - our vars
|
|
;
|
|
; Return:
|
|
; If xmit register sets are full, return CC==NE; else, CC==EQ.
|
|
; Notes:
|
|
; Called both on normal writes (with level 4 interrupts disabled) <LW9>
|
|
; AND on write completions (interrupt level 4)
|
|
;___________________________________________________________________________
|
|
|
|
PrimeXmitRS PROC
|
|
|
|
XmitPrm RECORD 4
|
|
XmitPtr DS.l 1 ; Transmit buffer ptr
|
|
ParmSz EQU *
|
|
ENDR
|
|
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,LAPMIBStats
|
|
|
|
Move.l XmitPrm.XmitPtr(SP), D1 ; D1 - xmit buffer ptr
|
|
|
|
; Move SR,-(SP) ; Save interrupt mask level <LW9>
|
|
; OrI #DMALockOut, SR ; Disable DMA ints. <LW9>
|
|
|
|
Move NxtXmitSet(A2), D2 ; get offset to next reg set to xmit on
|
|
Lea TxBuffSet0(A2), A1
|
|
Tst.l (A1,D2) ; Can we use this reg set?
|
|
Beq.s @cont2 ; yes
|
|
|
|
; Move (SP)+,SR ; Restore int. mask level <LW9>
|
|
MoveQ #-1, D0 ; Set CC's
|
|
Rts ; Return
|
|
|
|
;
|
|
; Initialize Xmit DMA Channel Register Set
|
|
;
|
|
@cont2
|
|
MoveA.l PSCBase(A2), A0
|
|
Lea PSC_MACE_XMIT(A0), A0 ; A0-> Xmit DMA Channel base addr
|
|
|
|
Move.l D1, (A1,D2) ; Indicate (D1) is active buff on reg set
|
|
MoveA.l D1, A1 ; A1->xmit buffer
|
|
|
|
IF SETDEBUG THEN
|
|
IF not SETDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a01 ; go to old PSC patch
|
|
Move.l XmitBuff.PhyBufPtr(A1), Addr(A0,D2) ; Set DMA dest addr
|
|
Bra.s @aaa1
|
|
@a01
|
|
ENDIF
|
|
Move.l XmitBuff.PhyBufPtr(A1), D0
|
|
And.l #$FFFFFFF0, D0 ; line aligned addr
|
|
@a1 Move.l XmitBuff.PhyBufPtr(A1), Addr(A0,D2) ; Set DMA dest addr
|
|
Move.l Addr(A0,D2), D1
|
|
And.l #$FFFFFFF0, D1 ; line aligned addr
|
|
Cmp.l D0, D1
|
|
IF SETDEBUGFAIL THEN
|
|
Beq.s @aa1
|
|
_Debugger
|
|
Bra.s @a1
|
|
@aa1
|
|
ELSE
|
|
Bne.s @a1
|
|
@aaa1
|
|
ENDIF
|
|
ELSE
|
|
Move.l XmitBuff.PhyBufPtr(A1), Addr(A0,D2) ; Set DMA dest addr
|
|
ENDIF
|
|
|
|
MoveQ #0, D0
|
|
Move.w XmitBuff.Len(A1), D0 ; Get DMA byte count (word)
|
|
|
|
IF SETDEBUG THEN
|
|
IF not SETDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a02 ; go to old PSC patch
|
|
Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long)
|
|
Bra.s @aaa2
|
|
@a02
|
|
ENDIF
|
|
@a2 Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long)
|
|
Move.l Cnt(A0,D2), D1
|
|
Cmp.l D0, D1
|
|
IF SETDEBUGFAIL THEN
|
|
Beq.s @aa2
|
|
_Debugger
|
|
Bra.s @a2
|
|
@aa2
|
|
ELSE
|
|
Bne.s @a2
|
|
@aaa2
|
|
ENDIF
|
|
ELSE
|
|
Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long)
|
|
ENDIF
|
|
|
|
BTst #0, XmitBuff.Packet(A1) ; xmiting a multi/bcast?
|
|
MoveA.l LAPMIBStatPtr(A2), A1
|
|
Bne.s @30
|
|
AddQ.l #1, ifOutUcastPkts(A1) ; inc. non-multi/bcast cntr
|
|
Bra.s @31
|
|
@30 AddQ.l #1, ifOutNUcastPkts(A1) ; inc. multi/bcast cntr
|
|
@31 Add.l D0, ifOutOctets(A1) ; inc. sent octet cntr
|
|
|
|
IF SETCSDEBUG THEN
|
|
IF not SETCSDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a03 ; go to old PSC patch
|
|
Move #(1<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A0,D2)
|
|
Bra.s @aaa3
|
|
@a03
|
|
ENDIF
|
|
@a3 Move #(1<<SENSE)+(1<<IE), CmdStat(A0,D2)
|
|
Move CmdStat(A0,D2), D0
|
|
BTst #IE, D0
|
|
IF SETCSDEBUGFAIL THEN
|
|
Bne.s @aa3
|
|
_Debugger
|
|
Bra.s @a3
|
|
@aa3
|
|
ELSE
|
|
Beq.s @a3
|
|
ENDIF
|
|
Move #(1<<SENSE)+(1<<ENABLED), CmdStat(A0,D2)
|
|
@aaa3
|
|
ELSE
|
|
Move #(1<<SENSE)+(1<<IE)+(1<<ENABLED), CmdStat(A0,D2)
|
|
ENDIF
|
|
|
|
BChg #4, D2 ; Toggle reg sets
|
|
Move D2, NxtXmitSet(A2) ; save offset to next reg set to xmit on
|
|
; Move (SP)+,SR ; Restore int. mask level <LW9>
|
|
MoveQ #0, D0 ; Set CC's
|
|
Rts ; Return
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; RecvBusErr - handle bus errors on PSC's MACE DMA receive channel
|
|
;
|
|
; Call:
|
|
; A2 - our variables
|
|
; D1 - Receive DMA Channel control register value
|
|
;
|
|
; Return:
|
|
; none
|
|
; Notes:
|
|
; Should never get called!
|
|
;___________________________________________________________________________
|
|
|
|
RecvBusErr PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RxChnDescr
|
|
|
|
ST RecvBerr(A2) ; indicate we're processing buserror
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, RecvBerrCnt(A2)
|
|
ENDIF
|
|
MoveA.l MACEBase(A2), A0
|
|
Move.b MACE_MAC_CNFG(A0), D0 ; get current config
|
|
Move.b D0, -(SP) ; save it
|
|
BClr #ENRCV, D0
|
|
Move.b D0, MACE_MAC_CNFG(A0) ; Disable recv
|
|
|
|
IF BUFDEBUG THEN
|
|
Move D1, RecvBerrCntl(A2) ; save chnl control reg
|
|
MoveQ #0, D0 ; assume set 0
|
|
BTst #0, D1 ; which set had bus error?
|
|
Beq.s @set0
|
|
BChg #4, D0 ; chng to set 1
|
|
@set0 MoveA.l PSCBase(A2), A0
|
|
Lea PSC_MACE_RECV(A0), A0 ; A0-> base addr of recv DMA chnl
|
|
Move.l Addr(A0,D0), RecvBerrAddr(A2) ; save addr of bus error
|
|
ENDIF
|
|
|
|
; Reset MACE FIFO
|
|
Bsr FlushRecvRegSet ; and put chain in InUse (PrimeRecv).
|
|
; NOTE: PrimeRecv toggles ActRecvSet(A2)
|
|
Bsr FlushRecvChn ; put other chain in InUse (PrimeRecv).
|
|
|
|
MoveA.l PSCBase(A2), A0
|
|
Move #(1<<SENSE)+(1<<SWRESET), PSC_MACE_RECV_CNTL(A0) ; Reset PSC recv chnl
|
|
|
|
Move #0, ActRecvSet(A2) ; make set 0 active reg set
|
|
|
|
Bsr InitRecvChl ; Initialize the Recv channel
|
|
|
|
MoveA.l PSCBase(A2), A0
|
|
Move #(1<<PAUSE), PSC_MACE_RECV_CNTL(A0) ; UnPause the DMA recv channel
|
|
|
|
Move.b (SP)+, D0 ; get previous config
|
|
MoveA.l MACEBase(A2), A0
|
|
Move.b D0, MACE_MAC_CNFG(A0) ; restore config
|
|
|
|
Clr.b RecvBerr(A2) ; indicate we're DONE processing buserror
|
|
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; XmitBusErr - handle bus errors on PSC's MACE DMA transmit channel
|
|
;
|
|
; Call:
|
|
; A0 - PSC base address
|
|
; A2 - our variables
|
|
; D1 - Transmit DMA Channel control register value
|
|
;
|
|
; Return:
|
|
;
|
|
; Notes:
|
|
; Should never get called!
|
|
;___________________________________________________________________________
|
|
|
|
XmitBusErr PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,XmitBuff
|
|
|
|
ST XmitBerr(A2) ; indicate we're processing buserror
|
|
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, XmitBerrCnt(A2)
|
|
ENDIF
|
|
IF BUFDEBUG THEN
|
|
Move D1, XmitBerrCntl(A2) ; save chnl control reg
|
|
MoveQ #0, D0 ; assume set 0
|
|
BTst #0, D1 ; which set had bus error?
|
|
Beq.s @set0
|
|
BChg #4, D0 ; chng to set 1
|
|
@set0 Lea PSC_MACE_XMIT(A0), A0 ; A0-> base addr of xmit DMA chnl
|
|
Move.l Addr(A0,D0), XmitBerrAddr(A2) ; save addr of bus error
|
|
ENDIF
|
|
; Reset PSC's MACE DMA xmit chnl and reset MACE xmit FIFO
|
|
Bsr ResetXmitChnl ; and put any xmit buffs on free queue.
|
|
|
|
Clr.b XmitBerr(A2) ; indicate we're DONE processing buserror
|
|
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; MaceXmit - Calls PrimeXmitRS to prime Reg Set with transmit packet info.
|
|
; If xmit register sets are full, put xmit buffer ptr on tail
|
|
; of xmit InUse queue.
|
|
;
|
|
; Call:
|
|
; 4(SP) - WDS ptr
|
|
;
|
|
; Return:
|
|
; D0 = error code; nobuff - temporarily out of xmit buffers
|
|
; eLenErr - sum of data in WDS > max. pkt size
|
|
; noErr - primed reg set with xmit pkt or put pkt
|
|
; on xmit InUse queue
|
|
; Notes:
|
|
; Called both on normal writes AND write completion (interrupt level 4)
|
|
;___________________________________________________________________________
|
|
|
|
MaceXmit PROC EXPORT
|
|
|
|
WDSPrm RECORD 4 ; Return address
|
|
WDSPtr DS.l 1 ; Write Data Structure ptr
|
|
ParmSz EQU *
|
|
ENDR
|
|
|
|
WITH MACERegs,MaceVars
|
|
|
|
Move.l WDSPrm.WDSPtr(SP), D2 ; Get WDS ptr
|
|
Move.l A2, -(SP) ; Save C regs
|
|
|
|
MoveA.l MaceVarPtr, A2 ; Get ptr to my vars
|
|
|
|
Move SR,-(SP) ; Save interrupt mask level
|
|
OrI #DMALockOut, SR ; Disable DMA ints.
|
|
|
|
Move.l FreeXmtBuff(A2),D1 ; get a buffer pointer
|
|
Bne.s @haveBuff
|
|
|
|
Move (SP)+,SR ; Restore int. mask level
|
|
MoveA.l (SP)+, A2 ; Restore C regs
|
|
MoveQ #nobuff,D0 ; Set no xmit buff available error
|
|
Rts ; return to caller
|
|
@haveBuff
|
|
MoveA.l D1, A1 ; A1->buffer
|
|
IF BUFDEBUG THEN
|
|
CmpA.l XmitBuff.Next(A1), A1 ; linked to myself?
|
|
Bne.s @dok1
|
|
_Debugger ; yes, oooppppsss!
|
|
@dok1
|
|
CmpA.l InUseTxHead(A2), A1 ; on Free as well as InUse?
|
|
Bne.s @dok2
|
|
_Debugger ; yes, oooppppsss!
|
|
@dok2
|
|
ENDIF
|
|
Move.l XmitBuff.Next(A1),FreeXmtBuff(A2) ; unlink buffer from free list
|
|
Clr.l XmitBuff.Next(A1)
|
|
Move (SP)+,SR ; Restore int. mask level
|
|
;
|
|
; Total the length and make sure it's valid
|
|
;
|
|
Move.l A1, -(SP) ; save buffer pointer for later
|
|
|
|
Move.l A4, -(SP) ; save non-interrupt scratch reg.
|
|
|
|
Clr.w XmitBuff.Len(A1) ; init len
|
|
Move.l D2, A4 ; A4-> WDS
|
|
@1
|
|
MoveQ #0,D0
|
|
Move.w (A4), D0 ; get this wds entry length
|
|
Beq.s @2 ; all done
|
|
AddQ.w #6, A4 ; inc to next wds entry length
|
|
Add.w D0, XmitBuff.Len(A1) ; sum the length
|
|
Bra.s @1 ; look for more
|
|
@2
|
|
Move.w XmitBuff.Len(A1),D1 ; get single fragment length
|
|
Sub.w #EHdrSize,D1 ; Subtract out header bytes
|
|
Cmp.w #EMaxDataSz,D1 ; Check the data's length
|
|
Bls.s @cont ; Branch if ok
|
|
;
|
|
; Length error, relink buffer onto free list and return error
|
|
;
|
|
MoveA.l (SP)+, A4 ; restore non-interrupt scratch reg.
|
|
MoveA.l (SP)+, A1 ; Pop buff ptr
|
|
|
|
Move SR,-(SP) ; Save interrupt mask level
|
|
OrI #DMALockOut, SR ; Disable DMA ints.
|
|
|
|
Move.l FreeXmtBuff(A2), XmitBuff.Next(A1) ; link buffer back into free list
|
|
Move.l A1, FreeXmtBuff(A2)
|
|
|
|
Move (SP)+,SR ; Restore int. mask level
|
|
MoveA.l (SP)+, A2 ; Restore C regs
|
|
MoveQ #eLenErr,D0 ; Set length error
|
|
Rts ; Return it
|
|
;
|
|
; Copy WDS data to our Xmit buffer
|
|
;
|
|
@cont
|
|
MoveA.l XmitBuff.LogBufPtr(A1), A1 ; A1->packet data
|
|
MoveA.l D2, A4 ; A4-> WDS
|
|
@3
|
|
Move.w (A4)+, D0 ; last WDS entry?
|
|
Beq.s @4 ; yes, all done
|
|
MoveA.l (A4)+, A0 ; get pointer to the data
|
|
; A0->source, A1->dest, D0=len
|
|
MoveM.l A1/D0,-(SP) ; save buff ptr and len
|
|
Jsr ([MemMove,A2]) ; move the data
|
|
MoveM.l (SP)+,A1/D0
|
|
AddA.l D0, A1 ; update buff ptr
|
|
Bra.s @3 ; look for more
|
|
@4
|
|
MoveA.l (SP)+, A4 ; restore non-interrupt scratch reg.
|
|
; (SP) -> Xmit buffer ptr pushed earlier
|
|
|
|
MoveA.l (SP)+, A1 ; Pop buff ptr <LW9>
|
|
Move SR,-(SP) ; Save interrupt mask level <LW9>
|
|
OrI #DMALockOut, SR ; Disable DMA ints. <LW9>
|
|
Move.l A1, -(SP) ; Push buff ptr <LW9>
|
|
|
|
Jsr PrimeXmitRS
|
|
Bne.s @regsetsfull
|
|
AddQ #4, SP ; Strip parms
|
|
Move (SP)+, SR ; <LW9>
|
|
MoveA.l (SP)+, A2 ; Restore C regs
|
|
MoveQ #0, D0 ; Set return code & CC's
|
|
Rts ; Return
|
|
;
|
|
; We were NOT able to queue this buffer in a reg set
|
|
; Put this xmit buffer on xmit InUse queue
|
|
;
|
|
@regsetsfull
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, XmitRSFull(A2)
|
|
ENDIF
|
|
MoveA.l (SP)+, A1 ; Restore xmit buffer ptr
|
|
|
|
; Move SR,-(SP) ; Save interrupt mask level <LW9>
|
|
; OrI #DMALockOut, SR ; Disable DMA ints. <LW9>
|
|
|
|
Move.l InUseTxTail(A2), D1 ; Something on the queue?
|
|
Bne.s @11 ; Yes, branch
|
|
; Empty queue
|
|
Move.l A1, InUseTxTail(A2) ; Point tail at us
|
|
Move.l A1, InUseTxHead(A2) ; Point head at us
|
|
Bra.s @22
|
|
@11 ; Items on queue
|
|
Move.l D1, A0 ; Get tail
|
|
Move.l A1, XmitBuff.Next(A0) ; Put on end of queue
|
|
Move.l A1, InUseTxTail(A2) ; Make tail pt to us
|
|
@22
|
|
Clr.l XmitBuff.Next(A1)
|
|
|
|
Move (SP)+,SR ; Restore int. mask level
|
|
MoveA.l (SP)+, A2 ; Restore C regs
|
|
MoveQ #0, D0 ; Set return code & CC's
|
|
Rts ; Return
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
IF PROM THEN
|
|
;___________________________________________________________________________
|
|
;
|
|
; MACEXmitProm - xmit packet directly from user's buffer
|
|
;
|
|
; Call:
|
|
; 4(SP) - xmit buffer ptr
|
|
;
|
|
; Return:
|
|
; If xmit register sets are full, return CC==NE; else, CC==EQ.
|
|
; Notes:
|
|
; Called both on normal writes AND write completion (interrupt level 4)
|
|
;___________________________________________________________________________
|
|
|
|
MACEXmitProm PROC EXPORT
|
|
|
|
XmitPrm RECORD {A6Link}
|
|
LocalSize EQU *
|
|
A6Link DS.l 2
|
|
XmitPtr DS.l 1 ; Transmit buffer ptr
|
|
XmitLen DS.w 1 ; Transmit buffer len
|
|
ENDR
|
|
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,LAPMIBStats,XmitPrm
|
|
|
|
Link A6,#LocalSize ; Save A6
|
|
MoveM.l A2, -(SP)
|
|
MoveA.l MaceVarPtr, A2 ; Get ptr to my vars
|
|
|
|
Move SR,-(SP) ; Save interrupt mask level
|
|
OrI #DMALockOut, SR ; Disable DMA ints.
|
|
|
|
Move NxtXmitSet(A2), D2 ; get offset to next reg set to xmit on
|
|
MoveA.l PSCBase(A2), A0
|
|
Lea PSC_MACE_XMIT(A0), A0 ; A0-> Xmit DMA Channel base addr
|
|
@chkxmtdn Move CmdStat(A0,D2), D0 ; Get DMA status (word)
|
|
Btst #TERMCNT, D0 ; xfer in progress?
|
|
Beq.s @chkxmtdn ; yes, wait for it to complete
|
|
; no, we can use this set
|
|
;
|
|
; Initialize Xmit DMA Channel Register Set
|
|
;
|
|
Move.l XmitPtr(A6), A1 ; A1 - user xmit buffer ptr
|
|
IF SETDEBUG THEN
|
|
IF not SETDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a01 ; go to old PSC patch
|
|
Move.l A1, Addr(A0,D2) ; Set DMA dest addr to user buff ptr
|
|
Bra.s @aaa1
|
|
@a01
|
|
ENDIF
|
|
Move.l A1, D0
|
|
And.l #$FFFFFFF0, D0 ; line aligned addr
|
|
@a1 Move.l A1, Addr(A0,D2) ; Set DMA dest addr
|
|
Move.l Addr(A0,D2), D1
|
|
And.l #$FFFFFFF0, D1 ; line aligned addr
|
|
Cmp.l D0, D1
|
|
IF SETDEBUGFAIL THEN
|
|
Beq.s @aa1
|
|
_Debugger
|
|
Bra.s @a1
|
|
@aa1
|
|
ELSE
|
|
Bne.s @a1
|
|
ENDIF
|
|
@aaa1
|
|
ELSE
|
|
Move.l A1, Addr(A0,D2) ; Set DMA dest addr to user buff ptr
|
|
ENDIF
|
|
|
|
MoveQ #0, D0
|
|
Move XmitLen(A6), D0 ; Get pkt len (word)
|
|
IF SETDEBUG THEN
|
|
IF not SETDEBUGFAIL THEN
|
|
Tst.b hasNewPSC(A2)
|
|
Beq.s @a02 ; go to old PSC patch
|
|
Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long)
|
|
Bra.s @aaa2
|
|
@a02
|
|
ENDIF
|
|
@a2 Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long)
|
|
Move.l Cnt(A0,D2), D1
|
|
Cmp.l D0, D1
|
|
IF SETDEBUGFAIL THEN
|
|
Beq.s @aa2
|
|
_Debugger
|
|
Bra.s @a2
|
|
@aa2
|
|
ELSE
|
|
Bne.s @a2
|
|
ENDIF
|
|
@aaa2
|
|
ELSE
|
|
Move.l D0, Cnt(A0,D2) ; Set DMA byte count (long)
|
|
ENDIF
|
|
|
|
BTst #0, (A1) ; xmiting a multi/bcast?
|
|
MoveA.l LAPMIBStatPtr(A2), A1
|
|
Bne.s @30
|
|
AddQ.l #1, ifOutUcastPkts(A1) ; inc. non-multi/bcast cntr
|
|
Bra.s @31
|
|
@30 AddQ.l #1, ifOutNUcastPkts(A1) ; inc. multi/bcast cntr
|
|
@31 Add.l D0, ifOutOctets(A1) ; inc. sent octet cntr
|
|
|
|
Move #(1<<SENSE)+(1<<ENABLED), CmdStat(A0,D2) ; Enable set, set ints. disabled
|
|
|
|
BChg #4, D2 ; Toggle reg sets
|
|
Move D2, NxtXmitSet(A2) ; save offset to next reg set to xmit on
|
|
Move (SP)+, SR ; Restore int. mask level
|
|
Move.l (SP)+, A2
|
|
MoveQ #0, D0 ; Set CC's
|
|
Rts ; Return
|
|
|
|
ENDP
|
|
ENDIF
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; MaceXmitDone - transmit completion routine
|
|
;
|
|
; Call:
|
|
; 4(SP) - xmit buffer ptr
|
|
;
|
|
; Return:
|
|
; no return value/status
|
|
;
|
|
; Notes: called at interrupt level 4 (PSC DMA)
|
|
;___________________________________________________________________________
|
|
|
|
MaceXmitDone PROC
|
|
|
|
TxPrm RECORD 4
|
|
TxBuff DS.l 1 ; xmit buffer ptr
|
|
TxPrmSz EQU *
|
|
ENDR
|
|
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL
|
|
MoveA.l MaceVarPtr, A0 ; Get ptr to my vars
|
|
IF BUFDEBUG THEN
|
|
AddQ.l #1, XmtDnActive(A0)
|
|
CmpI.l #1, XmtDnActive(A0)
|
|
Beq.s @ok
|
|
_Debugger ; oooppppsss!
|
|
@ok
|
|
ENDIF
|
|
;
|
|
; Link completed xmit buffer back into free list
|
|
;
|
|
Move.l TxPrm.TxBuff(SP), A1 ; xmt buffer ptr
|
|
IF BUFDEBUG THEN
|
|
CmpA.l XmitBuff.Next(A1), A1 ; linked to myself?
|
|
Bne.s @dok1
|
|
_Debugger ; oooppppsss!
|
|
@dok1
|
|
CmpA.l FreeXmtBuff(A0), A1 ; on free list too?
|
|
Bne.s @dok2
|
|
_Debugger ; oooppppsss!
|
|
@dok2
|
|
ENDIF
|
|
Move.l FreeXmtBuff(A0), XmitBuff.Next(A1) ; Make us pt to head of freelist
|
|
Move.l A1, FreeXmtBuff(A0) ; Make us head of freelist
|
|
|
|
; Check to see if xmit's waiting
|
|
Move.l InUseTxHead(A0), D1 ; Any waiting xmit's?
|
|
Beq.s @inuseempty ; No, branch
|
|
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, InUseXmit(A0)
|
|
ENDIF
|
|
IF BUFDEBUG THEN
|
|
Cmp.l A1, D1 ; what we just xmitted should not still be on in use
|
|
Bne.s @dok6
|
|
_Debugger ; oooppppsss!
|
|
@dok6
|
|
ENDIF
|
|
; Remove this buffer, which is the head, from the xmit InUse queue
|
|
Move.l D1, A1
|
|
Move.l XmitBuff.Next(A1), D1 ; D1=0, no more items; D1!=0, more items
|
|
Move.l D1, InUseTxHead(A0) ; Dequeue xmit
|
|
Bne.s @notempty ; Branch if more than 1 xmit waiting
|
|
Move.l D1, InUseTxTail(A0) ; Clear tail; if here, head is clear too.
|
|
@notempty
|
|
Clr.l XmitBuff.Next(A1)
|
|
;
|
|
; One or more transmit(s) are waiting; send the head of the InUse list
|
|
; Note:
|
|
; If MaceXmit can't send pkt because both reg sets are in use, it puts the xmit buff
|
|
; on the TAIL of the InUse queue. However, we're the xmit completion routine, by definition
|
|
; a xmit reg set is now available so we'll call PrimeXmitRS directly and ignore the return code.
|
|
;
|
|
Move.l A0, -(SP) ; Save MaceVarPtr
|
|
Move.l A1, -(SP) ; SP-> buffer to xmit (InUseTxHead)
|
|
Jsr PrimeXmitRS
|
|
MoveA.l (SP)+, A1 ; A1-> buffer just xmitted
|
|
MoveA.l (SP)+, A0 ; Restore MaceVarPtr
|
|
|
|
IF BUFDEBUG THEN
|
|
CmpA.l XmitBuff.Next(A1), A1 ; linked to myself?
|
|
Bne.s @dok3
|
|
_Debugger ; oooppppsss!
|
|
@dok3
|
|
CmpA.l FreeXmtBuff(A0), A1 ; on free list too?
|
|
Bne.s @dok4
|
|
_Debugger ; oooppppsss!
|
|
@dok4
|
|
Move.l FreeXmtBuff(A0), D1
|
|
Cmp.l InUseTxHead(A0), D1 ; on both?
|
|
Bne.s @dok5
|
|
_Debugger ; oooppppsss!
|
|
@dok5
|
|
ENDIF
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, InUseXmitD(A0)
|
|
ENDIF
|
|
|
|
@inuseempty
|
|
Move.l XmtDnRtn(A0), D0
|
|
Beq.s @skip ; no xmit completion rtn
|
|
Move.l A0, -(SP) ; Save A0
|
|
Move.l XmtDnParm(A0), -(SP) ; Push user parm
|
|
MoveA.l D0, A0
|
|
Jsr (A0) ; Call user xmit completion rtn
|
|
AddQ #4, SP ; Strip parms
|
|
MoveA.l (SP)+, A0 ; Restore A0
|
|
@skip
|
|
IF BUFDEBUG THEN
|
|
SubQ.l #1, XmtDnActive(A0)
|
|
ENDIF
|
|
Rts
|
|
|
|
ENDP
|
|
EJECT
|
|
;___________________________________________________________________________
|
|
;
|
|
; MaceRecv - Deferred Task Packet receive routine
|
|
;
|
|
; Call:
|
|
; A1 - our variables
|
|
; Received packet(s) in buffers in chain(s) on InUse Queue and, perhaps,
|
|
; in buffers in chain(s) on Register Sets.
|
|
;
|
|
; Return:
|
|
; Empty InUse Queue
|
|
;
|
|
; Destroys:
|
|
;
|
|
; Calls:
|
|
; Calls user's handler to receive packet.
|
|
;
|
|
; Notes:
|
|
; Since MaceRecv runs under DTMgr, more packets can arrive and
|
|
; get queued in chains on InUse queue while we're running. So,
|
|
; we'll loop using InUseRxHead to dequeue and process received packets.
|
|
; Once we've drained all chains from InUse, we check for packets in the
|
|
; chain on the active reg set.
|
|
; Installed via PSCInterrupt, called via Deferred Task Mgr.
|
|
; When the chain is ON the reg set, we compare Out & In, where
|
|
; In = Limit - Cnt. When the chain is on InUse, we compare Out & Limit.
|
|
;___________________________________________________________________________
|
|
|
|
MaceRecv PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,RecvBuff,RxChnDescr
|
|
WITH Dot3StatsEntry,LAPMIBStats
|
|
|
|
MoveM.l A2-A4/D3-D4,-(SP) ; save non-scratch regs
|
|
|
|
Move.l A1, A2 ; A2 -> Mace vars
|
|
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, MaceRcvCnt(A2)
|
|
ENDIF
|
|
;
|
|
; Check InUse queue for recv chains
|
|
;
|
|
Move SR,-(SP) ; Save interrupt mask level
|
|
OrI #DMALockOut, SR ; Disable DMA ints.
|
|
@recvnext
|
|
Move.l InUseRxHead(A2), D0 ; recv chain(s) in InUse?
|
|
Beq @chksets ; no
|
|
MoveA.l D0, A4
|
|
Move.l NextChn(A4), D0 ; Another chain in queue?
|
|
Bne.s @1 ; yes
|
|
Move.l D0, InUseRxTail(A2) ; Clear tail
|
|
@1 Move.l D0, InUseRxHead(A2) ; Make head pt to next entry
|
|
Clr.l NextChn(A4)
|
|
|
|
Move (SP)+, SR ; Restore SR
|
|
|
|
IF BUFDEBUG THEN
|
|
Move.l A4, CurrRecv(A2)
|
|
ENDIF
|
|
;
|
|
; Loop until Out == Limit, delivering packets to .ENET
|
|
;
|
|
@dochain
|
|
Move Limit(A4), D0
|
|
Cmp Out(A4), D0 ; are there packets to process?
|
|
Beq.s @chaindone ; no
|
|
|
|
Bsr GetPkt ; Get pkt at Out and deliver it
|
|
|
|
Bra.s @dochain ; check for more pkts
|
|
|
|
@chaindone
|
|
;
|
|
; Queue the now empty recv chain onto head of Free list. First check if either reg set
|
|
; needs to be primed since there may have been NO freechains when the DMA interrupt
|
|
; handler wanted to prime the reg set.
|
|
;
|
|
MoveA.l A4, A1 ; A1-> now empty chain descr
|
|
|
|
Move SR,-(SP) ; Save interrupt mask level
|
|
OrI #DMALockOut, SR ; Disable DMA ints.
|
|
|
|
|
|
Move ActRecvSet(A2), D4 ; get offset to active reg set
|
|
Move #1, D3 ; init loop cntr
|
|
MoveA.l PSCBase(A2), A3
|
|
Lea PSC_MACE_RECV(A3), A3 ; A3-> Recv Channel base address
|
|
@chkset Tst.l RxChainSet0(A2,D4) ; Reg Set0/1 need priming?
|
|
Bne.s @chk1 ; no
|
|
Bsr InitRecv ; Prime it
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, (DTprimeSet0,A2,D4)
|
|
ENDIF
|
|
Bra @recvnext ; Go check InUse list
|
|
@chk1
|
|
BChg #4, D4 ; Toggle reg sets ;
|
|
DBra D3, @chkset
|
|
; Put chain on free list
|
|
Move.l FreeRxChain(A2), NextChn(A1) ; Make us pt to current head of free list
|
|
Move.l A1, FreeRxChain(A2) ; Make us new head of free list
|
|
Bra @recvnext ; Go check InUse list
|
|
|
|
;
|
|
; We've drained all packets in chains on InUse queue, now check for packets
|
|
; in chains still on reg sets. We know ActRecvSet is valid since we just checked
|
|
; InUse queue and DMA ints are still masked. ActRecvSet assures us we'll process
|
|
; pkts in the correct order; ie. InUse head to tail, then ActRecvSet.
|
|
@chksets
|
|
Move ActRecvSet(A2), D4 ; get offset to active reg set
|
|
MoveA.l RxChainSet0(A2,D4), A4 ; get active chain descr
|
|
|
|
MoveA.l PSCBase(A2), A3
|
|
Lea PSC_MACE_RECV(A3), A3 ; A3-> Recv Channel base address
|
|
|
|
@domore
|
|
; We want to get Limit while ints are off to ensure we calculate "In" with the "real"
|
|
; limit and not with the "flush" value of limit. We want to get Cnt while ints are off to
|
|
; ensure Cnt value is Cnt for our chain. If ints we're on, we could take an int, reprime
|
|
; the reg set with a new chain, and Cnt would no longer refer to our chain.
|
|
Move Limit(A4), D1 ; get Limit
|
|
Move.l Cnt(A3,D4), D2 ; get current cnt
|
|
|
|
; Here, we don't care any more if chain is on or off reg set. We can recv the pkt at Out.
|
|
; However, we'll keep ints masked until after we clear DTInstalled. This prevents a race cond.
|
|
; where a recv/xmit int could occur between here and @exit. It could happen when we're here
|
|
; and there's 1 buffer left in chain (Out = Limit - 1). The int. hnldlr (ChkRecv) could run
|
|
; and would clear ints on the set then NOT install us since we're already installed. We'd
|
|
; leave but no more ints will happen on the set. If the other set is not primed, we'll never
|
|
; get called again.
|
|
Sub D2, D1 ; D1 = In = Limit - Cnt
|
|
IF BUFDEBUG THEN
|
|
Move D1, In(A4) ; save In
|
|
ENDIF
|
|
Cmp Out(A4), D1 ; Out == In?
|
|
Beq.s @exit ; yes, no more packets to recv
|
|
|
|
Move (SP), SR ; Restore int mask level
|
|
|
|
Bsr.s GetPkt ; Get pkt at Out and deliver it
|
|
;
|
|
; Verify chain we're processing is still on reg set. If not, its moved to InUse queue.
|
|
;
|
|
OrI #DMALockOut, SR ; Disable DMA ints.
|
|
|
|
Btst #OnOffSet, State(A4) ; Is chain still on reg set?
|
|
Beq @recvnext ; no, go drain it from InUse
|
|
Bra.s @domore ; yes, go check for more pkts
|
|
|
|
@exit Clr.b DTInstalled(A2) ; Indicate Deferred Task NOT Installed
|
|
Move #(1<<SENSE)+(1<<IE), CmdStat(A3,D4) ; re-enable set ints.
|
|
|
|
Move (SP)+, SR ; Restore int mask level
|
|
MoveM.l (SP)+, A2-A4/D3-D4 ; Restore used C registers
|
|
Rts ; That's it
|
|
|
|
; A4 - ptr to chain, A2 - global ptr
|
|
GetPkt
|
|
MoveM.l A5-A6, -(SP)
|
|
|
|
MoveQ #0, D0
|
|
MoveQ #11, D1
|
|
Move Out(A4), D0 ; get Out, segment number with pkt
|
|
Lsl.l D1, D0 ; Out = Out * 2**11 (RxBuffSz=2048)
|
|
Add.l LogChnPtr(A4), D0 ; compute address of segment <SM10>
|
|
MoveA.l D0, A0 ; A0-> segment in chain
|
|
Lea MaceStat(A0), A1 ; pt to Mace status
|
|
MoveA.l LAPMIBStatPtr(A2), A5 ; pt to LAP stats
|
|
MoveA.l Dot3StatPtr(A2), A6 ; pt to DOT3 stats
|
|
;
|
|
; Retrieve status bytes from beginning of buffer. Each status byte is present in
|
|
; the high and low bytes of a word. There are 4 status bytes, so there are 8 bytes
|
|
; of status.
|
|
;
|
|
Move (A1)+, D2 ; Get Byte Cnt(7-0)
|
|
MoveQ #0, D1
|
|
Move.b D2, D1
|
|
Add.l D1, ifInOctets(A5)
|
|
|
|
Move (A1)+, D1 ; Get Status(in bits 7-4) and
|
|
; Byte Cnt(11-8) in bits 3-0
|
|
Move.b D1, D0
|
|
AndI #(1<<RcvCLSN)+(1<<RcvFRAM)+(1<<RcvFCS), D0 ; get status bits for user
|
|
Move.l D0, -(SP) ; pass status to user later
|
|
|
|
Move (A1)+, D0 ; Get Runt pkt cnt
|
|
Move.b D0, 0(SP)
|
|
Move (A1), D0 ; Get Collision cnt
|
|
Move.b D0, 1(SP)
|
|
|
|
Btst #RcvOFLO, D1 ; Overflow Error?
|
|
Beq.s @s1
|
|
AddQ.l #1, dot3StatsInternalMacReceiveErrors(A6)
|
|
Bra.s @donext ; can't deliver to user
|
|
|
|
@s1 AndI.b #(1<<RcvCLSN)+(1<<RcvFRAM)+(1<<RcvFCS), D1 ; Receive Status Error?
|
|
Beq.s @s4 ; Note: only lower status/len byte trashed
|
|
|
|
AddQ.l #1, ifInErrors(A5)
|
|
Btst #RcvFCS, D1 ; FCS Error?
|
|
Beq.s @s2
|
|
AddQ.l #1, dot3StatsFCSErrors(A6)
|
|
@s2 Btst #RcvFRAM, D1 ; Framing Error?
|
|
Beq.s @s3
|
|
AddQ.l #1, dot3StatsAlignmentErrors(A6)
|
|
@s3 Btst #RcvCLSN, D1 ; Collsion Error?
|
|
Beq.s @s4
|
|
AddQ.l #1, COLLCnt(A2) ; Yes
|
|
AddQ.l #1, dot3StatsLateCollisions(A6) ; xmit & recv cntr
|
|
|
|
@s4
|
|
AndI #$0f00, D1 ; Get len from upper status/len byte
|
|
AndI #$00ff, D2 ; Ignore upper copy of len byte
|
|
Or D1, D2 ; Compute length of recv'd pkt
|
|
Move D2, -(SP) ; pass recv pkt len
|
|
;
|
|
; Call user's receive routine
|
|
;
|
|
Pea Packet(A0) ; Pass recv packet ptr
|
|
Move.l A0, -(SP) ; Pass recv buffer ptr
|
|
Move.l RcvParm(A2), -(SP) ; Pass user's rcv rtn parm
|
|
MoveA.l RcvRtn(A2), A0 ; User's rcv rtn
|
|
Jsr (A0) ; Call user's rcv rtn
|
|
Add #RcvParms.ParmsSz, SP ; strip parms
|
|
|
|
@done AddQ #1, Out(A4) ; inc out
|
|
MoveM.l (SP)+, A5-A6
|
|
Rts
|
|
|
|
@donext AddQ #4, SP ; pop status
|
|
Bra.s @done
|
|
|
|
ENDP
|
|
EJECT
|
|
;___________________________________________________________________________
|
|
;
|
|
; MaceInterrupt - Process interrupts from MACE
|
|
;
|
|
; Call:
|
|
; A1 - Our variables
|
|
;
|
|
; Return:
|
|
; D0=1, indicate interrupt was serviced
|
|
;
|
|
; Destroys:
|
|
;
|
|
; Calls:
|
|
; none
|
|
;
|
|
; Notes: Mace interrupts at Level 3
|
|
;
|
|
; Primary function is to read the MACE trasmit status upon receipt of the
|
|
; Transmit Completion interrupt. Also, reads and processes interrupts for
|
|
; error conditions.
|
|
;___________________________________________________________________________
|
|
|
|
MaceInterrupt PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL,Dot3StatsEntry,LAPMIBStats
|
|
MoveM.l A0/A2/A3/D1, -(SP) ; Save regs
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, MaceIntCnt(A1)
|
|
ENDIF
|
|
|
|
Move.l MACEBase(A1), A0 ; Base address of Mace
|
|
Move.b MACE_INT(A0), D0 ; Get Mace Interrupt Status
|
|
AndI.b #~OurIntsMask, D0 ; Process only the ones we want
|
|
Beq @done ; no ints we care about, leave
|
|
|
|
MoveA.l LAPMIBStatPtr(A1), A2
|
|
MoveA.l Dot3StatPtr(A1), A3
|
|
;
|
|
; Process Transmit Completion Interrupt
|
|
;
|
|
BTst #XMTINT, D0 ; Xmit done int?
|
|
Beq @rcvco ; no, check for err int.
|
|
|
|
; Read Mace Transmit Status
|
|
MoveQ #0, D1
|
|
Move.b MACE_TX_RETRY_CNT(A0), D1 ; Read Xmit Retry Count
|
|
Add.l D1, XmtRTRYCnt(A1)
|
|
Move.b MACE_TX_FRM_STAT(A0), D1 ; Read Xmit Frame Status
|
|
BTst #XMTSV, D1 ; Is status valid?
|
|
Bne.s @10 ; yes, continue
|
|
AddQ.l #1, XmtStatINV(A1)
|
|
Bra @rcvco
|
|
|
|
@10 Move.b D1, -(SP) ; save D1
|
|
AndI.b #(1<<UFLO)+(1<<LCOL)+(1<<RTRY), D1
|
|
Beq.s @1
|
|
AddQ.l #1, ifOutErrors(A2)
|
|
@1 Move.b (SP)+, D1 ; restore D1
|
|
|
|
BTst #UFLO, D1 ; Underflow?
|
|
Beq.s @2 ; no
|
|
AddQ.l #1, dot3StatsInternalMacTransmitErrors(A3)
|
|
|
|
@2 BTst #LCOL, D1 ; Late Collision?
|
|
Beq.s @3 ; no
|
|
AddQ.l #1, XmtLCOL(A1)
|
|
AddQ.l #1, dot3StatsLateCollisions(A3)
|
|
|
|
@3 BTst #LCAR, D1 ; Loss of Carrier?
|
|
Beq.s @4 ; no
|
|
AddQ.l #1, dot3StatsCarrierSenseErrors(A3)
|
|
|
|
@4 BTst #DEFER, D1 ; deferred?
|
|
Beq.s @5 ; no
|
|
AddQ.l #1, dot3StatsDeferredTransmissions(A3)
|
|
|
|
@5 BTst #RTRY, D1 ; 15 retries?
|
|
Beq.s @6 ; no
|
|
AddQ.l #1, dot3StatsExcessiveCollisions(A3)
|
|
Bra.s @rcvco ; Chk err since remaining
|
|
; bits can't be set
|
|
@6 BTst #MORE, D1 ; More than 1 retry?
|
|
Beq.s @7 ; no
|
|
AddQ.l #1, dot3StatsMultipleCollisionFrames(A3)
|
|
Bra.s @rcvco ; Chk err since remaining
|
|
; bits can't be set
|
|
@7 BTst #ONE, D1 ; Exactly 1 retry?
|
|
Beq.s @rcvco ; no
|
|
AddQ.l #1, dot3StatsSingleCollisionFrames(A3)
|
|
;
|
|
; Process Error Interrupts
|
|
;
|
|
@rcvco BTst #RCVCO, D0 ; Recv Collision Overflow count interrupt?
|
|
; Indicates RCV coll cntr rolled over from 255->0
|
|
Beq.s @mpci ; no
|
|
AddQ.l #1, RCVCOCnt(A1)
|
|
|
|
@mpci BTst #MPCO, D0 ; Missed packet count interrupt? This int.
|
|
; indicates MPC reg. rolled over from 255->0
|
|
Beq.s @cerr ; no
|
|
AddQ.l #1, MPCOCnt(A1)
|
|
Add.l #256, ifInErrors(A2)
|
|
|
|
|
|
@cerr BTst #CERR, D0 ; Collision error interrupt?
|
|
Beq.s @babl ; no
|
|
AddQ.l #1, dot3StatsSQETestErrors(A3)
|
|
AddQ.l #1, ifOutErrors(A2)
|
|
|
|
@babl BTst #BABL, D0 ; Babble error interrupt?
|
|
IF COUNTERS THEN
|
|
Beq.s @chkrcv ; no
|
|
AddQ.l #1, dot3StatsFrameTooLongs(A3)
|
|
AddQ.l #1, ifOutErrors(A2)
|
|
|
|
@chkrcv BTst #RCVINT, D0 ; Recv int?
|
|
Beq.s @done ; no, check ints.
|
|
AddQ.l #1, RcvInts(A1)
|
|
ELSE
|
|
Beq.s @done ; no
|
|
AddQ.l #1, dot3StatsFrameTooLongs(A3)
|
|
AddQ.l #1, ifOutErrors(A2)
|
|
ENDIF
|
|
|
|
@done MoveM.l (SP)+, A0/A2/A3/D1
|
|
MoveQ #1, D0 ; Indicate int. was serviced
|
|
RtS ; Return from MaceInterrupt
|
|
|
|
ENDP
|
|
EJECT
|
|
;___________________________________________________________________________
|
|
;
|
|
; PSCInterrupt - Process DMA Interrupt from PSC
|
|
;
|
|
; Call:
|
|
; A1 - our variables
|
|
;
|
|
; Return:
|
|
; D0=1, Indicate Interrupt was serviced
|
|
;
|
|
; Destroys:
|
|
; A2 - our variables
|
|
; A3 - Receive or Transmit DMA Channel base address
|
|
; D4.b - Register Set offset, 0 or $10
|
|
;
|
|
; Calls:
|
|
; PrimeRecv - reprime a Recv DMA reg set
|
|
; MaceXmitDone - read Xmit status and reprime Xmit DMA regs if needed
|
|
;
|
|
; RePrime Receive and Transmit Register Sets. Install Deferred Task to
|
|
; process Received Packets and Transmit Completions.
|
|
;___________________________________________________________________________
|
|
|
|
PSCInterrupt PROC
|
|
WITH MACERegs,MaceVars,PSC_DMA_CHNL
|
|
|
|
MoveM.l A0/A2-A3/D1-D4, -(SP) ; Save regs
|
|
Move.l A1, A2 ; A2 -> our variables
|
|
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, PSCIntCnt(A2)
|
|
ENDIF
|
|
;
|
|
; Check for packet in Receive DMA Channel
|
|
;
|
|
; If bus error, go handle it, make sure DT installed, then check for xmit done int.
|
|
; Else
|
|
; If set's chain is full, reprime set and install DT. Loop back and check the other
|
|
; set, ONLY so we can, if needed, disable ints for this set. Note: DT checks
|
|
; "active set" after draining InUse.
|
|
; Else set's chain is NOT full, disable ints for set, install DT, and leave.
|
|
;
|
|
ChkRecv
|
|
MoveA.l PSCBase(A2), A0
|
|
Move PSC_MACE_RECV_CNTL(A0), D1
|
|
BTst #BERR, D1 ; Bus Error on recv channel?
|
|
Beq.s @noberr ; no
|
|
Bsr RecvBusErr ; go handle it
|
|
Bra.s @rcvberrcont ; go make sure DT installed
|
|
|
|
@noberr BTst #CIRQ, D1 ; Interrupt on recv channel?
|
|
Beq.s ChkXmitDone ; no, check xmit channel
|
|
|
|
Lea PSC_MACE_RECV(A0), A3 ; A3-> Recv Channel base address
|
|
Move ActRecvSet(A2), D4 ; D4-> offset to reg set
|
|
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, (RecvSet0Cnt,A2,D4) ; inc count for set
|
|
ENDIF
|
|
IF DEBUG THEN
|
|
Move CmdStat(A3,D4), D1 ; Get command/status
|
|
BTst #IF, D1 ; Recv packet?
|
|
Bne.s @ok1
|
|
_Debugger ; no, actrecvset screwed up?
|
|
@ok1
|
|
ENDIF
|
|
Move #(1<<IF)+(1<<IE), CmdStat(A3,D4) ; Clear set int & int ENABLE
|
|
; If chain not full:
|
|
; we'll get another DMA int. for 2 cases: 1-DT recvs pkt and re-enables
|
|
; ints for this set; 2-all of chain's buffers fill up, PSC switches sets, and
|
|
; first pkt on new set causes int.
|
|
; Else chain is full:
|
|
; we'll re-enable ints when set is reprimed.
|
|
|
|
Move.l Cnt(A3,D4), D1 ; get reg set DMA cnt
|
|
Beq.s @chnfull ; bra if chain full
|
|
|
|
@rcvberrcont
|
|
Pea ChkXmitDone ; push return address so we leave ChkRecv
|
|
|
|
@installDT
|
|
Tst.b DTInstalled(A2) ; Is Deferred Task already installed?
|
|
IF COUNTERS THEN
|
|
Beq.s @33 ; no, go install it
|
|
AddQ.l #1, noDTInstall(A2) ; Yes, don't install it again
|
|
Bra.s @donerecv
|
|
@33
|
|
ELSE
|
|
Bne.s @donerecv ; Yes, don't install it again
|
|
ENDIF
|
|
ST DTInstalled(A2) ; Indicate Deferred Task Installed
|
|
IF USEDEFERREDTASK THEN
|
|
Lea DTQE(A2), A0 ; A0->deferred task queue element
|
|
MoveA.l JDTInstall, A1
|
|
Jmp (A1) ; install deferred task
|
|
ELSE
|
|
Move SR, -(SP)
|
|
Move #$0300, D0 ; Disable ² l3 ints.
|
|
_SETINTMASK D0
|
|
Lea MaceRecv, A0
|
|
MoveA.l A2, A1
|
|
Jsr (A0)
|
|
Move (SP)+, SR
|
|
ENDIF
|
|
@donerecv Rts
|
|
|
|
@chnfull Bsr PrimeRecv ; All of chain's buffers are full,
|
|
; reprime reg set with new chain
|
|
Bsr.s @installDT ; make sure DT installed
|
|
Bra.s ChkRecv ; go check other reg set
|
|
|
|
;
|
|
; Check for Transmit Completion Interrupt
|
|
;
|
|
ChkXmitDone
|
|
MoveA.l PSCBase(A2), A0
|
|
Move PSC_MACE_XMIT_CNTL(A0), D1
|
|
BTst #BERR, D1 ; Bus Error on xmit channel?
|
|
Beq.s @noberr ; no
|
|
Bsr XmitBusErr ; yes, go handle it
|
|
Bra.s @donePSCInt
|
|
|
|
@noberr BTst #CIRQ, D1 ; Interrupt on xmit channel?
|
|
Beq.s @donePSCInt ; no, leave
|
|
|
|
Lea PSC_MACE_XMIT(A0), A3 ; A3-> Xmit Channel base address
|
|
Move ActXmitSet(A2), D4 ; get offset to active reg set
|
|
|
|
IF COUNTERS THEN
|
|
AddQ.l #1, (XmitSet0Cnt,A2,D4) ; inc count for set
|
|
ENDIF
|
|
IF DEBUG THEN
|
|
Move CmdStat(A3,D4), D1 ; Get command/status
|
|
BTst #IF, D1 ; Xmit done packet?
|
|
Bne.s @ok1
|
|
_Debugger ; no, ActXmitSet screwed up?
|
|
@ok1
|
|
ENDIF
|
|
Move #(1<<IF), CmdStat(A3,D4) ; Clear int flag in command/status
|
|
; Process Xmit completion interrupt
|
|
Lea TxBuffSet0(A2), A0
|
|
IF BUFDEBUG THEN
|
|
Move.l (A0,D4), D0 ; get xmit buffer address
|
|
Bne.s @ok2 ; got one
|
|
_Debugger ; no, ActXmitSet screwed up?
|
|
@ok2
|
|
ENDIF
|
|
Move.l (A0,D4), -(SP) ; Push xmit buffer address
|
|
Clr.l (A0,D4) ; Indicate MaceXmit can use reg set
|
|
BChg #4, D4
|
|
Move D4, ActXmitSet(A2) ; update active reg set
|
|
Bsr MaceXmitDone
|
|
AddQ #4, SP ; Strip parms
|
|
|
|
Bra.s ChkXmitDone ; go check other reg set
|
|
|
|
@donePSCInt MoveQ #1, D0 ; Indicate interrupt was serviced
|
|
MoveM.l (SP)+, A0/A2-A3/D1-D4
|
|
|
|
Rts ; Return from PSCInterrupt
|
|
|
|
ENDP
|
|
EJECT
|
|
|
|
;___________________________________________________________________________
|
|
;
|
|
; MaceInit - Get var and DMA memory, then initialize DMA Register Sets and
|
|
; MACE chip
|
|
;
|
|
; Call: following record on stack:
|
|
;
|
|
; MACEInitParms RECORD 0
|
|
; RecvRtn DS.l 1 ; address of Ethernet receive routine
|
|
; RecvPrms DS.l 1 ; parms to pass @ receive
|
|
; XmitRtn DS.l 1 ; address of Ethernet xmit complete routine
|
|
; XmitPrms DS.l 1 ; parms to pass @ xmit complete
|
|
; MACECfgPtr DS.l 1 ; ptr to MACE config record
|
|
; Dot3NetStats DS.l 1 ; ptr to 802.3 statistics array
|
|
; LAPMIBNetStats DS.l 1 ; ptr to LAP MIB statistics array
|
|
; EnetAddr DS.l 1 ; ptr to ethernet address
|
|
; FastMoveRtn DS.l 1 ; ->proc to move memory FAST
|
|
; IPSize EQU *
|
|
;
|
|
; Return:
|
|
; D0 = openErr (-23) or mFulErr (-41)
|
|
;___________________________________________________________________________
|
|
|
|
MaceInit PROC EXPORT
|
|
|
|
parms RECORD {A6Link}
|
|
LocalSize EQU *
|
|
A6Link DS.l 2 ; link and return address
|
|
initp DS MACEInitParms ; parameters passed to us
|
|
ENDR
|
|
|
|
IMPORT TranslateAddress, GetMemory, FreeMemory
|
|
WITH parms,initp,MACERegs,MaceVars,PSC_DMA_CHNL,PSC_INT_TBL
|
|
|
|
Link A6,#LocalSize ; Save A6
|
|
MoveM.l A2-A4/D3-D5,-(SP) ; Save regs
|
|
|
|
WITH GetMem
|
|
Sub.l #GetMemSz, SP ; room for results
|
|
Move.l #MaceVarSz, memsize(SP) ; requested memory size
|
|
Move.l #0, memoptions(SP) ; do NOT want memory locked,
|
|
; contiguous, and non-cacheable
|
|
Pea MaceVarPtr
|
|
Move.l (SP)+, memhndl(SP)
|
|
Lea GetMemory, A0
|
|
Jsr (A0) ; get memory
|
|
Add.l #GetMemSz, SP ; pop parms
|
|
Blt @InitError ; bra if error
|
|
ENDWITH
|
|
MoveA.l MaceVarPtr, A2 ; get ptr to my vars
|
|
|
|
Move.l UnivInfoPtr, A0 ; get ptr to ProductInfo
|
|
Add.l ProductInfo.DecoderInfoPtr(A0), A0 ; point to the base address table
|
|
Move.l DecoderInfo.PSCAddr(A0), PSCBase(A2) ; Save the PSC base address
|
|
|
|
Move.l RecvRtn(A6), RcvRtn(A2) ; save addr of recv rtn
|
|
Move.l RecvPrms(A6), RcvParm(A2) ; save parm for recv rtn
|
|
|
|
Move.l XmitRtn(A6), XmtDnRtn(A2) ; save addr of xmit compl rtn
|
|
Move.l XmitPrms(A6), XmtDnParm(A2) ; save parm for xmit compl rtn
|
|
|
|
Move.l MACECfgPtr(A6), A4
|
|
Move.l MACECfg.MACEBase(A4), MACEBase(A2)
|
|
Move.l A4, MCfg(A2) ; save ptr to MACE config record
|
|
|
|
Move.l Dot3NetStats(A6), Dot3StatPtr(A2)
|
|
Move.l LAPMIBNetStats(A6), LAPMIBStatPtr(A2)
|
|
|
|
Move.l EnetAddr(A6), OurAddrPtr(A2) ; save ptr to our Ethernet address
|
|
|
|
Move.l FastMoveRtn(A6), MemMove(A2) ; save addr of fast mem move rtn
|
|
|
|
MoveQ #0, D0 ; initialize some regs
|
|
Move.l D0, D2
|
|
Move.l D0, D3
|
|
Move.l D0, D5
|
|
Move MACECfg.XmitBuffs(A4), D2
|
|
Bne.s @10
|
|
Move #DefTxBuffs, D2 ; 0 passed in, set to default
|
|
@10 Move MACECfg.RecvBuffs(A4), D3
|
|
Bne.s @11
|
|
Move #DefRxBuffs, D3 ; 0 passed in, set to default
|
|
@11 Move MACECfg.RecvChains(A4), D5
|
|
Bne.s @12
|
|
Move #DefChns, D5 ; 0 passed in, set to default
|
|
@12 ; force 1 ² recv chains ² max
|
|
CmpI #OneChn, D5 ; 1 recv chain?
|
|
Bne.s @chkmax ; no
|
|
CmpI #MaxBufpChn, D3 ; too many buffers in our 1 chain?
|
|
Bls.s @GetMem ; no
|
|
Move #MaxBufpChn, D3 ; reset # of buffers to max allowed
|
|
Bra.s @GetMem
|
|
|
|
@chkmax CmpI #MaxChns, D5 ; must be ² max allowed
|
|
Bls.s @cont1
|
|
Move #MaxChns, D5
|
|
@cont1 Move D5, MACECfg.RecvChains(A4) ; set # of chains
|
|
|
|
Move D5, D0 ; D0.w=# of chains
|
|
Move D3, D5 ; D5.l=# of recv buffers
|
|
DivU D0, D5 ; D5.l=# of buffers per chain in low word
|
|
Swap D5 ; get remainder in low word
|
|
Tst D5 ; was there a remainder?
|
|
Beq.s @noremndr ; no
|
|
Sub D5, D3 ; adjust # recv buffers down so
|
|
; same # per chain
|
|
Clr D5 ; clear remainder
|
|
@noremndr Swap D5 ; get back # of buffers per chain
|
|
|
|
CmpI #MaxBufpChn, D5 ; too many buffers per chain?
|
|
Bls.s @chkmin ; no
|
|
Move #MaxBufpChn, D5 ; reset # of buffers to max allowed
|
|
Bra.s @cont2
|
|
@chkmin CmpI #MinBufpChn, D5 ; too few buffers per chain?
|
|
Bhs.s @Getmem ; no
|
|
Move #MinBufpChn, D5 ; reset # of buffers to min allowed
|
|
Move #DefChns, MACECfg.RecvChains(A4) ; reset # of chains
|
|
@cont2 Move D5, D3 ; D3=# of buffers per chain
|
|
Move MACECfg.RecvChains(A4), D1 ; D1=# of chains
|
|
MulU D1, D3 ; D3.l=total # of recv buffers
|
|
|
|
@GetMem
|
|
Move D2, D4 ; D4=# xmit buffers
|
|
Move #XmitBuff.TxBuffSz, D0
|
|
MulU D4, D0 ; D0.l=memory for xmit buffers
|
|
|
|
Move D3, D4 ; D4=# recv buffers
|
|
Move #RecvBuff.RxBuffSz, D1 ; size of a recv buffer
|
|
MulU D1, D4 ; D4.l=memory for recv buffers, used later
|
|
|
|
Add.l D4, D0 ; D0=memory for recv & xmit buffers
|
|
AddI.l #RecvBuff.RxBuffSz, D0 ; add 1 since we must 2K align recv buffs
|
|
|
|
WITH GetMem
|
|
Sub.l #GetMemSz, SP ; room for results
|
|
Move.l D0, memsize(SP) ; requested memory size
|
|
Move.l #(1<<Locked)+(1<<Contig)+(1<<CacheOff), memoptions(SP) ; want memory locked,
|
|
; contiguous, and non-cacheable
|
|
Pea MACEmem(A2)
|
|
Move.l (SP)+, memhndl(SP)
|
|
Pea RecvBuffMem(A2)
|
|
Move.l (SP)+, memhndla(SP)
|
|
Pea RecvXmitMemSz(A2)
|
|
Move.l (SP)+, memhndlasz(SP)
|
|
Lea GetMemory, A0
|
|
Jsr (A0) ; get memory
|
|
Add.l #GetMemSz, SP ; pop parms
|
|
ENDWITH
|
|
Beq.s @haveMem ; bra if NO error
|
|
|
|
SubQ #1, D2 ; adjust # xmit buffers first
|
|
Bgt.s @GetMem
|
|
|
|
MoveQ #1, D2 ; set to mininum of one xmit buf
|
|
Sub.l D5, D3 ; now adjust # recv buffers, by #
|
|
; of recv buffers per chain
|
|
; Note: if OneChn, D5 = 1
|
|
CmpI #OneChn, D5 ; 1 recv chain?
|
|
Bne.s @decchn ; no
|
|
CmpI #MinBufpChn,D3 ; less than min # bufs/chn?
|
|
Blo.s @err ; yes
|
|
Bra.s @GetMem ; try for mem while ³ MinBufpChn
|
|
@decchn SubI #1, MACECfg.RecvChains(A4) ; dec. # of chains
|
|
Bgt.s @GetMem ; try for mem while ³ OneChn
|
|
|
|
@err Move.w #mFulErr, D0
|
|
Bra @InitError ; get out with error
|
|
|
|
@haveMem
|
|
Move D2, MACECfg.XmitBuffs(A4) ; save # of xmit buffs
|
|
Move D3, MACECfg.RecvBuffs(A4) ; save # of recv buffs
|
|
|
|
Move.l RecvBuffMem(A2), D0 ; get ptr to aligned mem
|
|
Add.l D4, D0 ; D0 = Recv ptr + recv mem size
|
|
Move.l D0, XmitBuffMem(A2) ; save xmit mem ptr
|
|
;
|
|
; GetMem for recv chain descriptors
|
|
;
|
|
WITH RecvBuff,RxChnDescr
|
|
Move MACECfg.RecvChains(A4), D4
|
|
Mulu #RxChnDescrSz, D4 ; D4.l = recv chain descr size
|
|
|
|
WITH GetMem
|
|
Sub.l #GetMemSz, SP ; room for results
|
|
Move.l D4, memsize(SP) ; requested memory size
|
|
Move.l #0, memoptions(SP) ; do NOT want memory locked,
|
|
; contiguous, and non-cacheable
|
|
Pea ChnDescrMem(A2)
|
|
Move.l (SP)+, memhndl(SP)
|
|
Lea GetMemory, A0
|
|
Jsr (A0) ; get memory
|
|
Add.l #GetMemSz, SP ; pop parms
|
|
Blt @InitError ; bra if error
|
|
ENDWITH
|
|
|
|
Move.l ChnDescrMem(A2), D0
|
|
Move.l D0, FreeRxChain(A2) ; set up ptr to chain descr's
|
|
;
|
|
; Initialize recv buffer chains
|
|
;
|
|
MoveA.l D0, A3 ; get recv chain descr ptr
|
|
Move.l RecvBuffMem(A2), LogChnPtr(A3) ; pt chain descr at chain
|
|
|
|
Move MACECfg.RecvChains(A4), D1 ; # of chains
|
|
CmpI #OneChn, D1 ; do we have only 1 chain?
|
|
Bne.s @r4 ; no
|
|
Move MACECfg.RecvBuffs(A4), D5 ; yes, D5 contain total # of recv buffers
|
|
@r4
|
|
Move D5, D3 ; get # buffers per chain
|
|
MulU #RxBuffSz, D3 ; D3.l = size of chain
|
|
@r3
|
|
; Initialize chain head
|
|
Move D5, savedLimit(A3) ; Set chain limit
|
|
Move #0, Out(A3)
|
|
IF BUFDEBUG THEN
|
|
Move #0, In(A3)
|
|
ENDIF
|
|
MoveM.l D1/D2, -(SP) ; Save used C-scratch regs
|
|
Move.l D3, -(SP) ; logical size of chain
|
|
Move.l LogChnPtr(A3), -(SP) ; logical address of chain
|
|
Lea TranslateAddress, A0
|
|
Jsr (A0) ; get physical address in D0
|
|
AddQ #8, SP ; trash parms
|
|
MoveM.l (SP)+, D1/D2 ; restore used C-scratch regs
|
|
Blt @InitError
|
|
Move.l D0, PhyChnPtr(A3) ; save physical address of chain
|
|
|
|
SubQ #1, D1 ; are we done?
|
|
Beq.s @done ; yes
|
|
Lea RxChnDescrSz(A3), A0 ; compute ptr to next chain descr
|
|
Move.l A0, NextChn(A3) ; make us pt to next chain descr
|
|
MoveA.l LogChnPtr(A3), A1
|
|
AddA.l D3, A1 ; compute addr of next chain
|
|
Move.l A1, LogChnPtr(A0) ; save addr of next chain
|
|
Move.l A0, A3 ; pt to next chain descr
|
|
Bra.s @r3 ; process next chain
|
|
@done
|
|
ENDWITH
|
|
;
|
|
; Link together xmit buffers
|
|
;
|
|
WITH XmitBuff
|
|
Move.l XmitBuffMem(A2), FreeXmtBuff(A2)
|
|
MoveA.l FreeXmtBuff(A2), A0 ; Get Xmit header pointer
|
|
MoveQ #0, D0
|
|
Move MACECfg.XmitBuffs(A4), D0 ; get # xmit buffers
|
|
SubQ #1,D0 ; adjust loop count
|
|
Bra.s @x1
|
|
@x2
|
|
Lea TxBuffSz(A0), A1 ; A1-> next buffer address
|
|
Move.l A1, Next(A0) ; set link to next buffer
|
|
MoveA.l A1, A0 ; point to next buffer
|
|
@x1
|
|
DBra D0,@x2 ; do them all
|
|
Clr.l Next(A0) ; clear last buffer's next ptr
|
|
;
|
|
; Get and save physical address of each transmit buffer's packet data area
|
|
; This loop depends on all buffers being contiguous.
|
|
;
|
|
Move.l FreeXmtBuff(A2), A0 ; Get Xmit header pointer
|
|
Move.l D2,D1
|
|
SubQ #1,D1 ; adjust loop count
|
|
@x3
|
|
Lea Packet(A0), A1 ; Get Packet logical address
|
|
MoveM.l A0/D1/D2, -(SP) ; Save used C regs
|
|
Move.l #TxBuffSz, -(SP) ; logical size
|
|
Move.l A1, -(SP) ; logical address
|
|
Lea TranslateAddress, A0
|
|
Jsr (A0) ; get physical address in D0
|
|
MoveA.l (SP)+, A1 ; get back buffer addr
|
|
AddQ #4, SP ; trash length
|
|
MoveM.l (SP)+, A0/D1/D2 ; restore used C regs
|
|
Blt @InitError
|
|
Move.l A1, LogBufPtr(A0) ; save logical address
|
|
Move.l D0, PhyBufPtr(A0) ; save physical address
|
|
Lea TxBuffSz(A0), A0 ; A0-> next buffer address
|
|
DBra D1,@x3 ; do them all
|
|
ENDWITH
|
|
;
|
|
; MACE Chip initialization
|
|
;
|
|
MoveA.l MACEBase(A2), A0 ; A0-> base address of Mace regs
|
|
|
|
Bsr ResetMACE ; Reset MACE chip and PSC DMA chnls
|
|
|
|
Move.b #(1<<RTRD), MACE_USER_TEST_REG(A0) ; Disable access to Reserved Test Regs
|
|
Move.b #MaceIntMask, MACE_INT_MSK(A0) ; Disable all ints.
|
|
Move.b #XMTS64, MACE_BIU_CNFG(A0) ; Xmit start after 64 bytes, Intel Bus Mode
|
|
Move.b MACECfg.XmitFrmCtl(A4), MACE_TX_FRM_CNTRL(A0) ; Xmit Control -> Default:
|
|
; Enable Retry, FCS, Auto Padding
|
|
Move.b MACECfg.RecvFrmCtl(A4), MACE_RX_FRM_CNTRL(A0) ; Recv Control -> Default:
|
|
; Disable Auto Pad Stripping
|
|
; Set up FIFOs' configuration
|
|
Move.b MACECfg.FIFOCfgCtl(A4), MACE_FIFO_CNFG(A0)
|
|
Move.b #0, MACE_PLS_CNFG(A0) ; Set up for normal transmit
|
|
|
|
Move.b MACE_CHIP_ID_HIGH(A0), D0
|
|
Lsl #8, D0
|
|
Move.b MACE_CHIP_ID_LOW(A0), D0
|
|
Move D0, MACEChipID(A2)
|
|
|
|
Move.b #(1<<ADDRCHG), MACE_ADDR_CNFG(A0) ; Set address change bit
|
|
@wait1 Move.b MACE_ADDR_CNFG(A0), D0 ; wait for MACE to clear it
|
|
BTst #ADDRCHG, D0
|
|
Bne.s @wait1
|
|
|
|
Move.b #(1<<PHYADDR), MACE_ADDR_CNFG(A0) ; Select physical address
|
|
Lea MACE_PHY_ADDR(A0), A0 ; A0-> Mace Phy Address Reg
|
|
MoveA.l OurAddrPtr(A2), A1 ; A1-> Our node address
|
|
Move.b (A1)+, (A0) ; Move addr byte0 to Mace reg
|
|
Move.b (A1)+, (A0) ; Move addr byte1 to Mace reg
|
|
Move.b (A1)+, (A0) ; Move addr byte2 to Mace reg
|
|
Move.b (A1)+, (A0) ; Move addr byte3 to Mace reg
|
|
Move.b (A1)+, (A0) ; Move addr byte4 to Mace reg
|
|
Move.b (A1), (A0) ; Move addr byte5 to Mace reg
|
|
MoveA.l MACEBase(A2), A0 ; Get back base address of Mace regs
|
|
|
|
Move.b #(1<<ADDRCHG), MACE_ADDR_CNFG(A0) ; Set address change bit
|
|
@wait2 Move.b MACE_ADDR_CNFG(A0), D0 ; wait for MACE to clear it
|
|
BTst #ADDRCHG, D0
|
|
Bne.s @wait2
|
|
|
|
Move.b #(1<<LOGADDR), MACE_ADDR_CNFG(A0) ; Select logical address
|
|
Lea MACE_LOG_ADDR(A0), A1 ; A1-> Mace Phy Address Reg
|
|
MoveQ #7, D0
|
|
@laf Move.b #0, (A1) ; CLEAR all bits in Log Addr Filter
|
|
DBra D0, @laf
|
|
|
|
Move #0, NxtXmitSet(A2) ; make set0 next reg set to xmit on
|
|
Move #0, ActXmitSet(A2) ; make set0 active xmit reg set
|
|
Move #0, ActRecvSet(A2) ; make set0 active recv reg set
|
|
|
|
IF SETDEBUG THEN
|
|
;???? temp code to see if we have post evt5 PSC that has non-sticking register write fix
|
|
MoveA.l VIA, A1
|
|
BTst #vSCCWrReq, vDirA(A1) ; new psc: bit(vSCCWrReq) = 0
|
|
; old psc: bit(vSCCWrReq) = 1
|
|
Seq.b hasNewPSC(A2)
|
|
; end temp code
|
|
ENDIF
|
|
|
|
Bsr InitRecvChl ; Initialize DMA recv channel
|
|
|
|
; Install MACE Recv DMA channel Deferred Task, called by MACE_RECVhndlr
|
|
Move.w #dtQType, DTQE+qType(A2) ; Set Deferred Task queue type
|
|
Lea MaceRecv, A1
|
|
Move.l A1, DTQE+dtAddr(A2) ; Set address of DT, called by slot int. hndlr.
|
|
Move.l A2, DTQE+dtParm(A2) ; Set variable pointer to MACE vars
|
|
|
|
; Install PSC DMA handlers for Mace Recv & Xmit channels
|
|
MoveA.l PSCBase(A2), A3 ; Get the PSC base address
|
|
WITH ExpandMemRec
|
|
MoveA.l ([ExpandMem],emDMADispatchGlobals), A0; A0-> PSC Interrupt table ptr
|
|
ENDWITH
|
|
Lea PSCInterrupt, A1
|
|
Move.l A1, MACE_RECVhndlr(A0) ; Install DMA recv handler
|
|
Move.l A2, MACE_RECVparm(A0) ; MaceVarPtr passed back in A1
|
|
Move.l A1, MACE_XMIThndlr(A0) ; Install DMA xmit done handler
|
|
Move.l A2, MACE_XMITparm(A0) ; MaceVarPtr passed back in A1
|
|
Move.b #(1<<L4B7)+(1<<DMA), L4IER(A3) ; Enable DMA interrupts
|
|
|
|
; Initialize Recv & Xmit DMA Channel Control Registers
|
|
Move #(1<<SENSE)+(1<<CIE), PSC_MACE_XMIT_CNTL(A3)
|
|
Move #(1<<SENSE)+(1<<CIE), PSC_MACE_RECV_CNTL(A3)
|
|
|
|
Move #(1<<PAUSE), PSC_MACE_XMIT_CNTL(A3) ; UnPause the DMA xmit channel
|
|
Move #(1<<PAUSE), PSC_MACE_RECV_CNTL(A3) ; UnPause the DMA recv channel
|
|
|
|
; Install Mace Interrupt handler, called at Level 3
|
|
Lea MaceInterrupt, A1
|
|
Move.l A1, MACEhndlr(A0)
|
|
Move.l A2, MACEparm(A0) ; MaceVarPtr passed back in A1
|
|
Move.b #(1<<L3B7)+(1<<MACE), L3IER(A3) ; Enable MACE interrupts
|
|
|
|
Move.l MACEBase(A2), A0 ; Base address of Mace
|
|
Move.b MACECfg.MACCfgCtl(A4), MACE_MAC_CNFG(A0) ; Default: Enable xmit and recv
|
|
Move.b #OurIntsMask, MACE_INT_MSK(A0) ; Enable ints. we care about
|
|
|
|
MoveQ #0, D0
|
|
Bra.s @60
|
|
|
|
;
|
|
; Init error - clear out variable pointer for next try
|
|
;
|
|
@InitError
|
|
Move D0,D3 ; Save error code
|
|
|
|
Bsr FreeMACEMem ; Free, and unlock if needed, all mem blks
|
|
|
|
Move D3,D0
|
|
CmpI #-1,D0 ; Translate generic error
|
|
Bne.s @60
|
|
MoveQ #openErr,D0
|
|
@60
|
|
Tst D0
|
|
MoveM.l (SP)+, A2-A4/D3-D5 ; Restore regs
|
|
Unlk A6
|
|
Rts ; Return with error
|
|
|
|
ENDP
|
|
|
|
END
|
|
|
|
|
|
|