mirror of
https://github.com/elliotnunn/mac-rom.git
synced 2024-11-17 20:05:05 +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.
1378 lines
40 KiB
Plaintext
1378 lines
40 KiB
Plaintext
;
|
|
; File: Sonic.a
|
|
;
|
|
; Contains: Sonic-specific support routines
|
|
;
|
|
; Written by: Sean Findley
|
|
;
|
|
; Copyright: © 1990, 1992 by Apple Computer, Inc., all rights reserved.
|
|
;
|
|
; Change History (most recent first):
|
|
;
|
|
; <1> 10/6/92 GDW New location for ROMLink tool.
|
|
; <1> 6/12/92 RLM first checked in
|
|
; <P2> 02/07/92 jmp (jmp,H2/BG/SJF,Z3) Modifications for passing in SonicPtr instead
|
|
; of storing it.
|
|
; <1> 2/4/92 mal first checked in
|
|
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; Pre-Horror ROM comments begin here.
|
|
; ÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑÑ
|
|
; <2> 4/21/91 CCH Rolled in Sean Findley's changes.
|
|
; <1> 12/14/90 JK Added to builds
|
|
;
|
|
; To Do:
|
|
;
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ SONIC.a
|
|
; written by Sean J. Findley Jan. 1990
|
|
|
|
PRINT NOMDIR,NOMCALL
|
|
|
|
MACRO
|
|
Set10
|
|
SMOVE #(TalliesPerSec*10) MOD 65536,Timer0(A2)
|
|
; set lower 16 bits of counter
|
|
SMOVE #(TalliesPerSec*10) DIV 65536,Timer1(A2)
|
|
; set upper 16 bits of counter
|
|
MOVE.L #(1<<TimerElapsed),D0
|
|
SMOVE D0,Int_Status(A2) ; make sure no pending timer interrupt
|
|
ENDM
|
|
|
|
INCLUDE 'SonicEqu.a'
|
|
|
|
IF Txpkt.frag_esize = 6 THEN
|
|
MACRO
|
|
&L FragMul &DReg
|
|
&L ADD.W &DReg, &DReg
|
|
MOVE.W &DReg, -(A7)
|
|
ADD.W &DReg, &DReg
|
|
ADD.W (A7)+, &DReg
|
|
ENDM
|
|
ELSEIF Txpkt.frag_esize = 12 THEN
|
|
MACRO
|
|
&L FragMul &DReg
|
|
&L ADD.W &DReg, &DReg
|
|
MOVE.W &DReg, -(A7)
|
|
ADD.W &DReg, &DReg
|
|
ADD.W (A7)+, &DReg
|
|
ADD.W &DReg, &DReg
|
|
ENDM
|
|
ELSE
|
|
AError 'Unexpected value for Txpkt.frag_esize'
|
|
ENDIF
|
|
|
|
SONICdata PROC
|
|
; For machines with MMUs present, pointers may have additional values associated with them.
|
|
; One is the lowest possible logical address the pointer may have. This value is used to
|
|
; calculate an offset that can be added to the second value which is the lowest possible
|
|
; physical address to quickly translate logical to physical addresses, and vice-versa.
|
|
|
|
ENTRY TxTDAptr,NextTxTDA,FreeTxTDA,RRAptr,RBAptr,RDAptr
|
|
ENTRY RECVParms,RECVProc,TRANParms,TRANProc,TxRetries,RxDescs
|
|
ENTRY NextRxDesc,LastDesc,HoldDescHdr,IntDRtn,IntERtn,NetStatp,FreeQ
|
|
|
|
TxTDAptr DC.L 0,0,0 ; pointer to current Tx descriptor area
|
|
NextTxTDA DC.L 0 ; pointer to next TDA to transmit
|
|
FreeTxTDA DC.L 0 ; pointer to available TDA
|
|
|
|
RRAptr DC.L 0,0,0 ; pointer to read resource area
|
|
RBAptr DC.L 0,0,0 ; pointer to read buffer area
|
|
RDAptr DC.L 0,0,0 ; pointer to read descriptor area
|
|
|
|
RECVParms DC.L 0 ; parm ptr to pass to user receive routine
|
|
RECVProc DC.L 0 ; addr of user receive routine
|
|
TRANParms DC.L 0 ; parm ptr to pass to xmit complete routine
|
|
TRANProc DC.L 0 ; address of xmit complete routine
|
|
|
|
TxRetries DC.L 0 ; retry counter for failed xmits
|
|
RxDescs DC.L 0 ; number of recv descriptors allocated
|
|
|
|
NextRxDesc DC.L 0 ; ptr to next recv descriptor to poll
|
|
LastDesc DC.L 0 ; ptr to last descriptor
|
|
HoldDescHdr DC.L 0 ; hdr to held descriptor list
|
|
|
|
IntDRtn DC.L 0 ; ptr to proc to disable interrupts
|
|
IntERtn DC.L 0 ; ptr to proc to enable interrupts
|
|
|
|
NetStatp DC.L 0 ; ptr to network stats. array
|
|
|
|
; We keep a queue to manage the freeing of receive descriptors. Since descriptors may be
|
|
; freed out of the received sequence order, we cannot permit the SONIC to use a given descriptor
|
|
; unless it is being freed in the same sequence as it was received. Thus as packets are
|
|
; received, their descriptors are placed onto a queue (we have a head & tail for fast queue
|
|
; insertions/deletions), and a "freed" flag is set to false. When the descriptor is freed,
|
|
; the flag is set to true, and if the descriptor is at the front of the queue it, and any others
|
|
; directly behind it that have been freed are given back to the SONIC. This will prevent a
|
|
; "buffer wrap-around".
|
|
|
|
FreeQ DC.L 0,0 ; head/tail pointer for queuing
|
|
ENDPROC
|
|
|
|
llg EQU 4 ; offset to lowest logical addr
|
|
lph EQU 8 ; offset to lowest physical addr
|
|
|
|
; Routines for initializing SONIC chip and reading/writing packets on Ethernet.
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; Setup SONIC clock to go off in 10 seconds. Assumes A2-> SONIC registers.
|
|
Set10Seconds PROC ENTRY
|
|
WITH SONICRegs
|
|
Set10 ; set timer for 10 seconds
|
|
RTS
|
|
ENDPROC
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; Restart SONIC. Assumes A2-> SONIC registers.
|
|
RestartSONIC PROC EXPORT ; take SONIC out of reset <T2>
|
|
WITH SONICRegs
|
|
MOVEQ #0,D0
|
|
SMOVE D0,Command(A2) ; take out of reset
|
|
@wait
|
|
SMOVE Command(A2),D0
|
|
BTST #SoftReset,D0
|
|
BNE.S @wait ; wait for it
|
|
|
|
Set10 ; set timer for 10 seconds
|
|
|
|
MOVEQ #(1<<RxEnable)+(1<<StartTimer),D0
|
|
SMOVE D0,Command(A2) ; start receiving packets again
|
|
@waitmore
|
|
SMOVE Command(A2),D0
|
|
BTST #RxDisable,D0
|
|
BNE.S @waitmore ; wait for receiver to enable
|
|
RTS
|
|
ENDPROC
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; Reset SONIC. Assumes A2-> SONIC registers
|
|
|
|
ResetSONIC PROC EXPORT ; <T2>
|
|
WITH SONICRegs
|
|
MOVEQ #(1<<RxDisable),D0
|
|
SMOVE D0,Command(A2) ; disable packet reception
|
|
@wait
|
|
SMOVE Command(A2),D0
|
|
BTST #RxEnable,D0
|
|
BNE.S @wait ; wait until it disables
|
|
@wait1
|
|
SMOVE Command(A2),D0
|
|
EORI.W #(1<<StartTimer)+(1<<RxDisable),D0
|
|
BNE.S @wait1 ; make sure no other commands active
|
|
|
|
BSET #SoftReset,D0
|
|
SMOVE D0,Command(A2) ; so we can look at CAM cells
|
|
|
|
RTS
|
|
ENDPROC
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; Set a bit in command register and wait for it to clear.
|
|
; D0=bit # to set/poll.
|
|
; A2->SONIC chip
|
|
; Uses D1
|
|
|
|
SONICSync PROC ENTRY
|
|
WITH SONICRegs
|
|
SUB.L D1,D1 ; clear 32 bits
|
|
BSET D0,D1
|
|
SMOVE D1,Command(A2)
|
|
@waitloop
|
|
SMOVE Command(A2),D1
|
|
BTST D0,D1
|
|
BNE.S @waitloop ; wait for command to complete
|
|
RTS
|
|
ENDWITH
|
|
ENDPROC
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥
|
|
; Link to the end of recv descriptor list.
|
|
; A1->new entry, uses A0
|
|
LinkToRxList PROC ENTRY
|
|
|
|
MOVE.L A2,-(SP)
|
|
|
|
SUB.L D0,D0
|
|
SMOVE D0,Rxpkt.status(A1) ; setup to receive
|
|
MOVEQ #(1<<EOL_Bit), D0 ; mark us at the end
|
|
SMOVE D0,Rxpkt.link(A1) ; new last one
|
|
|
|
MOVEQ #-1,D0
|
|
SMOVE D0,Rxpkt.in_use(A1) ; mark entry as in use by SONIC
|
|
|
|
LEA LastDesc,A0 ; A0->last descriptor ptr
|
|
MOVEA.L (A0),A2 ; A2->last descriptor
|
|
|
|
MOVE.L A1,(A0) ; update last pointer
|
|
MOVE.L A1,D0
|
|
|
|
IF MMU THEN
|
|
SUB.L RDAptr+llg,D0
|
|
ADD.L RDAptr+lph,D0 ; D0=physical address
|
|
ENDIF
|
|
|
|
SMOVE D0,Rxpkt.link(A2) ; link us to the end of the list
|
|
|
|
LEA NextRxDesc,A0
|
|
TST.L (A0) ; were we out of buffers?
|
|
BNE.S @done ; no
|
|
|
|
MOVE.L A1,(A0) ; set next recv desc to poll
|
|
@done
|
|
MOVEA.L (SP)+,A2
|
|
RTS
|
|
ENDPROC
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ SONIC Free Buffer
|
|
; void SONICFREEBUFF(desc)
|
|
SONICFREEBUFF PROC EXPORT
|
|
|
|
parms RECORD 4
|
|
RxDescriptor DS.L 1 ; ->to RDA descriptor to free
|
|
ENDR
|
|
|
|
WITH parms
|
|
|
|
MOVEA.L IntDRtn,A0 ; A0->proc to disable interrupts
|
|
JSR (A0) ; call it
|
|
|
|
MOVEA.L RxDescriptor(SP),A1 ; A1->descriptor to be freed
|
|
|
|
MOVE.L A2,-(SP) ; save reg
|
|
MOVE.L D0,-(SP) ; save SR returned by proc
|
|
|
|
ST Rxpkt.isFree(A1) ; mark this desc to be freed
|
|
|
|
LEA FreeQ,A2 ; A2->to be freed queue
|
|
CMPA.L (A2),A1 ; is this entry at the front?
|
|
BNE.S @xit ; that's all we can do now
|
|
; free as many descriptors as possible starting at the front of the queue
|
|
@FreeDesc
|
|
TST.B Rxpkt.isFree(A1) ; can we free this desc?
|
|
BEQ.S @done ; no, all done
|
|
|
|
MOVE.L Rxpkt.nextRD(A1),(A2) ; set queue head to next desc if any
|
|
|
|
BSR.S doFreeDesc ; give descriptor back to SONIC
|
|
|
|
MOVE.L (A2),D0 ; any more to free?
|
|
BEQ.S @done ; all done
|
|
|
|
MOVEA.L D0,A1 ; A1->next descriptor to free
|
|
BRA.S @FreeDesc ; try the next one
|
|
@done
|
|
TST.L (A2)+ ; see if queue has been emptied
|
|
BNE.S @xit ; is not
|
|
CLR.L (A2) ; clear tail pointer too
|
|
@xit
|
|
MOVEA.L IntERtn,A0 ; A0->proc to enable interrupts
|
|
JSR (A0) ; do it
|
|
ADDQ.W #4,SP ; strip SR parm
|
|
|
|
MOVEA.L (SP)+,A2 ; get back reg
|
|
RTS
|
|
doFreeDesc
|
|
SMOVE Rxpkt.in_use(A1),D0 ; see if SONIC still using desc
|
|
TST.W D0
|
|
BEQ LinkToRxList ; put desc on receive list
|
|
; put desc on hold list
|
|
; If the descriptor might still be in use by the SONIC. This can happen if no other descriptors
|
|
; have been freed prior to this one OR we have not received any packets since freeing other
|
|
; descriptors prior to this one.
|
|
LEA HoldDescHdr,A0 ; A0->hold list header
|
|
MOVE.L (A0),Rxpkt.nextRD(A1) ; link prev to our next
|
|
MOVE.L A1,(A0) ; put desc on head of list
|
|
RTS
|
|
|
|
ENDWITH
|
|
ENDPROC
|
|
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ SONIC Interrupt Handler
|
|
SONICInterrupt PROC ENTRY
|
|
|
|
OurStack RECORD {A6Link} ; <Z3>
|
|
Sz EQU * ; <Z3>
|
|
A6Link DS.L 2 ; <Z3>
|
|
SONICPtr DS.L 1 ; <Z3>
|
|
ENDR ; <Z3>
|
|
|
|
; void SONICInterrupt()
|
|
|
|
WITH SONICRegs
|
|
LINK A6,#OurStack.Sz ; <Z3>
|
|
MOVEM.L A2-A3, -(SP) ; save those we use
|
|
@more
|
|
MOVEA.L OurStack.SONICptr(A6),A2 ; A2->SONIC regs <Z3>
|
|
|
|
SMOVE Int_Status(A2),D0 ; get ISR from SONIC
|
|
MOVE.W D0,D1 ; save it
|
|
MOVE.W #(1<<RecdPkt),D2
|
|
AND.W D2,D0 ; a receive?
|
|
BEQ.S @chkXmit
|
|
SMOVE D2,Int_Status(A2) ; clear interrupt status
|
|
BSR PKTRX ; yes, process it right away
|
|
BRA.S @more
|
|
@chkXmit
|
|
MOVE.W #(1<<TransDone),D2
|
|
AND.W D2,D1 ; a xmit complete?
|
|
BEQ.S @chkOther
|
|
SMOVE D2,Int_Status(A2) ; clear interrupt status
|
|
BSR TXDN ; yes, do it right now
|
|
BRA.S @more
|
|
@chkOther
|
|
SMOVE Int_Status(A2),D0 ; get ISR from SONIC again
|
|
ANDI.W #OurIntsMask,D0 ; only the ones we want
|
|
BEQ.S @done ; finished
|
|
|
|
MOVEQ #15, D1 ; loop count
|
|
@chkBit
|
|
BTST.L D1, D0 ; check a bit
|
|
DBNE D1, @chkBit ; loop until a bit is on
|
|
|
|
SUB.L D2, D2 ; clear 32 bits
|
|
BSET D1, D2 ; set the bit that is on
|
|
ADD.W D1, D1 ; get table offset
|
|
|
|
LEA IntTable, A0
|
|
ADDA.W (A0, D1.W), A0 ; Get address of routine
|
|
|
|
SMOVE D2,Int_Status(A2) ; clear interrupt status
|
|
JSR (A0) ; and execute it
|
|
BRA.S @more ; look for more work to do
|
|
|
|
@done
|
|
MOVEM.L (SP)+, A2-A3
|
|
UNLK A6 ; <Z3>
|
|
RTS
|
|
|
|
IntTable
|
|
; Each interrupt is called with its respective status bit set in D2. It has the option of
|
|
; when to clear it in the ISR.
|
|
|
|
DC.W RFO-IntTable ; receive FIFO overrun
|
|
DC.W MP-IntTable ; MP tally counter rollover
|
|
DC.W FAE-IntTable ; FAE tally counter rollover
|
|
DC.W CRC-IntTable ; CRC tally counter rollover
|
|
DC.W RBAE-IntTable ; receive buffer overflow
|
|
DC.W RBE-IntTable ; receive buffers exhausted
|
|
DC.W RDE-IntTable ; receive descriptors exhausted
|
|
DC.W TC-IntTable ; timer complete
|
|
DC.W TXER-IntTable ; transmit error
|
|
DC.W TXDN-IntTable ; transmit complete
|
|
DC.W PKTRX-IntTable ; packet received
|
|
DC.W PINT-IntTable ; programmable interrupt
|
|
DC.W LCD-IntTable ; load CAM done
|
|
DC.W HBL-IntTable ; heartbeat lost
|
|
DC.W Reserved-IntTable ; reserved
|
|
DC.W Reserved-IntTable ; reserved
|
|
;________________
|
|
RFO ; receive FIFO overrun
|
|
MACRxError
|
|
MOVEA.L NetStatp, A0 ; Get pointer to array
|
|
ADDQ.L #1, NetStats.MPerr(A0) ; Increment statistic
|
|
RTS
|
|
;________________
|
|
MP ; MP tally counter rollover
|
|
RTS
|
|
;________________
|
|
FAE ; FAE tally counter rollover
|
|
RTS
|
|
;________________
|
|
CRC ; CRC tally counter rollover
|
|
RTS
|
|
;________________
|
|
RBAE ; receive buffer overflow
|
|
BRA.S MACRxError ; report receive error
|
|
;________________
|
|
RBE ; receive buffers exhausted
|
|
BRA.S MACRxError ; report receive error
|
|
;________________
|
|
RDE ; receive descriptors exhausted
|
|
RTS
|
|
;________________
|
|
TC ; timer complete
|
|
; This interrupt is used to fix a bug in the SONIC. If a packet has not been received in
|
|
; the last 10 seconds and there ARE receive descriptors available, AND the current RDA
|
|
; pointer is at the End Of List, reset the SONIC.
|
|
|
|
|
|
SMOVE Silicon_Rev(A2),D0 ; check SONIC version
|
|
CMPI.W #3,D0
|
|
BHI.S @done ; do nothing if rev 4 or later
|
|
|
|
MOVE.L NextRxDesc,D0 ; see if descriptors available
|
|
BEQ Set10Seconds ; none available, user is very slow to free buffers
|
|
SMOVE Current_RDA(A2),D0
|
|
BTST #EOL_Bit,D0
|
|
BEQ Set10Seconds ; SONIC is not stuck
|
|
SMOVE Int_Status(A2),D0
|
|
BTST #RecdPkt,D0 ; make sure a packet did'nt arrive
|
|
BNE Set10Seconds ; process it if so
|
|
; SONIC is in a loop, reset it and get going again
|
|
SMOVE Command(A2),-(SP) ; save current command status
|
|
|
|
MOVE.L #1<<SoftReset,D0
|
|
SMOVE D0,Command(A2)
|
|
|
|
BSR RestartSONIC ; and get it going again
|
|
SMOVE (SP)+,Command(A2) ; continue with whatever we were doing
|
|
@done
|
|
RTS
|
|
;________________
|
|
TXER ; transmit error
|
|
RTS
|
|
;________________
|
|
TXDN ; transmit complete
|
|
|
|
LEA TxRetries,A0 ; A0->retry count
|
|
|
|
SMOVE Int_Status(A2),D0 ; check for errors
|
|
ANDI.W #(1<<TransError),D0 ; any abort errors?
|
|
BEQ.S @nextXmit ; no, see if more to xmit
|
|
|
|
SMOVE D0,Int_Status(A2) ; clear error status
|
|
|
|
ADDQ.L #1,(A0) ; inc retry count
|
|
CMPI.L #TxMaxRetries,(A0) ; past the treshhold?
|
|
BLO.S @nextXmit ; give up if so
|
|
|
|
SMOVE Current_TDA(A2),D0
|
|
BTST #EOL_Bit,D0 ; make sure we have a Tx descriptor
|
|
BNE.S @nextXmit ; give up if not
|
|
|
|
MOVEQ #(1<<TxEnable), D0
|
|
SMOVE D0,Command(A2) ; try retransmitting
|
|
RTS ; get out
|
|
@nextXmit
|
|
CLR.L (A0) ; reset retry count
|
|
|
|
MOVEA.L IntDRtn,A1
|
|
JSR (A1)
|
|
MOVE.L D0,-(SP) ; disable interrupts and save old SR
|
|
|
|
LEA TxTDAptr,A0
|
|
MOVE.L (A0),A3 ; save ptr to transmitted chain
|
|
|
|
LEA NextTxTDA,A1
|
|
MOVE.L (A1),(A0) ; set any pending chain to current
|
|
BEQ.S @callTxComp ; were'nt any pending
|
|
|
|
CLR.L (A1) ; pending chain now being xmitted
|
|
MOVE.L (A0),D0
|
|
|
|
IF MMU THEN
|
|
SUB.L TxTDAptr+llg,D0
|
|
ADD.L TxTDAptr+lph,D0 ; D0=physical address of curr TDA
|
|
ENDIF
|
|
|
|
SMOVE D0,Current_TDA(A2) ; set SONIC TDA ptr
|
|
|
|
MOVEQ #(1<<TxEnable), D0
|
|
SMOVE D0,Command(A2) ; start transmitting pending chain
|
|
@callTxComp
|
|
MOVEA.L IntERtn,A0
|
|
JSR (A0) ; reenable interrupts
|
|
@doTxComp ; A3->xmitted TDA
|
|
MOVE.L TRANParms,-(SP) ; pointer to xmit complete parms
|
|
MOVEM.L A3,-(SP) ; pass ptr to xmit buffer descriptor
|
|
MOVE.L TRANProc,A0 ; xmit completion routine address
|
|
JSR (A0) ; call it
|
|
ADDQ.W #8,SP ; strip trans parms
|
|
|
|
SMOVE TxPkt.status(A3),D0 ; get back status
|
|
ANDI.W #$F800, D0
|
|
MOVEA.L NetStatp, A0 ; Get pointer to array
|
|
CMPI.W #$0800, D0 ; were there any?
|
|
BLO.S @ok ; none
|
|
BHI.S @many ; more than one
|
|
ADDQ.L #1, NetStats.sCollFrame(A0) ; Increment statistic
|
|
BRA.S @coll
|
|
|
|
@many
|
|
ADDQ.L #1, NetStats.mCollFrame(A0) ; inc multiple collision frame
|
|
|
|
@coll
|
|
ADDQ.L #1, NetStats.CollFrame(A0) ; inc collision count
|
|
@ok
|
|
SMOVE TxPkt.status(A3),D1 ; get back status
|
|
CMPI.W #(1<<TransmitOK),D1 ; fast check
|
|
BNE.S @chkErrs ; not a normal result
|
|
ADDQ.L #1, NetStats.TxOK(A0) ; pkt transmitted OK
|
|
BRA.S @nxtTDA
|
|
@chkErrs
|
|
BTST #TransmitOK,D1
|
|
BEQ.S @latechk ; not transmitted
|
|
ADDQ.L #1, NetStats.TxOK(A0) ; pkt transmitted OK
|
|
|
|
BTST #DeferredTx,D1
|
|
BEQ.S @latechk
|
|
ADDQ.L #1, NetStats.DefTx(A0) ; had a deferred transmission
|
|
@latechk
|
|
BTST #OutWindow,D1
|
|
BEQ.S @aborts
|
|
ADDQ.L #1, NetStats.LateColl(A0) ; out of window
|
|
@aborts
|
|
BTST #ExcessColl,D1
|
|
BEQ.S @aborts1
|
|
ADDQ.L #1, NetStats.ExcessColl(A0) ; excess collisions
|
|
@aborts1
|
|
BTST #ExcessDefer,D1
|
|
BEQ.S @aborts2
|
|
ADDQ.L #1, NetStats.ExcessDef(A0) ; excess deferrals
|
|
@aborts2
|
|
BTST #FIFOUnderRun,D1
|
|
BNE.S @aborts3 ; internal error
|
|
BTST #BCMismatch,D1
|
|
BEQ.S @nxtTDA
|
|
@aborts3
|
|
ADDQ.L #1, NetStats.InMACTxErr(A0) ; internal MAC xmit error
|
|
@nxtTDA
|
|
MOVEA.L IntDRtn,A1
|
|
JSR (A1) ; disable interrupts
|
|
|
|
SMOVE Txpkt.frag_count(A3),D0 ; get count of fragments in this TDA
|
|
FragMul D0 ; calc offset to link field
|
|
|
|
LEA FreeTxTDA,A0
|
|
|
|
MOVE.L (A0),TxPkt.nextTD(A3) ; put this TDA on the free list
|
|
MOVE.L A3,(A0)
|
|
|
|
LEA Txpkt.frag_start(A3),A3
|
|
LEA (A3,D0.W),A3 ; A3->this TDA link field
|
|
|
|
SMOVE (A3),D0 ; fetch link field
|
|
BTST #EOL_Bit,D0
|
|
BNE.S @done ; this is the end..my friend
|
|
|
|
SMOVE Upper_TDA(A2),D1
|
|
SWAP D1
|
|
MOVE.W D0,D1
|
|
|
|
IF MMU THEN
|
|
SUB.L TxTDAptr+lph,D1
|
|
ADD.L TxTDAptr+llg,D1 ; D1=logical address
|
|
ENDIF
|
|
|
|
MOVEA.L D1,A3 ; A3->next TDA in xmitted chain
|
|
|
|
MOVEA.L IntERtn,A1
|
|
JSR (A1) ; reenable interrupts
|
|
|
|
BRA @doTxComp
|
|
@done
|
|
MOVEA.L IntERtn,A1
|
|
JSR (A1) ; reenable interrupts
|
|
ADDQ.W #4,SP ; strip old SR
|
|
|
|
RTS
|
|
;________________
|
|
PKTRX ; packet received
|
|
MOVE.L HoldDescHdr,D0 ; any descriptors held?
|
|
BEQ.S checkDesc ; none to process
|
|
|
|
; Free available receive descriptors from the hold list.
|
|
|
|
LEA HoldDescHdr,A3 ; A3->prev link
|
|
MOVEA.L D0,A1 ; A1->held descriptor
|
|
@chk
|
|
MOVE.L Rxpkt.nextRD(A1),D1 ; save forward link
|
|
|
|
SMOVE RxPkt.in_use(A1),D0
|
|
TST.W D0 ; desc still in use by the SONIC?
|
|
BMI.S @nxt ; yes
|
|
|
|
BSR LinkToRxList ; put on receive list
|
|
|
|
MOVE.L D1,(A3) ; delete from hold list
|
|
MOVEA.L A3,A1 ; keep prev link
|
|
@nxt
|
|
MOVEA.L A1,A3 ; A3->prev link
|
|
MOVEA.L D1,A1 ; A1->next held desc maybe
|
|
TST.L D1
|
|
BNE.S @chk ; more to do
|
|
checkDesc
|
|
MOVE.L NextRxDesc,D0
|
|
BEQ @done
|
|
|
|
MOVEA.L D0,A3 ; A3->next active descriptor
|
|
|
|
SMOVE RxPkt.status(A3),D0
|
|
TST.W D0 ; at logical end of list?
|
|
BEQ @done
|
|
|
|
MOVE.L A3,-(SP) ; pass buffer descriptor
|
|
MOVE.L RECVparms,-(SP) ; parms ptr for user
|
|
SMOVE RxPkt.pkt_ptr1(A3),D0
|
|
SWAP D0
|
|
SMOVE RxPkt.pkt_ptr0(A3),D1
|
|
MOVE.W D1,D0
|
|
|
|
IF MMU THEN
|
|
SUB.L RBAptr+lph,D0
|
|
ADD.L RBAptr+llg,D0 ; D0=logical address
|
|
ENDIF
|
|
|
|
MOVE.L D0,-(SP) ; pointer to packet data
|
|
SUB.L D0,D0
|
|
SMOVE RxPkt.byte_count(A3),D0
|
|
MOVE.L D0,-(SP) ; length of packet received
|
|
SUB.L D0,D0
|
|
SMOVE RxPkt.status(A3),D0
|
|
MOVE.L D0,-(SP) ; receive status
|
|
|
|
; setup pointer to next descriptor
|
|
SUB.L D1,D1
|
|
SMOVE Rxpkt.link(A3),D2 ; get lower part of link
|
|
BTST #EOL_Bit,D2 ; end of list?
|
|
BNE.S @FreeQueue ; yes
|
|
SMOVE Upper_RDA(A2),D1
|
|
SWAP D1 ; setup upper part of address
|
|
MOVE.W D2,D1 ; setup lower part of address
|
|
|
|
IF MMU THEN
|
|
SUB.L RDAptr+lph,D1
|
|
ADD.L RDAptr+llg,D1 ; D1=logical address
|
|
ENDIF
|
|
@FreeQueue
|
|
; place descriptor on to-be-freed queue
|
|
LEA FreeQ,A1 ; A1->to be freed queue
|
|
CLR.L Rxpkt.nextRD(A3) ; clear this desc link field
|
|
CLR.B Rxpkt.isFree(A3) ; mark as not freed yet
|
|
TST.L (A1)+ ; check queue head
|
|
BNE.S @notEmpty ; has entries on it
|
|
MOVE.L A3,(A1) ; put this desc on the end of queue
|
|
MOVE.L A3,-(A1) ; and on the front as well
|
|
BRA.S @doneQueueing ; that's it
|
|
@notEmpty
|
|
MOVEA.L (A1),A0 ; A0->tail
|
|
MOVE.L A3,Rxpkt.nextRD(A0) ; link tail to this desc
|
|
MOVE.L A3,(A1) ; put this desc on the end of queue
|
|
@doneQueueing
|
|
MOVEA.L D1,A3 ; A3->next descriptor maybe
|
|
|
|
LEA NextRxDesc,A0
|
|
MOVE.L A3,(A0) ; update for next receive
|
|
@doRxCall
|
|
MOVEA.L RECVProc,A0 ; addr of receive routine
|
|
JSR (A0) ; call it
|
|
|
|
MOVE.L (SP)+,D1 ; get back status
|
|
LEA 16(SP),SP ; strip other parms
|
|
|
|
MOVEA.L NetStatp, A0 ; Get pointer to array
|
|
MOVE.W #(1<<ReceivedOK),D0
|
|
AND.W D1,D0 ; see if errors occured
|
|
BEQ.S @Checkerrs
|
|
ADDQ.L #1, NetStats.RxOK(A0) ; pkt received OK
|
|
|
|
MOVE.W #(1<<MultiRecd),D0
|
|
AND.W D1,D0
|
|
BEQ.S @chkB
|
|
ADDQ.L #1, NetStats.MultiRxOK(A0) ; multicast received OK
|
|
@chkB
|
|
ANDI.W #(1<<BroadRecd),D1
|
|
BEQ checkDesc
|
|
ADDQ.L #1, NetStats.BroadRxOK(A0) ; broadcast received OK
|
|
BRA checkDesc
|
|
@Checkerrs
|
|
BTST #CRCErr,D1
|
|
BEQ.S @chkFAE
|
|
ADDQ.L #1, NetStats.FCSerr(A0) ; CRC error
|
|
@chkFAE
|
|
BTST #FramAlignErr,D1
|
|
BEQ checkDesc
|
|
ADDQ.L #1, NetStats.FAerr(A0) ; frame alignment error
|
|
BRA checkDesc
|
|
@done
|
|
Set10 ; set timer for 10 seconds
|
|
RTS
|
|
;________________
|
|
PINT ; programmable interrupt
|
|
RTS
|
|
;________________
|
|
LCD ; load CAM done
|
|
RTS
|
|
;________________
|
|
HBL ; heartbeat lost
|
|
RTS
|
|
;________________
|
|
Reserved ; reserved
|
|
RTS
|
|
|
|
ENDWITH
|
|
ENDPROC
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ SONIC Initializaiton
|
|
|
|
; int SONICINIT( SONICbase,IntInstall,RECVRtn,RECVPrms,
|
|
; TRANRtn,TRANPrms,MemStart,MemSize,IntDisable,IntEnable,NetStatArray)
|
|
|
|
SONICINIT PROC EXPORT
|
|
|
|
parms RECORD {A6Link}
|
|
LocalSize EQU * ; no local vars
|
|
A6Link DS.L 2 ; link and return address
|
|
initp DS SONICinitParms ; parameters passed to us
|
|
ENDR
|
|
|
|
WITH parms,initp,SONICRegs,TxPkt,RRArec,Rxpkt,CAMDesc
|
|
|
|
LINK A6,#LocalSize ; save A6
|
|
MOVE.L A2,-(SP) ; save this reg
|
|
|
|
MOVEQ #-1,D0 ; possible error
|
|
CMPI.L #Min_Mem_Size,MemSize(A6) ; enough memory?
|
|
BLO @Ierror ; no
|
|
|
|
MOVEA.L SONICbase(A6),A2 ; A2->SONIC registers <Z3>
|
|
|
|
LEA RECVProc,A0
|
|
MOVE.L RECVRtn(A6),(A0)
|
|
|
|
LEA RECVParms,A0
|
|
MOVE.L RECVPrms(A6),(A0)
|
|
|
|
LEA TRANProc,A0
|
|
MOVE.L TRANRtn(A6),(A0)
|
|
|
|
LEA TRANParms,A0
|
|
MOVE.L TRANPrms(A6),(A0)
|
|
|
|
LEA IntDRtn,A0
|
|
MOVE.L IntDisable(A6),(A0)
|
|
|
|
LEA IntERtn,A0
|
|
MOVE.L IntEnable(A6),(A0)
|
|
|
|
LEA NetStatp,A0
|
|
MOVE.L NetStatArray(A6),(A0)
|
|
|
|
SUB.L D0,D0 ; clear 32 bits
|
|
SMOVE D0,Int_Mask(A2) ; disable SONIC interrupts
|
|
|
|
BSET #SoftReset,D0 ; do a software reset on SONIC
|
|
SMOVE D0,Command(A2)
|
|
|
|
PEA SONICInterrupt ; addr of our interrupt handler
|
|
MOVEA.L IntInstall(A6),A0 ; addr of installation proc
|
|
JSR (A0) ; install interrupt handler
|
|
ADDQ.W #4,SP
|
|
|
|
; setup SONIC chip configuration
|
|
MOVE.L DataConfig(A6),D0
|
|
SMOVE D0,Data_Config(A2) ; setup data configuration
|
|
; setup reception control
|
|
SUB.L D0,D0 ; clear 32 bits
|
|
BSET #RecvErrors,D0 ; receive CRC errors
|
|
|
|
SMOVE Silicon_Rev(A2),D1
|
|
CMPI.W #3,D1
|
|
BLS.S @setBrd ; no runts for rev 3 or earlier
|
|
BSET #RecvRunts,D0 ; receive runt packets
|
|
@setBrd
|
|
BSET #RecvBroadCast,D0 ; receive broadcasts
|
|
SMOVE D0,Recv_Control(A2)
|
|
; Ensure that descriptors are in the same 64k page
|
|
MOVE.L NumRxBuffs(A6),D0 ; calculate control memory size
|
|
MULU #Rxpkt.RxRDAsize,D0 ; memory for recv descriptors
|
|
|
|
ADDI.L #TxTDAsize * Max_Tx_Packets + RRArecSz + CAMDescSz,D0
|
|
; xmit descriptors, RRA and CAM
|
|
ADD.L MemStart(A6),D0 ; calc ending address
|
|
SUBQ.L #1,D0 ; make it inclusive
|
|
CLR.W D0 ; trash lower 16 bits
|
|
|
|
MOVE.L MemStart(A6),D1
|
|
CLR.W D1 ; get start address page
|
|
CMP.L D1,D0 ; see if boundry crossed
|
|
BEQ.S @AllocateMem ; proceed if not
|
|
|
|
ADDI.L #$10000,D1 ; adjust to 64k boundry
|
|
SUB.L MemStart(A6),D1 ; calc adjustment amount
|
|
|
|
ADD.L D1,MemStart(A6) ; update pointer
|
|
SUB.L D1,MemSize(A6) ; update size
|
|
@AllocateMem
|
|
|
|
; get memory for TDA
|
|
MOVE.L #TxTDAsize * Max_Tx_Packets,D0
|
|
; mem for TDA (up to 16 packets)
|
|
LEA FreeTxTDA,A1
|
|
MOVE.L MemStart(A6),(A1) ; save free txtda ptr
|
|
|
|
IF MMU THEN
|
|
LEA TxTDAPtr,A1
|
|
BSR @SetAddresses ; set current phys/log addrs
|
|
ENDIF
|
|
|
|
MOVEA.L MemStart(A6),A1 ; A1->1st TDA
|
|
MOVE.L A1,D1
|
|
|
|
IF MMU THEN
|
|
SUB.L TxTDAPtr+llg,D1
|
|
ADD.L TxTDAPtr+lph,D1 ; D1=physical address of TDA
|
|
ENDIF
|
|
|
|
SWAP D1
|
|
SMOVE D1,Upper_TDA(A2) ; set upper TDA
|
|
|
|
ADD.L D0,MemStart(A6) ; update pointer
|
|
SUB.L D0,MemSize(A6) ; update size
|
|
MOVEQ #Max_Tx_Packets-2,D1 ; link together all free TDAs
|
|
@linkTDA
|
|
PEA TxTDAsize(A1) ; get link to next TDA
|
|
MOVE.L (SP),nextTD(A1) ; put in link field of TDA
|
|
MOVEA.L (SP)+,A1 ; point at next one
|
|
DBRA D1,@linkTDA ; do them all (last link = nil)
|
|
|
|
; get memory for RRA
|
|
MOVEQ #RRArecSz+CAMDescSz,D0 ; mem for 1 RRA and 1 CAM descriptor
|
|
LEA RRAptr,A1
|
|
MOVE.L MemStart(A6),(A1) ; save RRA ptr
|
|
|
|
IF MMU THEN
|
|
BSR @SetAddresses ; set log/phys addresses
|
|
ENDIF
|
|
|
|
MOVE.L MemStart(A6),D1
|
|
|
|
IF MMU THEN
|
|
SUB.L RRAptr+llg,D1
|
|
ADD.L RRAptr+lph,D1 ; D1=physical address of RRA
|
|
ENDIF
|
|
|
|
SWAP D1
|
|
SMOVE D1,Upper_RRA(A2) ; set upper 16 bits of RRA addr
|
|
|
|
ADD.L D0,MemStart(A6) ; update pointer
|
|
SUB.L D0,MemSize(A6) ; update size
|
|
; get memory for RBA
|
|
MOVE.L MemSize(A6),D0
|
|
|
|
DIVU #Max_Pkt_Size+RxRDAsize,D0
|
|
EXT.L D0
|
|
|
|
CMP.L NumRxBuffs(A6),D0 ; more than requested?
|
|
BLS.S @usebuffs ; use number if less
|
|
|
|
MOVE.L NumRxBuffs(A6),D0
|
|
@usebuffs
|
|
LEA RxDescs,A1
|
|
MOVE.L D0,(A1) ; save buffer/descriptor count
|
|
; get memory for RDA
|
|
LEA RDAptr,A1
|
|
MOVE.L MemStart(A6),(A1) ; set RD list pointer
|
|
|
|
IF MMU THEN
|
|
BSR @SetAddresses ; set log/phys addresses
|
|
ENDIF
|
|
|
|
LEA NextRxDesc,A1
|
|
MOVE.L MemStart(A6),(A1) ; set next poll address too
|
|
|
|
MOVE.L RxDescs,D0 ; D0=# descriptors
|
|
MOVE.L D0,D1
|
|
MULU #Rxpkt.RxRDAsize,D1 ; get actual allocated descriptor size
|
|
ADD.L D1,MemStart(A6)
|
|
SUB.L D1,MemSize(A6)
|
|
SUBQ.L #1,D0 ; convert desc count to base zero
|
|
MOVEA.L RDAptr,A0 ; A0->start of RDA
|
|
@setRD
|
|
TST.L D0 ; on last one?
|
|
BNE.S @notLast
|
|
|
|
SUB.L D1,D1 ; nil pointer
|
|
BSET #EOL_Bit,D1
|
|
BRA.S @setLink ; link last to first
|
|
@notLast
|
|
PEA RxRDAsize(A0)
|
|
MOVE.L (SP)+,D1 ; link to next
|
|
|
|
IF MMU THEN
|
|
SUB.L RDAptr+llg,D1
|
|
ADD.L RDAptr+lph,D1 ; D1=physical address
|
|
ENDIF
|
|
@setLink
|
|
SMOVE D1,RxPkt.link(A0) ; set link
|
|
MOVEQ #-1,D1
|
|
SMOVE D1,RxPkt.in_use(A0) ; mark descriptor as in use by SONIC
|
|
LEA RxRDASize(A0),A0
|
|
DBRA D0,@setRD
|
|
|
|
PEA -RxRDASize(A0)
|
|
LEA LastDesc,A1
|
|
MOVE.L (SP)+,(A1) ; save ptr to last one in list
|
|
; set pointer to buffer area
|
|
MOVE.L RxDescs,D0
|
|
MULU #Max_Pkt_Size,D0 ; get actual memory used for buffers
|
|
|
|
LEA RBAptr,A1
|
|
MOVE.L MemStart(A6),(A1) ; save ptr to buffer area
|
|
|
|
IF MMU THEN
|
|
BSR @SetAddresses ; set log/phys addresses
|
|
ENDIF
|
|
|
|
ADD.L D0,MemStart(A6) ; update pointer
|
|
SUB.L D0,MemSize(A6) ; update size
|
|
; init RRA descriptors
|
|
MOVEA.L RRAPtr,A0 ; get pointer to RRA
|
|
LEA CAMDescSz(A0),A1 ; add in enough for CAM operations
|
|
|
|
PEA (A1) ; save for later
|
|
MOVE.L A1,D0
|
|
|
|
IF MMU THEN
|
|
SUB.L RRAptr+llg,D0
|
|
ADD.L RRAptr+lph,D0 ; A1=physical address
|
|
ENDIF
|
|
|
|
SMOVE D0,RRA_Read(A2) ; set up RRP
|
|
SMOVE D0,RRA_Start(A2) ; save lower 16 bit of RRA addr
|
|
|
|
ADDI.W #RRArecSz,D0 ; ONE descriptor
|
|
|
|
SMOVE D0,RRA_End(A2) ; and set the end of RRA too
|
|
SUB.L D0,D0 ; clear 32 bits
|
|
SMOVE D0,RRA_Write(A2) ; force wrap-around RRA
|
|
|
|
MOVE.L RBAptr,D0
|
|
|
|
IF MMU THEN
|
|
SUB.L RBAptr+llg,D0
|
|
ADD.L RBAptr+lph,D0 ; D0=physical address
|
|
ENDIF
|
|
|
|
MOVEA.L (SP)+,A1 ; get ptr to descriptor
|
|
|
|
SMOVE D0,buff_ptr0(A1) ; setup resource descriptor
|
|
SWAP D0
|
|
SMOVE D0,buff_ptr1(A1)
|
|
|
|
MOVE.L RxDescs,D1
|
|
MULU #Max_Pkt_Size/2,D1 ; D1=word count for buffer area
|
|
|
|
SMOVE D1,buff_wc0(A1) ; setup buffer size
|
|
SWAP D1
|
|
SMOVE D1,buff_wc1(A1)
|
|
|
|
MOVEQ #-1,D0 ; reset all bits in ISR
|
|
SMOVE D0,Int_Status(A2)
|
|
BSR Set10Seconds ; init timer value
|
|
|
|
SUB.L D0,D0
|
|
SMOVE D0,Command(A2) ; start chip running
|
|
@wait
|
|
SMOVE Command(A2),D0 ; wait for SONIC to start up
|
|
BTST #SoftReset,D0
|
|
BNE.S @wait
|
|
|
|
MOVEQ #ReadRRA,D0
|
|
BSR SONICSync ; read RRA descriptor
|
|
@loadRD
|
|
MOVE.L RDAptr,D0
|
|
|
|
IF MMU THEN
|
|
SUB.L RDAptr+llg,D0
|
|
ADD.L RDAptr+lph,D0 ; D0= physical address
|
|
ENDIF
|
|
|
|
SMOVE D0,Current_RDA(A2) ; setup RDA pointers
|
|
SWAP D0
|
|
SMOVE D0,Upper_RDA(A2)
|
|
|
|
BSR RestartSONIC ; enable reception and start timer
|
|
|
|
MOVE.L #OurIntsMask,D0 ; setup for our interrupts
|
|
SMOVE D0,Int_Mask(A2) ; enable SONIC interrupts
|
|
MOVE.L MemSize(A6),D0 ; return # unused bytes in usage area
|
|
@IError
|
|
MOVEA.L (SP)+,A2
|
|
UNLK A6
|
|
RTS
|
|
|
|
IF MMU THEN
|
|
@SetAddresses
|
|
; set lowest logical/physical addresses for pointer in A1
|
|
MOVE.L D0,-(SP) ; save mem size, ptr
|
|
MOVE.L A1,-(SP)
|
|
MOVE.L D0,-(SP) ; pass logical size
|
|
MOVE.L MemStart(A6),-(SP) ; pass logical address
|
|
MOVEA.L TransAddr(A6),A0
|
|
JSR (A0) ; D0=lowest physical addr
|
|
ADDQ.W #8,SP
|
|
MOVEA.L (SP)+,A1
|
|
MOVE.L D0,lph(A1) ; set lowest physical address
|
|
MOVE.L MemStart(A6),llg(A1) ; set lowest logical address
|
|
MOVE.L (SP)+,D0 ; get back mem size
|
|
RTS
|
|
ENDIF
|
|
|
|
ENDWITH
|
|
ENDPROC
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ SONIC ShutDown
|
|
; void SONICHALT()
|
|
|
|
SONICHALT PROC EXPORT
|
|
OurStack RECORD {A6Link} ; <Z3> thru next <Z3>
|
|
Sz EQU *
|
|
A6Link DS.L 2
|
|
SONICPtr DS.L 1
|
|
ENDR
|
|
|
|
WITH SONICRegs
|
|
|
|
LINK A6,#OurStack.Sz
|
|
MOVE.L A2,-(SP)
|
|
|
|
MOVEA.L IntDRtn,A0 ; A0->proc to disable interrupts
|
|
JSR (A0) ; call it
|
|
MOVE.L D0,-(SP) ; save SR returned
|
|
|
|
MOVEA.L OurStack.SONICptr(A6),A2 ; A2->sonic regs <Z3>
|
|
BSR ResetSONIC ; disable packet reception
|
|
SUB.L D0,D0
|
|
SMOVE D0,Int_Mask(A2) ; disable SONIC interrupts
|
|
SMOVE D0,CAM_Enable(A2) ; wipe out the CAM
|
|
|
|
MOVEA.L IntERtn,A0 ; <Z3>
|
|
JSR (A0) ; reenable interrupts <Z3>
|
|
ADDQ.W #4,SP ; <Z3>
|
|
|
|
MOVEA.L (SP)+,A2
|
|
UNLK A6 ; <Z3>
|
|
RTS ; all done
|
|
ENDPROC
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ SONIC Transmit
|
|
; void SONICXMIT(wdsPtr)
|
|
|
|
parms RECORD {A6Link}
|
|
LocalSize EQU *
|
|
SaveA2 DS.L 1
|
|
A6Link DS.L 2
|
|
SONICPtr DS.L 1 ; <Z3>
|
|
wdsPtr DS.L 1 ; write data structure pointer
|
|
ENDR
|
|
|
|
PROC
|
|
EXPORT SONICXMIT
|
|
WITH SONICRegs,TxPkt,parms
|
|
|
|
noTDA
|
|
MOVEA.L IntERtn,A0
|
|
MOVE.L D0,-(SP) ; save SR returned by proc
|
|
JSR (A0) ; reenable interrupts
|
|
MOVEQ #-1,D0
|
|
UNLK A6
|
|
RTS
|
|
SONICXMIT
|
|
LINK A6,#LocalSize ; make some room
|
|
|
|
MOVEA.L IntDRtn,A0 ; A0->proc to disable interrupts
|
|
JSR (A0) ; call it
|
|
|
|
MOVE.L FreeTxTDA,D1
|
|
BEQ.S noTDA ; If no TDA available
|
|
; it's always faster to not branch
|
|
MOVE.L A2,SaveA2(A6) ; save regs
|
|
MOVE.L D0,-(SP) ; save SR returned by IntDRtn proc
|
|
|
|
LEA FreeTxTDA,A0
|
|
MOVEA.L (A0),A1 ; A1->new TDA
|
|
MOVE.L nextTD(A1),(A0) ; unlink from free list
|
|
|
|
EXG A1,A2 ; save TDA ptr
|
|
MOVEA.L IntERtn,A0
|
|
JSR (A0) ; reenable interrupts maybe
|
|
EXG A1,A2 ; restore TDA ptr
|
|
|
|
MOVEA.L wdsPtr(A6),A2 ; A2->wds, A1->this TDA
|
|
|
|
SUB.L D0,D0 ; clear 32 bits
|
|
SMOVE D0,frag_count(A1) ; init Tx fields
|
|
SMOVE D0,pkt_size(A1)
|
|
SMOVE D0,status(A1)
|
|
SMOVE D0,config(A1) ; start timer after SFD, tx FCS, time
|
|
; excessive deferrals
|
|
|
|
LEA frag_start(A1),A0 ; A0->fragment fields
|
|
@fragloop
|
|
SUB.L D0,D0 ; clear 32 bits
|
|
MOVE.W (A2)+,D0 ; check wds segment len
|
|
BEQ.S @chkpkt ; see if everything is ok
|
|
|
|
IF SONIC32 THEN
|
|
ADDQ.L #1,frag_count(A1)
|
|
ADD.L D0,pkt_size(A1) ; and total packet size
|
|
ELSE
|
|
ADDQ.W #1,frag_count(A1) ; bump count
|
|
ADD.W D0,pkt_size(A1) ; and total packet size
|
|
ENDIF
|
|
|
|
MOVE.L D0,-(SP) ; save frag size from wds
|
|
MOVE.L (A2)+,D0 ; get wds ptr
|
|
SMOVE D0,(A0)+ ; set lower 16 of frag_ptr
|
|
SWAP D0
|
|
SMOVE D0,(A0)+ ; set upper 16
|
|
MOVE.L (SP)+,D0
|
|
SMOVE D0,(A0)+ ; set frag size in TDA
|
|
BRA.S @fragloop ; keep going
|
|
@chkpkt
|
|
SMOVE pkt_size(A1),D0
|
|
EXT.L D0 ; make a 32 bit quantity
|
|
|
|
SUBI.L #Min_Pkt_Size,D0 ; calc pad size
|
|
BHS.S @sendit ; go do it if long enough
|
|
|
|
NEG.L D0 ; convert to positive number
|
|
|
|
IF SONIC32 THEN
|
|
|
|
ADDQ.L #1,frag_count(A1) ; add another fragment for padding
|
|
ADD.L D0,pkt_size(A1) ; bump total too
|
|
|
|
ELSE
|
|
|
|
ADDQ.W #1,frag_count(A1) ; add another fragment for padding
|
|
ADD.W D0,pkt_size(A1) ; bump total too
|
|
|
|
ENDIF
|
|
|
|
MOVE.L RBAptr,D1 ; start of buffers
|
|
|
|
IF MMU THEN
|
|
SUB.L RBAptr+llg,D1
|
|
ADD.L RBAptr+lph,D1 ; convert to physical address
|
|
ENDIF
|
|
|
|
SMOVE D1,(A0)+ ; set lower 16 of frag_ptr
|
|
SWAP D1
|
|
SMOVE D1,(A0)+ ; set upper 16
|
|
|
|
SMOVE D0,(A0)+ ; set frag size in TDA
|
|
@sendit
|
|
MOVEQ #(1<<EOL_Bit), D0
|
|
SMOVE D0,(A0) ; set link field
|
|
|
|
EXG A1,A2 ; save curr frag ptr
|
|
|
|
MOVEA.L IntDRtn,A0 ; A0->proc to disable interrupts
|
|
JSR (A0) ; call it (SR already on stack from above)
|
|
|
|
EXG A1,A2 ; restore curr frag ptr in A1
|
|
MOVEA.L SONICptr(A6),A2 ; A2->sonic regs <Z3>
|
|
|
|
MOVE.L NextTxTDA,D0 ; check if we already have a chain
|
|
BNE.S @haveChain
|
|
|
|
LEA NextTxTDA,A0 ; start a new chain
|
|
MOVE.L A1,(A0)
|
|
BRA.S @doxmit ; transmit new chain maybe
|
|
@haveChain
|
|
MOVEA.L D0,A0 ; A0->start of existing chain
|
|
SMOVE Upper_TDA(A2),D1
|
|
SWAP D1 ; get upper TDA address
|
|
@chkTDA
|
|
SMOVE frag_count(A0),D0 ; D0=fragment count for this packet
|
|
FragMul D0 ; calc an offset to the link field
|
|
LEA frag_start(A0),A0 ; A0->start of fragments for this pkt
|
|
LEA (A0,D0.W),A0 ; A0->link field for this pkt
|
|
SMOVE (A0),D0
|
|
BTST #EOL_Bit,D0 ; at the last pkt in chain?
|
|
BNE.S @setlink ; append to end if so
|
|
|
|
MOVE.W D0,D1 ; D1=physical address of next TDA
|
|
|
|
IF MMU THEN
|
|
SUB.L TxTDAPtr+lph,D1
|
|
ADD.L TxTDAPtr+llg,D1 ; D1=logical addr (upper half)
|
|
ENDIF
|
|
|
|
MOVEA.L D1,A0 ; A0->next TDA
|
|
BRA.S @chkTDA ; keep searching for last TDA
|
|
@setlink
|
|
MOVE.L A1,D0 ; D0=ptr to new TDA
|
|
|
|
IF MMU THEN
|
|
SUB.L TxTDAPtr+llg,D0
|
|
ADD.L TxTDAPtr+lph,D0 ; D0=physical address
|
|
ENDIF
|
|
|
|
SMOVE D0,(A0) ; update link of last TDA
|
|
@doxmit
|
|
LEA TxTDAptr,A0
|
|
TST.L (A0)
|
|
BNE.S @done ; transmit already in progress
|
|
|
|
LEA NextTxTDA,A1
|
|
MOVE.L (A1),(A0) ; start transmitting current chain
|
|
MOVEQ #0, D0
|
|
MOVE.L D0, (A1) ; empty chain
|
|
|
|
MOVE.L (A0),D0
|
|
|
|
IF MMU THEN
|
|
SUB.L TxTDAPtr+llg,D0
|
|
ADD.L TxTDAPtr+lph,D0 ; D0=physical address of curr TDA
|
|
ENDIF
|
|
|
|
SMOVE D0,Current_TDA(A2) ; set current SONIC TDA ptr
|
|
|
|
MOVEQ #(1<<TxEnable), D0 ; set command bit
|
|
SMOVE D0,Command(A2) ; start transmitting
|
|
@done
|
|
MOVEA.L IntERtn,A0
|
|
JSR (A0) ; reenable interrupts maybe
|
|
ADDQ.W #4,SP
|
|
MOVEA.L SaveA2(A6),A2 ; restore reg
|
|
|
|
UNLK A6
|
|
SUB.L D0,D0 ; good return code
|
|
RTS
|
|
ENDWITH
|
|
ENDPROC
|
|
|
|
;¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥ SONIC CAM Load
|
|
; SONICCAMLOAD(CAMentry,Loadit)
|
|
; Set/Clear Content Addressable Memory. Return CAM index when setting an entry.
|
|
|
|
SONICCAMLOAD PROC EXPORT
|
|
|
|
parms RECORD {A6Link}
|
|
LocalSize EQU *
|
|
A6Link DS.L 2
|
|
SONICPtr DS.L 1 ; <Z3>
|
|
CAMentry DS.W 3 ; 48 bit address to set in CAM
|
|
Loadit DS.L 1 ; true if adding CAM entry
|
|
ENDR
|
|
|
|
WITH parms,SONICRegs,CAMDesc
|
|
|
|
LINK A6,#LocalSize ; save A6
|
|
MOVEM.L A2/D3/D4,-(SP) ; save reg
|
|
|
|
MOVEA.L IntDRtn,A0 ; A0->proc to disable interrupts <Z3>
|
|
JSR (A0) ; call it <Z3>
|
|
MOVE.L D0,-(SP) ; save SR returned <Z3>
|
|
|
|
MOVEA.L SONICptr(A6),A2 ; A2->SONIC <Z3>
|
|
|
|
MOVE.L CAMentry(A6),D1 ; D1=upper/middle of 48 bit addr
|
|
MOVE.W CAMentry+4(A6),D2 ; D2.W=lower "
|
|
|
|
TST.L Loadit(A6) ; doing a load CAM?
|
|
BEQ.S @doClear ; no
|
|
; search for an empty CAM entry
|
|
@wait1
|
|
SMOVE Command(A2),D0
|
|
EORI.W #(1<<StartTimer)+(1<<RxEnable),D0
|
|
BNE.S @wait1 ; make sure no other commands active
|
|
|
|
SMOVE CAM_Enable(A2),D0 ; get current CAM map
|
|
MOVEQ #15,D3
|
|
@chkMap
|
|
ASL.W #1,D0 ; check a bit
|
|
DBCC D3,@chkMap ; do them all
|
|
BCC.S @haveit ; until we find one
|
|
MOVE.W D3,D0
|
|
EXT.L D0 ; D0.L=-1
|
|
BRA @Xit ; return error
|
|
@haveit
|
|
MOVEA.L RRAptr,A0 ; A0->RRA, D3=index to CAM cell
|
|
|
|
ROR.W #8,D2 ; swap bytes in word
|
|
SMOVE D2,Port0(A0) ; set lower 16 bits
|
|
|
|
ROR.W #8,D1 ; swap bytes in word
|
|
SMOVE D1,Port1(A0) ; set middle "
|
|
|
|
SWAP D1
|
|
ROR.W #8,D1 ; swap bytes in word
|
|
SMOVE D1,Port2(A0) ; set upper "
|
|
|
|
SMOVE CAM_Enable(A2),D0 ; get current CAM map
|
|
BSET D3,D0 ; set the new one
|
|
SMOVE D0,enable(A0) ; set bit map for CAM
|
|
|
|
BSR.S LoadCAMcells ; load descriptor and CAM enable reg
|
|
|
|
MOVE.L D3,D0 ; set function result
|
|
BRA.S @Xit
|
|
@doClear
|
|
BSR ResetSONIC ; let transmits/receives complete
|
|
|
|
MOVEQ #15,D3
|
|
SMOVE CAM_Enable(A2),D0 ; get current CAM map
|
|
@compCAM
|
|
ASL.W #1,D0 ; check cell
|
|
DBCS D3,@compCAM ; until we have an active one
|
|
BCS.S @compareit
|
|
@notfound
|
|
BSR RestartSONIC ; get SONIC going again
|
|
MOVE.W D3,D0
|
|
EXT.L D0 ; D0.L=-1
|
|
BRA.S @Xit ; return error (did'nt find entry)
|
|
@more
|
|
SUBQ #1,D3 ; keep index straight
|
|
BMI.S @notfound
|
|
BRA.S @compCAM
|
|
@compareit ; compare CAM to addr in D1/D2
|
|
SMOVE D3,CAM_EntryPtr(A2) ; select CAM cell to read
|
|
SMOVE CAM_Port1(A2),D4 ; get middle 16 bits
|
|
ROR.W #8,D4 ; normalize it
|
|
MOVE.W D4,-(SP) ; save it
|
|
SMOVE CAM_Port0(A2),D4 ; get upper 16 bits
|
|
ROR.W #8,D4 ; normalize it
|
|
MOVE.W D4,-(SP) ; save it
|
|
CMP.L (SP)+,D1 ; same as the one we want?
|
|
BNE.S @more ; no, keep checking
|
|
|
|
SMOVE CAM_Port2(A2),D4 ; get lower 16
|
|
ROR.W #8,D4 ; normalize it
|
|
CMP.W D4,D2 ; same?
|
|
BNE.S @more ; look again if not
|
|
|
|
MOVEA.L RRAptr,A0 ; A0->CAM descriptor
|
|
|
|
SUB.L D2,D2
|
|
SMOVE D2,Port0(A0) ; put zero entry in cell
|
|
SMOVE D2,Port1(A0)
|
|
SMOVE D2,Port2(A0)
|
|
SMOVE CAM_Enable(A2),D0 ; get current CAM map
|
|
BCLR D3,D0 ; clear the one to delete
|
|
SMOVE D0,enable(A0) ; and do it
|
|
|
|
BSR RestartSONIC ; get SONIC going again
|
|
BSR.S LoadCAMcells ; clear the entry now
|
|
SUB.L D0,D0 ; clear 32 bits
|
|
@Xit
|
|
MOVEA.L IntERtn,A0 ; <Z3>
|
|
JSR (A0) ; reenable interrupts <Z3>
|
|
ADDQ.W #4,SP ; <Z3>
|
|
|
|
MOVEM.L (SP)+,A2/D3/D4
|
|
UNLK A6
|
|
RTS
|
|
|
|
|
|
LoadCAMcells ; setup CAM cells and enable register
|
|
; D3=base zero index of CAM cell, A0->CAM load descriptor
|
|
SMOVE D3,Entry_ptr(A0) ; set base zero index to CAM cell
|
|
MOVE.L A0,D0
|
|
|
|
IF MMU THEN
|
|
SUB.L RRAptr+llg,D0
|
|
ADD.L RRAptr+lph,D0 ; D0=physical address
|
|
ENDIF
|
|
|
|
SMOVE D0,CAM_DescPtr(A2) ; set current descriptor ptr
|
|
MOVEQ #1, D0
|
|
SMOVE D0,CAM_Count(A2) ; set one cell only
|
|
|
|
MOVEQ #LoadCAM,D0
|
|
BRA SONICSync ; do it now & return
|
|
ENDWITH
|
|
ENDPROC
|
|
|
|
END
|
|
|