Web 51 - Packet Driver RTL8019AS |
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 DMAReadHlavič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 noneOtestujeme 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 notBuffer 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 itA poté zastavíme obvod.
;; Stop the NIC ISAOUT EN_CMD, #EN_PAGE0+EN_NODMA+EN_STOP ; Remote DMA, Stop and reset the chipA 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 longpausePoté 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 ENDPORTDATAOtestujeme, 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 againZkontrolujeme, 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 headerV 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_packetPř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 AR4Zač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 debrisPokud 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 topUkazatel 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_okPokud 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,APoté 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 RegisterSmazat 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 ringVypnou režim smyčky.
; Take the NIC out of loopback PORTDATA EN0_TXCR, 0 ;Normal Operation ENDPORTDATAA 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 transmitterPoté ukončíme proceduru přijetí paketu potvrzením přerušení a instrukcí RET.
AJMP recv_frame_breakBuffer nepřetekl, zkontrolujeme zda došlo při příjmu k chybám.
recv_no_overrun: JNB BITISR_COUNTERS, NoReadTallyCountersPokud 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, PacketReceivedV 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 requestPoté 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 registersA 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_framesDošli jsme na konec fronty, potvrdíme přerušení a vrátíme se instrukcí RET
SJMP recv_frame_breakPř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 ReadPacketHeaderA otestujeme zda je přijatý paket vpořádku
MOV A,rcv_hdr ; Get the buffer status byte XRL A,#ENRSR_RXOK ; Good packet ? JZ GoodPacketPopř. 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 RingV 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 RETZpracování paketu(*)
;************************************************************* ;** process frame ;** ProcessFrame: LCALL ProcessEthPacketPaket 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 bufferA zpracujeme další případný paket
SJMP recv_framePacket 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.
POPIS Web51 | NOVINKY | FAQ | OBJEDNÁVKA | DOWNLOAD |
(c)Copyright 2000, 2001, HW server & Radek Benedikt
Web51@HW.cz, Web51.HW.cz Final applications of the Web51 : www.HWgroup.cz |