Web 51 - Packet Driver RTL8019AS

Web 51 - Packet Driver RTL8019AS Vysilani paketu - part 2  software.html  Web 51 - Packet Driver RTL8019AS Zdrojove texty a literatura - part 4

část 3 - příjem paketů

Příjem paketů je nesporně nejsložitější částí celého driveru. Nejprve ukážeme proceduru, která čte hlavičku přijatého paketu včetně stavových informací.
;*************************************************************
;***            R E C E I V E   P A C K E T                 **
;*************************************************************

;*************************************************************
;** read header of receive packet
;**
ReadPacketHeader:
        mov     R2,#high(SIZE_OF_8019_HDR+SIZE_OF_ETH_PKT_HDR)
        mov     R3,#low(SIZE_OF_8019_HDR+SIZE_OF_ETH_PKT_HDR) ;R2R3 Byte Count
;       MOV     R4,#...         ;R4R5 Remote Start Address
        MOV     R5,#0
        MOV     R1,#rcv_hdr     ;R1 store pointer
        MOV     DPTR,#icall_save;pointer to procedure BYTE(@R1) save
        AJMP    DMARead

Hlavička přečtená z obvodu RTL vypadá následovně:

rcv_hdr Received frame status Status přijatého paketu 1 byte
rcv_hdr_nxt_pg Page after this frame Ukazatel na následující paket 1 byte
rcv_hdr_size Length of this frame Délka paketu 2 byte
eth_pkt_hdr_dest Destination Address MAC Adresa příjemce 6 bytů
eth_pkt_hdr_src Source Address MAC Adresa odesílatele 6 bytů
eth_pkt_hdr_type Length Délka paketu 2 byty

Ukažme tedy jak vypadá zpracování přijatého paketu.

;*************************************************************
;** receive packet
;**
rcv_pkt:

Nejprve zjistíme, zda je co zpracovávat.

        ISAIN   EN0_ISR         ; Get pending interrupts
        JNZ     ISRtestOverrun
        RET                     ; Ret if none

Otestujeme zda nedošlo k poškození dat v bufferu, vlivem jeho přetečení.

ISRtestOverrun:
                                                ; Was there an overrun ?
        JB      BITISR_OVER,recv_overrun        ; Go if so
        AJMP    recv_no_overrun                 ; Go if not

Buffer přetekl, je nutno ošetřit přetečení.

;*************************************************************
;** receive overrun
;**

Nejprve si uschováme aktuální stav obvodu.

recv_overrun:
        ISAIN   EN_CMD          ; read Chip's command register
        PUSH    Acc             ; and save it

A poté zastavíme obvod.

;; Stop the NIC
        ISAOUT  EN_CMD, #EN_PAGE0+EN_NODMA+EN_STOP
                                ; Remote DMA, Stop and reset the chip

A vyčkáme na dokončení příjmu či vysílání paketu.

;; Wait 1.6ms for the NIC to stop transmitting or receiving a packet. National
;; says monitoring the ISR RST bit is not reliable, so a wait of the maximum
;; packet time (1.2ms) plus some padding is required.
        ACALL   longpause

Poté začneme se "vkříšením" obvodu, nastavením délky přenosu na nulu.

;; Reset RBCR[01] back to zero as per magic incantation.
        BEGINPORTDATA
        PORTDATA        EN0_RCNTHI,0    ; MSB Remote byte count reg
        PORTDATA        EN0_RCNTLO,0    ; LSB Remote byte count reg
        ENDPORTDATA

Otestujeme, zda obvod v okamžiku zastavení vysílal, a pokud ano, zjistíme, zda bylo v pořádku dokončeno. Pokud ne tak si to poznamenáme a později zopakujeme přenos.

;; check the saved state of the EN_TRANS bit in the command register
        CLR     flagResend
        POP     Acc             ; pop Chip's command register
        JNB     BIT_TRANS,rcv_ovr_loopback
;; Transmitter was running, see if it finished or died
        ISAIN   EN0_ISR         ; Get pending interrupts
        ANL     A,#ENISR_TX_ERR+ENISR_TX ; Did the transmitter finish?
        JNZ     rcv_ovr_loopback        ; one will be set if TX finished
; Transmitter did not complete, remember to resend the packet later.
        SETB    flagResend
rcv_ovr_loopback:

Do doby dokončení celé záchrané operace, je nutno obvod zapnout do smyčkového módu, kdy nepříjímá data z linky. Po té je možno obvod opět spustit.

;; Have to enter loopback mode and then restart the NIC before you are
;; allowed to slurp packets up off the ring
        BEGINPORTDATA
        PORTDATA        EN0_TXCR,ENTXCR_LOOP ; set internal loopback mode
        PORTDATA        EN_CMD, EN_PAGE0+EN_NODMA+EN_START
                                ; Start the chip running again

Zkontrolujeme, zda je v bufferu nějaký paket, porovnáním adresy kam bude obvod ukládat data a adresy kde je následující paket očekáván tímto programem.

;; Verify that there is really a packet to receive by fetching the current
;; page pointer and comparing it to the next packet pointer.
        PORTDATA        EN_CMD, EN_PAGE1+EN_NODMA       ; Set Page 1
        ENDPORTDATA
        ISAIN   EN1_CURPAG      ; Current memory page
        MOV     R4,A
        ISAOUT  EN_CMD, #EN_PAGE0+EN_NODMA      ; Page 1, Remote DMA
        MOV     A,next_packet
        XRL     A,R4            ; Check if buffer empty
        JNZ     rcv_ovr_rx_one  ; O.K. get the NIC header

V paměti není žádný paket, přeskoč verifikaci.

; NO PACKET IN THE RING AFTER AN OVW INTERRUPT??? Can this ever happen?
; YES! if overrun happend between a receive interrupt and the when the
; current page register is read at the start of recv_frame.
        AJMP    rcv_ovr_empty   ; Current Page == next_packet

Přečteme hlavičku přijatého paketu.

rcv_ovr_rx_one:
;       MOV     R5,#0           ; R4R5 Remote Start Address Register
        PUSH    AR4
        ACALL   ReadPacketHeader
        POP     AR4

Začneme kontrolovat přijatý paket ve frontě na jeho poškození.

        MOV     A,rcv_hdr       ; Get the buffer status byte
        ;Received a good packet ?

Nejprve zjistíme, zda má paket ve své hlavičce uvedeno zda je správně přijatý.

        JNB     BITRSR_RXOK, rcv_ovr_ng  ; No, received debris

Pokud ano, zkontrolujeme ukazatel na další paket ve frontě zda je v povoleném rozsahu.

; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
; it doesn't hurt to range check the next packet pointer here.
        MOV     A,rcv_hdr_nxt_pg        ; pointer to next packet
        CJNE    A,#RX_START_PG,$+3      ;; First page of RX Ring
        JC      rcv_ovr_ng      ;; < RX_START_PG
                                ;;invalid pointer, Bellow around the bottom
        CJNE    A,#NE_STOP_PG,$+3;;Last page + 1 of RX Ring
        JNC     rcv_ovr_ng      ;; >= NE_STOP_PG
                                ;;invalid pointer, Above the top

Ukazatel je v pořádku, proto jej uložíme a zpracujeme přijatý paket.

        MOV     next_packet,A   ;save pointer to next packet
        MOV     curr_recv,R4    ;save pointer to current packet
        LCALL   ProcessEthPacket
        SJMP    rcv_ovr_ok

Pokud v hlavičce není uvedeno správné přijetí paketu, popř. je nesprávný ukazatel na další paket, zahodíme všechny pakety v paměti.

rcv_ovr_ng:
;
; HAD TO ADD ERROR RECOVERY HERE. TO BLINDLY PROCEED AND ASSUME THE NEXT
; PACKET POINTR FROM THE NIC HEADER IS VALID IS INVITING DISASTER.
;
; Error recovery consists of killing and restarting the NIC. This drops all
; the packets in the ring, but thats better than winding up in the weeds!
;

; Instead copy the last known current page pointer into the next packet pointer
; which will result in skipping all the packets from the errored one to where
; the NIC was storing them when we entered this ISR, but prevents us from
; trying to follow totally bogus next packet pointers through the card RAM
; space.
        MOV     A,R4            ; Current memory page
        ;;MOV   next_packet,A

Poté ukončíme proceduru přijetí paketu potvrzením přerušení a instrukcí RET.

        AJMP    recv_frame_break1       ;save next_packet...

Přitý paket je zpracován, popř. nebyl přijat žádný paket. Zbývá nastavit mezní registr.

rcv_ovr_ok:
rcv_ovr_empty:
        MOV     A,next_packet   ; Grap the next packet pointer
        DEC     A               ; Back up one page
        CJNE    A,#RX_START_PG,$+3 ;; Did it wrap?
        JNC     BoundaryOK      ; >= RX_START_PG
        MOV     A,#NE_STOP_PG-1 ;; Yes, back to end of ring
BoundaryOK:
        ISAOUTA EN0_BOUNDARY    ;Boundary Register

Smazat příznak přepsání přijímací fronty.

        BEGINPORTDATA
; Clear the OVW bit in the ISR register.
        PORTDATA        EN0_ISR, ENISR_OVER ;Interrupt status reg
                                ;Receiver overwrote the ring

Vypnou režim smyčky.

; Take the NIC out of loopback
        PORTDATA        EN0_TXCR, 0     ;Normal Operation
        ENDPORTDATA

A pokud bylo zastaveno probíhající vysílání, tak jej obnovit.

; Any incomplete transmission to resend?
        JNB     flagResend,recv_frame_break     ;No
; Yes, restart the transmission
        ISAOUT  EN_CMD, EN_TRANS+EN_NODMA+EN_START      ;Start the transmitter

Poté ukončíme proceduru přijetí paketu potvrzením přerušení a instrukcí RET.

        AJMP    recv_frame_break

Buffer nepřetekl, zkontrolujeme zda došlo při příjmu k chybám.

recv_no_overrun:
        JNB     BITISR_COUNTERS, NoReadTallyCounters

Pokud byly detekovány chyby, tak přečteme jejich počet.

;*************************************************************
;** some errors, read Tally Counters
;**
        PUSH    Acc
        MOV     ADDRPORT,#EN0_COUNTER0  ;CNTR0..2
;CNTR0 Frame Alignment Error Tally Counter Register
;CNTR1 CRC Error Tally Counter Register
;CNTR2 Missed Packet Tally Counter Register
        ISAREAD
        INC     ADDRPORT
        ISAREAD
        INC     ADDRPORT
        ISAREAD
        ISAOUT  EN0_ISR, #ENISR_COUNTERS        ;Interrupt status reg
                                ;ReSet CNT (Error Tally Counters)
        POP     Acc
NoReadTallyCounters:

Pokud byl přijat paket, ať již vpořádku, či s chybou zpracujeme jej.

        JB      BITISR_RX, PacketReceivedOK
        JB      BITISR_RX_ERR, PacketReceived

V opačném případě ukončíme proceduru přijetí paketu potvrzením přerušení a instrukcí RET.

        AJMP    recv_frame_break
;*************************************************************
;** test frame pointer
;**

Podtvrdíme zpracování přerušení od přijatého paketu

PacketReceived:
PacketReceivedOK:
        ISAOUT  EN0_ISR, #ENISR_RX_ERR + ENISR_RX       ; Clear those request

Poté si uschováme ukazatel, pokud je buffer zaplněn přijatými pakety

;; Get the rx page (incoming packet pointer)
        ISAOUT  EN_CMD, #EN_PAGE1+EN_NODMA+EN_START
                                ; Switch to page 1 registers
        ISAIN   EN1_CURPAG      ; Get current page of rcv ring
        PUSH    Acc             ; ans save it
        ISAOUT  EN_CMD, #EN_PAGE0+EN_NODMA+EN_START
                                ; Back to page 0 registers

A v cykly zpracujeme postupně celou frontu.

; This becomes the loop back point to read packets from the ring.
; now only loop back and read until those packets received at the time
; the current page register is read above have been read.
recv_frame:
;; Read all the frames ??
        MOV     R4,next_packet
        POP     Acc             ; Get current page of rcv ring
        CJNE    A,AR4,recv_more_frames

Došli jsme na konec fronty, potvrdíme přerušení a vrátíme se instrukcí RET

        SJMP    recv_frame_break

Přečteme hlavičku paketu

;; Remove one frame from the ring. Boundary is always a page behind.
recv_more_frames:
        PUSH    Acc             ; Save current page of rcv ring
        MOV     curr_recv,R4
;       MOV     R5,#0           ; R4R5 Remote Start Address Register
        ACALL   ReadPacketHeader

A otestujeme zda je přijatý paket vpořádku

        MOV     A,rcv_hdr       ; Get the buffer status byte
        XRL     A,#ENRSR_RXOK   ; Good packet ?
        JZ      GoodPacket

Popř. zda nebyl přijat broadcast/multicast

        XRL     A,#(ENRSR_PHY + ENRSR_RXOK) XOR ENRSR_RXOK
                                ;Received broadcast/multicast
        JNZ     InvalidNextFramePtr
GoodPacket:

Paket vypadá vpořádku, zkontrolujeme ukazatel na hlavičku následujícího paketu

; EVEN if the NIC header status is OK, I have seen garbaged NIC headers, so
; it doesn't hurt to range check the next packet pointer here.
        MOV     A,rcv_hdr_nxt_pg; get pointer to next packet
        MOV     next_packet,A   ; and save it
        CJNE    A,#RX_START_PG,$+3      ;; First page of RX Ring
        JC      InvalidNextFramePtr     ; < RX_START_PG
        CJNE    A,#NE_STOP_PG,$+3       ;; Last page + 1 of RX Ring

V případě, že je vše v pořádku paket zpracujeme

        JC      ProcessFrame            ; next_packet < NE_STOP_PG
;

Pokud není v pořádku, nastavíme ukazatel na konec fronty a ukončíme proceduru.

InvalidNextFramePtr:
        POP     Acc             ; Get current page of rcv ring
recv_frame_break1:
        MOV     next_packet,A
recv_frame_break:
        ISAOUT  EN0_ISR, #ENISR_RDC ;Interrupt status reg
                                ;remote dma complete
        RET

Zpracování paketu(*)

;*************************************************************
;** process frame
;**
ProcessFrame:
        LCALL   ProcessEthPacket

Paket byl zpracován, vyjmeme jej z fronty

        MOV     R4,next_packet
        DEC     R4
        CJNE    R4,#RX_START_PG,$+3     ;;First page of RX Ring
        JNC     SetBoundaryNxt  ; >= RX_START_PG
        MOV     R4,#NE_STOP_PG-1;;(Last page + 1)-1 of RX Ring
SetBoundaryNxt:
        ISAOUT  EN0_BOUNDARY,R4 ;Boundary page of ring buffer

A zpracujeme další případný paket

        SJMP    recv_frame
Dil 2Packet Driver RTL8019AS, část 4

(*) Web 51 používá mírně pozměněné volání, packet driver místo volání ProcessEthPacket poznamená pomocí stavových bitů eth_state bod kde bude v činnosti driveru pokračováno a předá řízení nadřazené (volající) proceduře.





Sponzored by LPhard Ltd. Graphics by GIMP Created by EasyPad

(c)Copyright 2000, 2001, HW server & Radek Benedikt
Web51@HW.cz, Web51.HW.cz

Final applications of the Web51 : www.HWgroup.cz
Web 51 - Packet Driver RTL8019AS Vysilani paketu - part 2  Obsah  Web 51 - Packet Driver RTL8019AS Zdrojove texty a literatura - part 4