Atmel Avr Tcpip Atmel-crystal.asm
.include "M103def.inc"
.list
.listmac
.eseg
.db "Copyright 1998-1999 Gary T. Desrosiers. All Rights Reserved.",0
.cseg
.org 0
jmp start
;-----------------------------------------------------------------------+
; ATmega103 <===> Crystal Interconnects. |
;-----------------------------------------------------------------------+
; |
;PORTA - Unconnected. Because external SRAM enable bit set in MCUCR, |
; this port becomes the data port (AD0-7). |
; |
;PORTB - Connected to SA0-SA3 of Crystal board. PB4-PB7 is unconnected |
; |
;PORTC - Unconnected. Because external SRAM enable bit set in MCUCR, |
; this port becomes the high order address bus (A8-A15). |
; |
;PORTD - Connected to SD0-SD7 of the Crystal board (Crystal Data Bus). |
; |
;PORTE - Tied to PE0-->>/RD, PE1-->>/WR, PE2-->>/CHIPSEL, |
; and PE3<<--INTR on the Crystal board. |
; |
; Note: When using the STK300 development board, remove the PORTB, |
; PORTD, and PORTE jumpers. |
; |
;-----------------------------------------------------------------------+
; Note: When using the STK300 development board, perform the following: |
; |
; * Remove the PORTB jumpers (all 8) |
; * Remove the PORTD jumpers (all 8) |
; * Remove PORTE jumpers for RE0/RE1 |
; * Move J1 to J2 to disable 3.3v mode and enable 5.0v mode |
; * Optionally, connect the 16x1 or 2x8 LCD |
;-----------------------------------------------------------------------+
;
.equ CDB=PORTD ;Crystal Data Bus
.equ CAB=PORTB ;Crystal Address Bus
.equ CSIG=PORTE ;Crystal Signals
.equ IOR=0 ;Read
.equ IOW=1 ;Write
.equ CHIPSEL=2 ;Chip Select
.equ INTR=3 ;Interrupt signal
;
;
;
; *Change these* : Configuration equates.
;
.equ ClkFreq = 4000000 ;4 Mhz crystal
;
.equ IP1 = 192 ;first octet of IP address
.equ IP2 = 168 ;second octet of IP address
.equ IP3 = 1 ;third octet of IP address
.equ IP4 = 2 ;fourth octet of IP address
;
.equ MAC1 = 0x00 ;\
.equ MAC2 = 0x00 ; \
.equ MAC3 = 0x00 ; \
.equ MAC4 = 0x12 ; 48 bit IEEE OUI (Organizationally Unique Identifier)
.equ MAC5 = 0x34 ; /
.equ MAC6 = 0x56 ;/
;
; Some useful macros
;
.macro ppRD ;Read PacketPage port at addr @0
ldi offsetL,low(@0)
ldi offsetH,high(@0)
rcall ReadPP
.endmacro
;
.macro ppWR ;Write PacketPage port (addr,val)
ldi offsetL,low(@0)
ldi offsetH,high(@0)
ldi valueL,low(@1)
ldi valueH,high(@1)
rcall WritePP
.endmacro
;
.macro Dinput
clr wL ;Change the data bus to input
out DDRD,wL
.endmacro
;
.macro Doutput
ser wL ;Change the data bus to output
out DDRD,wL
.endmacro
;
.macro ior ;I/O port read at @0
ldi wL,@0
rcall ioRead
.endmacro
;
.macro iow ;I/O port write at @0
out CDB,wL
ldi wL,@0
out CAB,wL
rcall ioWrite
.endmacro
;
; Crystal CS8900 PacketPage equates
;
.equ portRxTxData = 0x00 ;Receive/Transmit data (port 0)
.equ portRxTxData1 = 0x02 ;Receive/Transmit data (port 0)
.equ portTxCmd = 0x04 ;Transmit Commnad
.equ portTxLength = 0x06 ;Transmit Length
.equ portISQ = 0x08 ;Interrupt status queue
.equ portPtr = 0x0a ;PacketPage pointer
.equ portData = 0x0c ;PacketPage data (port 0)
.equ portData1 = 0x0e ;PacketPage data (port 1)
;
; CS8900 PacketPage Offsets
;
.equ ppEISA = 0x0000 ;EISA Registration number of CS8900
.equ ppProdID = 0x0002 ;Product ID Number
.equ ppIOBase = 0x0020 ;I/O Base Address
.equ ppIntNum = 0x0022 ;Interrupt number (0,1,2, or 3)
.equ ppMemBase = 0x002C ;Memory Base address register (20 bit)
.equ ppRxCfg = 0x0102 ;Receiver Configuration
.equ ppRxCtl = 0x0104 ;Receiver Control
.equ ppTxCfg = 0x0106 ;Transmit Configuration
.equ ppBufCfg = 0x010A ;Buffer Configuration
.equ ppLineCtl = 0x0112 ;Line Control
.equ ppSelfCtl = 0x0114 ;Self Control
.equ ppBusCtl = 0x0116 ;Bus Control
.equ ppTestCtl = 0x0118 ;Test Control
.equ ppISQ = 0x0120 ;Interrupt status queue
.equ ppRxEvt = 0x0124 ;Receiver Event
.equ ppTxEvt = 0x0128 ;Transmitter Event
.equ ppBufEvt = 0x012C ;Buffer Event
.equ ppRxMiss = 0x0130 ;Receiver Miss Counter
.equ ppTxCol = 0x0132 ;Transmit Collision Counter
.equ ppLineSt = 0x0134 ;Line Status
.equ ppSelfSt = 0x0136 ;Self Status
.equ ppBusSt = 0x0138 ;Bus Status
.equ ppTxCmd = 0x0144 ;Transmit Command Request
.equ ppTxLength = 0x0146 ;Transmit Length
.equ ppIndAddr = 0x0158 ;Individual Address (IA)
.equ ppRxStat = 0x0400 ;Receive Status
.equ ppRxLength = 0x0402 ;Receive Length
.equ ppRxFrame = 0x0404 ;Receive Frame Location
.equ ppTxFrame = 0x0A00 ;Transmit Frame Location
;
; Register Numbers
;
.equ REG_NUM_MASK = 0x003F
.equ REG_NUM_RX_EVENT = 0x0004
.equ REG_NUM_TX_EVENT = 0x0008
.equ REG_NUM_BUF_EVENT = 0x000C
.equ REG_NUM_RX_MISS = 0x0010
.equ REG_NUM_TX_COL = 0x0012
;
; Self Control Register
;
.equ SELF_CTL_RESET = 0x0040
.equ SELF_CTL_HC1E = 0x2000
.equ SELF_CTL_HCB1 = 0x8000
;
; Self Status Register
;
.equ SELF_ST_INIT_DONE = 0x0080
.equ SELF_ST_SI_BUSY = 0x0100
.equ SELF_ST_EEP_PRES = 0x0200
.equ SELF_ST_EEP_OK = 0x0400
.equ SELF_ST_EL_PRES = 0x0800
;
; Bus Control Register
;
.equ BUS_CTL_USE_SA = 0x0200
.equ BUS_CTL_MEM_MODE = 0x0400
.equ BUS_CTL_IOCHRDY = 0x1000
.equ BUS_CTL_INT_ENBL = 0x8000
;
; Bus Status Register
;
.equ BUS_ST_TX_BID_ERR = 0x0080
.equ BUS_ST_RDY4TXNOW = 0x0100
;
; Line Control Register
;
.equ LINE_CTL_RX_ON = 0x0040
.equ LINE_CTL_TX_ON = 0x0080
.equ LINE_CTL_AUI_ONLY = 0x0100
.equ LINE_CTL_10BASET = 0x0000
;
; Test Control Register
;
.equ TEST_CTL_DIS_LT = 0x0080
.equ TEST_CTL_ENDEC_LP = 0x0200
.equ TEST_CTL_AUI_LOOP = 0x0400
.equ TEST_CTL_DIS_BKOFF = 0x0800
.equ TEST_CTL_FDX = 0x4000
;
; Receiver Configuration Register
;
.equ RX_CFG_SKIP = 0x0040
.equ RX_CFG_RX_OK_IE = 0x0100
.equ RX_CFG_CRC_ERR_IE = 0x1000
.equ RX_CFG_RUNT_IE = 0x2000
.equ RX_CFG_X_DATA_IE = 0x4000
;
; Receiver Event Register
;
.equ RX_EVENT_RX_OK = 0x0100
.equ RX_EVENT_IND_ADDR = 0x0400
.equ RX_EVENT_BCAST = 0x0800
.equ RX_EVENT_CRC_ERR = 0x1000
.equ RX_EVENT_RUNT = 0x2000
.equ RX_EVENT_X_DATA = 0x4000
;
;Receiver Control Register
;
.equ RX_CTL_RX_OK_A = 0x0100
.equ RX_CTL_MCAST_A = 0x0200
.equ RX_CTL_IND_A = 0x0400
.equ RX_CTL_BCAST_A = 0x0800
.equ RX_CTL_CRC_ERR_A = 0x1000
.equ RX_CTL_RUNT_A = 0x2000
.equ RX_CTL_X_DATA_A = 0x4000
;
;Transmit Configuration Register
;
.equ TX_CFG_LOSS_CRS_IE = 0x0040
.equ TX_CFG_SQE_ERR_IE = 0x0080
.equ TX_CFG_TX_OK_IE = 0x0100
.equ TX_CFG_OUT_WIN_IE = 0x0200
.equ TX_CFG_JABBER_IE = 0x0400
.equ TX_CFG_16_COLL_IE = 0x8000
.equ TX_CFG_ALL_IE = 0x8FC0
;
;Transmit Event Register
;
.equ TX_EVENT_TX_OK = 0x0100
.equ TX_EVENT_OUT_WIN = 0x0200
.equ TX_EVENT_JABBER = 0x0400
.equ TX_EVENT_16_COLL = 0x1000
;
; Transmit Command Register
;
.equ TX_CMD_START_5 = 0x0000
.equ TX_CMD_START_381 = 0x0080
.equ TX_CMD_START_1021 = 0x0040
.equ TX_CMD_START_ALL = 0x00C0
.equ TX_CMD_FORCE = 0x0100
.equ TX_CMD_ONE_COLL = 0x0200
.equ TX_CMD_NO_CRC = 0x1000
.equ TX_CMD_NO_PAD = 0x2000
;
;Buffer Configuration Register
;
.equ BUF_CFG_SW_INT = 0x0040
.equ BUF_CFG_RDY4TX_IE = 0x0100
.equ BUF_CFG_TX_UNDR_IE = 0x0200
;
;
; Register file assignments
;
.def count=r14
.def lcdPos=r15
.def wL=r16
.def wH=r17
.def offsetL=r18
.def offsetH=r19
.def valueL=r20
.def valueH=r21
.def tempL=r22
.def tempH=r23
.def flags=r24
.def scratch=r25
.def lengthL=r26
.def lengthH=r27
.def chksumL=r0
.def chksumM=r1
.def chksumH=r2
;
; start of packet data in sram
;
.equ packet = 0x60
;
; Packet offset equates
;
;
; Packet header
;
.equ pktLenH = 0x00
.equ pktLenL = 0x01
.equ pktDest0H= 0x02
.equ pktDest0L= 0x03
.equ pktDest1H= 0x04
.equ pktDest1L= 0x05
.equ pktDest2H= 0x06
.equ pktDest2L= 0x07
.equ pktSrc0H = 0x08
.equ pktSrc0L = 0x09
.equ pktSrc1H = 0x0a
.equ pktSrc1L = 0x0b
.equ pktSrc2H = 0x0c
.equ pktSrc2L = 0x0d
.equ pktTypeH = 0x0e
.equ pktTypeL = 0x0f
;
; ARP
;
.equ ar_hwtype= 0x10 ;hardware type
.equ ar_prtype= 0x12 ;protocol type
.equ ar_hwlen = 0x14 ;hardware address length
.equ ar_prlen = 0x15 ;protocol address length
.equ ar_op = 0x16 ;ARP operation (1=request, 2=reply)
.equ ar_sha = 0x18 ;senders hardware address
.equ ar_spa = 0x1e ;senders IP address
.equ ar_tha = 0x22 ;target hardware address
.equ ar_tpa = 0x28 ;target IP address
;
; IP header
;
.equ ip_verlen= 0x10 ;IP version and header length(in longs)
.equ ip_tos = 0x11 ;IP type of service
.equ ip_len = 0x12 ;packet length (length-header_length)
.equ ip_id = 0x14 ;datagram id
.equ ip_fragoff= 0x16 ;fragment offset
.equ ip_ttl = 0x18 ;time to live (in gateway hops)
.equ ip_proto = 0x19 ;protocol (ICMP=1, TCP=6, EGP=8, UDP=17)
.equ ip_cksum = 0x1a ;header checksum
.equ ip_src = 0x1c ;IP address of source
.equ ip_dst = 0x20 ;IP addess of destination
.equ ip_data = 0x24
;
; IP value equates
;
.equ IPT_ICMP = 1 ;protocol type for ICMP packets
.equ IPT_TCP = 6 ;protocol type for TCP packets
.equ IPT_EGP = 8 ;protocol type for EGP packets
.equ IPT_UDP = 0x11 ;protocol type for UDP packets
;
; ICMP header
;
.equ ic_type = ip_data ;0=reply, 8=request, others=who-cares
.equ ic_code = ic_type+1 ;code
.equ ic_cksum = ic_code+1 ;checksum of header+data
.equ ic_id = ic_cksum+2 ;message id
.equ ic_seq = ic_id+2 ;sequence number
;
; UDP Header
;
.equ u_src = ip_data ;source udp port number
.equ u_dst = u_src+2 ;destination UDP port number
.equ u_len = u_dst+2 ;length of UDP header+data
.equ u_cksum = u_len+2 ;checksum (see note)
.equ u_data = u_cksum+2 ;start of data
;
; Note: checksum is calculated by taking the 16 bit sums of the ip_src, ip_dst,
; ip_proto, u_len, and the sum starting at u_src for a length of u_len
; yes, this means that u_len is taken twice! u_cksum is zero during the calc.
; The sum is then one's complemented. This is the checksum
;
;
start:
ldi wL,low(RAMEND)
out SPL,wL
ldi wL,high(RAMEND) ;setup the stack
out SPH,wL
ldi wL,$c0 ;Setup for external
out MCUCR,wL ; SRAM Enable and Wait State Enable
ldi wL,0b11110111 ;PORTE INTR signal input all others output
out DDRE,wL
sbi CSIG,IOR ;no read
sbi CSIG,IOW ;no write
sbi CSIG,CHIPSEL ;don't select chip
ser wL
out DDRB,wL ;PORTB (Crystal Address Bus) output
clr count ;packet counter
Dinput
ldi scratch,255 ;wait
rcall wait
rcall lcd_reset ;reset LCD
rcall VerChip ;make sure that the CS8900 is connected, Z set if true
ldi wL,'>' ;success indicator
breq VerOK
ldi wL,'<' ;failure indicator on LCD
VerOK: rcall lcd_write
rcall ResetChip ;reset CS8900
rcall InitChip ;initialize CS8900
;
; We already did this in VerChip but get the signature bytes for the CS8900 and display
; them on the LCD. Should be 3000 630E 0500
;
Dinput
ior portPtr+1 ;read PacketPage Ptr for high order byte
mov valueH,wL ;save high low
ior portPtr ;read PacketPage Ptr for high order byte
mov valueL,wL ;save high low
rcall outHL
ppRD ppEISA ;get the EISA number whoch should be 0x630E
rcall outHL
ppRD ppProdID ;get the Product ID which should be 000x xxxx 0000 0000
rcall outHL
clr flags ;Packet flags
loop:
sbis PINE,INTR ;wait for interrupt
rjmp loop
rcall ProcessISQ ;process the queue
sbrs flags,0 ;received frame flag
rjmp loop
cbr flags,1 ;clear the receive flag
;
; We're going to display on the LCD, t: CC LLLL FFFF
; Where t=r for recieved frame, a=arp request, p=ping request
; CC=count of frames received so far
; LLLL=length of this frame
; FFFF=frame type. For example 0800 for IP, 0806 for ARP
;
rcall lcd_clear
clr lcdPos
inc lcdPos ;start in second LCD position
ldi wL,':'
rcall lcd_write
mov wL,count
rcall toHexH
rcall lcd_write
mov wL,count ;display the count of received frames
rcall toHexL
rcall lcd_write
ldi wL,' '
rcall lcd_write
lds valueH,packet+pktLenH ;display the packet length
lds valueL,packet+pktLenL
rcall outHL
lds valueH,packet+pktTypeH ;and the packet type
lds valueL,packet+pktTypeL
rcall outHL
sbrc flags,1 ;bit set when valid arp
rjmp ArpRequest
sbrc flags,2 ;bit set when valid UDP Request on port 7
rjmp UDP7Request
sbrc flags,3 ;bit set when valid ICMP Ping request received
rjmp PingRequest
clr lcdPos
ldi wL,'r'
rcall lcd_write
rjmp loop
ArpRequest:
cbr flags,2 ;clear the valid arp request flag
clr lcdPos
ldi wL,'a'
rcall lcd_write
rcall WriteARP ;respond to the ARP request with our IP/MAC
rjmp loop
PingRequest:
cbr flags,8 ;clear the valid ICMP ping request flag
clr lcdPos
ldi wL,'p'
rcall lcd_write
rcall WritePing ;respond to the ping
rjmp loop
UDP7Request:
cbr flags,4 ;clear the valid UDP port 7 request flag
clr lcdPos
ldi wL,'u'
rcall lcd_write
rcall WriteUDP ;echo reply
rjmp loop
;
; Converts the valueH/valueL to hex and displays it on the LCD
;
outHL:
mov wL,valueH
rcall toHexH
rcall lcd_write
mov wL,valueH
rcall toHexL
rcall lcd_write
mov wL,valueL
rcall toHexH
rcall lcd_write
mov wL,valueL
rcall toHexL
rcall lcd_write
ldi wL,' '
rcall lcd_write
ret
toHexL:
andi wL,0x0f
ori wL,0x30
cpi wL,0x3a
brlo thlX
ldi wH,7
add wL,wH
thlX: ret
toHexH:
lsr wL
lsr wL
lsr wL
lsr wL
ori wL,0x30
cpi wL,0x3a
brlo thhX
ldi wH,7
add wL,wH
thhX: ret
;
; Send the reset sequence to the LCD's HD44780 controller.
;
lcd_reset:
ldi scratch,20 ;wait 20 milliseconds
rcall wait
ldi wL,$30 ;Spec said to send this init sequence
sts $8000,wL
ldi scratch,4
rcall wait ;Wait 4ms
ldi wL,$30 ;Spec said to send this init sequence
sts $8000,wL ;Send init sequence again
rcall delay100us ;Wait 100us
ldi wL,$30 ;Spec said to send this init sequence
sts $8000,wL ;and one last time
rcall delay100us ;Wait 100us
ldi wL,$3F ;Display off
sts $8000,wL
ldi scratch,4
rcall wait ;Wait 4ms
ldi wL,$0F ;Display on
sts $8000,wL
ldi scratch,4
rcall wait ;Wait 4ms
ldi wL,$06 ;Entry Mode Set
sts $8000,wL
ldi scratch,4
rcall wait ;Wait 4ms
rcall lcd_clear ;clear display
clr lcdPos ;position of character on LCD
ret
;
; Clear the LCD display
;
lcd_clear:
ldi wL,$01 ;Clear Display
sts $8000,wL
ldi scratch,4
rcall wait ;Wait 4ms
clr lcdPos ;position of character on LCD
ret
;
; Sends the character in r16 to the LCD. The register "lcdPos" is
; incremented to the next position. The register value is a modulous 8
; and the LCD is broken into two sections (as is typical for HD44780 based LCDs),
; position 0-7 on LCD1 and 0-7 on LCD2.
;
lcd_write:
mov r17,lcdPos
sbrs r17,3
rjmp lcd_1
andi r17,0x07
ori r17,0x40
rjmp lcd_2
lcd_1: andi r17,0x07
lcd_2: ori r17,0x80
sts $8000,r17
rcall delay40us
sts $C000,r16
rcall delay40us
inc lcdPos
ret
delay40us:
push wL
ldi wL,$40
loop3: dec wL
brne loop3
pop wL
ret
delay100us:
push wL
ldi wL,$88
loop4: dec wL
brne loop4
pop wL
ret
;
; wait for W milliseconds
;
;delay the given number of milliseconds using a software loop
; Enter: scratch = number of milliseconds to delay
; Exit: scratch,wL,wH = undefined
wait:
wait1: ldi wH,high((ClkFreq / 1000) / 4)
ldi wL,low((ClkFreq / 1000) / 4)
wait2: subi wL,1 ;(1)
sbci wH,0 ;(1)
brne wait2 ;(2)
dec scratch
brne wait1
ret
;************************************************************************
;* C S 8 9 0 0 D r i v e r F u n c t i o n s *
;************************************************************************
;
; WriteARP - Send a response ARP to the requestor
;
WriteARP:
ldi zL,low(packet)
ldi zH,high(packet) ;load the z reg with the packet address
clr wL
st z,wL
ldi wL,42 ;length of ARP response frame
std z+2,wL
; Target HW address MAC (6)
lds wL,packet+pktSrc0H
sts packet+ar_tha,wL
sts packet+pktDest0H,wL
lds wL,packet+pktSrc0L
sts packet+ar_tha+1,wL
sts packet+pktDest0L,wL
lds wL,packet+pktSrc1H
sts packet+ar_tha+2,wL
sts packet+pktDest1H,wL
lds wL,packet+pktSrc1L
sts packet+ar_tha+3,wL
sts packet+pktDest1L,wL
lds wL,packet+pktSrc2H
sts packet+ar_tha+4,wL
sts packet+pktDest2H,wL
lds wL,packet+pktSrc2L
sts packet+ar_tha+5,wL
sts packet+pktDest2L,wL
; Target IP (4)
lds wL,packet+ar_spa
sts packet+ar_tpa,wL
lds wL,packet+ar_spa+1
sts packet+ar_tpa+1,wL
lds wL,packet+ar_spa+2
sts packet+ar_tpa+2,wL
lds wL,packet+ar_spa+3
sts packet+ar_tpa+3,wL
; Senders IP (4)
ldi wL,IP1
sts packet+ar_spa,wL
ldi wL,IP2
sts packet+ar_spa+1,wL
ldi wL,IP3
sts packet+ar_spa+2,wL
ldi wL,IP4
sts packet+ar_spa+3,wL
; Src HW Address MAC (6)
ldi wL,MAC1
sts packet+ar_sha,wL
sts packet+pktSrc0H,wL
ldi wL,MAC2
sts packet+ar_sha+1,wL
sts packet+pktSrc0L,wL
ldi wL,MAC3
sts packet+ar_sha+2,wL
sts packet+pktSrc1H,wL
ldi wL,MAC4
sts packet+ar_sha+3,wL
sts packet+pktSrc1L,wL
ldi wL,MAC5
sts packet+ar_sha+4,wL
sts packet+pktSrc2H,wL
ldi wL,MAC6
sts packet+ar_sha+5,wL
sts packet+pktSrc2L,wL
; Packet type (2)
ldi wL,0x08
sts packet+pktTypeH,wL
ldi wL,0x06
sts packet+pktTypeL,wL
; Hardware type (2)
ldi wL,0x00
sts packet+ar_hwtype,wL
ldi wL,0x01
sts packet+ar_hwtype+1,wL
; Protocol type (2)
ldi wL,0x08
sts packet+ar_prtype,wL
ldi wL,0x00
sts packet+ar_prtype+1,wL
; Hardware and protocol address lengths (2)
ldi wL,0x06
sts packet+ar_hwlen,wL
ldi wL,0x04
sts packet+ar_prlen,wL
; Operation (response) (2)
ldi wL,0x00
sts packet+ar_op,wL
ldi wL,0x02
sts packet+ar_op+1,wL
rcall WritePacket
ret
;
; WriteUDP - Send a response to the port 7 UDP echo request
;
WriteUDP:
clr wL
sts packet+ip_cksum,wL ;clear
sts packet+ip_cksum+1,wL ; checksum
lds wL,packet+ip_src ;move
sts packet+ip_dst,wL ; ip
lds wL,packet+ip_src+1 ; of
sts packet+ip_dst+1,wL ; source
lds wL,packet+ip_src+2 ; to
sts packet+ip_dst+2,wL ; dest
lds wL,packet+ip_src+3
sts packet+ip_dst+3,wL
ldi wL,IP1 ;move
sts packet+ip_src,wL ; our
ldi wL,IP2 ; ip
sts packet+ip_src+1,wL ; address
ldi wL,IP3 ; to
sts packet+ip_src+2,wL ; source
ldi wL,IP4
sts packet+ip_src+3,wL
lds wL,packet+pktSrc0H ;move
sts packet+pktDest0H,wL ; mac src to dest
lds wL,packet+pktSrc0L
sts packet+pktDest0L,wL
lds wL,packet+pktSrc1H ;move
sts packet+pktDest1H,wL ; mac src to dest
lds wL,packet+pktSrc1L
sts packet+pktDest1L,wL
lds wL,packet+pktSrc2H ;move
sts packet+pktDest2H,wL ; mac src to dest
lds wL,packet+pktSrc2L
sts packet+pktDest2L,wL
ldi wL,MAC1 ;move
sts packet+pktSrc0H,wL ; our
ldi wL,MAC2 ; MAC
sts packet+pktSrc0L,wL ; address
ldi wL,MAC3 ; to
sts packet+pktSrc1H,wL ; source
ldi wL,MAC4
sts packet+pktSrc1L,wL
ldi wL,MAC5
sts packet+pktSrc2H,wL
ldi wL,MAC6
sts packet+pktSrc2L,wL
ldi lengthL,20 ;length of IP header
clr lengthH
ldi zL,low(packet+ip_verlen)
ldi zH,high(packet+ip_verlen)
rcall cksum
sts packet+ip_cksum,valueH ;save new IP checksum
sts packet+ip_cksum+1,valueL
lds wH,packet+u_src ;get src port
lds wL,packet+u_dst ;put dest port
sts packet+u_src,wL ;in source
sts packet+u_dst,wH ;put source port in dest
lds wH,packet+u_src+1 ;get src port
lds wL,packet+u_dst+1 ;put dest port
sts packet+u_src+1,wL ;in source
sts packet+u_dst+1,wH ;put source port in dest
clr wL
sts packet+u_cksum,wL ;clear UDP checksum for new calc
sts packet+u_cksum+1,wL ;clear byte two
ldi zl,low(packet+ip_src)
ldi zh,high(packet+ip_src)
lds lengthH,packet+ip_len
lds lengthL,packet+ip_len+1
ldi wL,20-8 ;ip_len-20+8 (20 is the length of an IP header.
clr wH ; 8 is the length of the two IP fields (ip_src/ip_dst)
sub lengthL,wL
sbc lengthH,wH
rcall cksum
clr wH
lds wL,packet+ip_proto ;get protocol (1 byte)
sub valueL,wL ;add to accum
sbc valueH,wH
lds wH,packet+u_len ;add in UDP len
lds wL,packet+u_len+1
sub valueL,wL
sbc valueH,wH
sts packet+u_cksum,valueH
sts packet+u_cksum+1,valueL
rcall WritePacket
ret
;
; WritePing - Send a ICMP Ping response
;
WritePing:
;we might want to check in the future for IA or broadcast requests
clr wL
sts packet+ip_cksum,wL
sts packet+ip_cksum+1,wL ;clear checksum
lds wL,packet+ip_src ;move
sts packet+ip_dst,wL ; ip
lds wL,packet+ip_src+1 ; of
sts packet+ip_dst+1,wL ; source
lds wL,packet+ip_src+2 ; to
sts packet+ip_dst+2,wL ; dest
lds wL,packet+ip_src+3
sts packet+ip_dst+3,wL
ldi wL,IP1 ;move
sts packet+ip_src,wL ; our
ldi wL,IP2 ; ip
sts packet+ip_src+1,wL ; address
ldi wL,IP3 ; to
sts packet+ip_src+2,wL ; source
ldi wL,IP4
sts packet+ip_src+3,wL
clr wL
sts packet+ic_cksum,wL ;clear ICMP
sts packet+ic_cksum+1,wL ; checksum
sts packet+ic_type,wL ;make type a reply
sts packet+ic_code,wL ;clear code
lds wL,packet+pktSrc0H ;move
sts packet+pktDest0H,wL ; mac src to dest
lds wL,packet+pktSrc0L
sts packet+pktDest0L,wL
lds wL,packet+pktSrc1H ;move
sts packet+pktDest1H,wL ; mac src to dest
lds wL,packet+pktSrc1L
sts packet+pktDest1L,wL
lds wL,packet+pktSrc2H ;move
sts packet+pktDest2H,wL ; mac src to dest
lds wL,packet+pktSrc2L
sts packet+pktDest2L,wL
ldi wL,MAC1 ;move
sts packet+pktSrc0H,wL ; our
ldi wL,MAC2 ; MAC
sts packet+pktSrc0L,wL ; address
ldi wL,MAC3 ; to
sts packet+pktSrc1H,wL ; source
ldi wL,MAC4
sts packet+pktSrc1L,wL
ldi wL,MAC5
sts packet+pktSrc2H,wL
ldi wL,MAC6
sts packet+pktSrc2L,wL
ldi lengthL,20 ;set length of
clr lengthH ; checksum calculation = length of IP header
ldi zL,low(packet+ip_verlen);displacement to start of IP header
ldi zH,high(packet+ip_verlen)
rcall cksum ;calculate the checksum
sts packet+ip_cksum,valueH ;set new checksum
sts packet+ip_cksum+1,valueL
lds lengthH,packet+ip_len ;get length high
lds lengthL,packet+ip_len+1 ;calc length of ICMP header+data
subi lengthL,20 ;-length of IP header
sbci lengthH,0
ldi zL,low(packet+ic_type) ;start of ICMP header
ldi zH,high(packet+ic_type) ;start of ICMP header
rcall cksum
sts packet+ic_cksum,valueH ;set new checksum
sts packet+ic_cksum+1,valueL
rcall WritePacket
ICMPDone:
ret
;----------------------------------------------------------------------
; Receive Event
; Input with RxEvent in valueH
;
ReceiveEvent:
;
; It's important to read the status and length high-order
; byte first.
;
Dinput ;make data bus input
ior portRxTxData+1 ;read and discard status
ior portRxTxData ;read and discard status
ldi yL,low(packet) ;set indirect
ldi yH,high(packet)
ior portRxTxData+1 ;get length high
st y+,wL ;save in header
mov lengthH,wL ; and in lengthH
ior portRxTxData ;get length low
st y+,wL ;save in header area
mov lengthL,wL ; and in lengthL
sbrc lengthL,0 ;odd length?
adiw lengthL,1 ;yes, increment lengthL/lengthH by 1
lsr lengthH ;divide high by 2 and set carry appropriately
ror lengthL ;rotate carry into lower and divide by 2
ReadFrame:
ior portRxTxData ;read from CS8900
st y+,wL ;write it to sram
ior portRxTxData+1 ;read from CS8900
st y+,wL ;write it to sram
sbiw lengthL,1 ;decrement lengthL/lengthH
brpl ReadFrame
inc count ;increment packet counter
sbr flags,1 ;flag frame read
lds wL,packet+pktTypeH ;check if packet type
cpi wL,0x08 ; is 0x0806 (ARP)
brne ChkIP
lds wL,packet+pktTypeL
cpi wL,0x06
breq DoArp
ChkIP:
lds wL,packet+pktTypeH ;check if packet type
cpi wL,0x08 ; is 0x0806 (ARP)
brne REReturn
lds wL,packet+pktTypeL
cpi wL,0x00
breq DoIP
REReturn:
ret
;
; It's an arp request, Could be a request or a response.
; ARP packets are small so the whole thing is always in
; the register file.
;
DoArp:
lds wL,packet+ar_hwtype+1 ;make sure it's 1
cpi wL,0x01
brne DoArpX
lds wL,packet+ar_prtype ;compare to high
cpi wL,0x08 ;make sure it's 0x0800
brne DoArpX
lds wL,packet+ar_prtype+1 ;compare to high
cpi wL,0x00 ;make sure it's 0x0800
brne DoArpX
lds wL,packet+ar_hwlen ;make sure it's 6 for hwlen
cpi wL,0x06 ;compare to high
brne DoArpX
lds wL,packet+ar_prlen ;make sure it's 4 for protocol length
cpi wL,0x04 ;compare to low
brne DoArpX
lds wL,packet+ar_op+1 ;make sure it's 0x0001 for arp request
cpi wL,0x01 ;compare to low
brne DoArpX
lds wL,packet+ar_tpa
cpi wL,IP1
brne DoArpX
lds wL,packet+ar_tpa+1
cpi wL,IP2
brne DoArpX
lds wL,packet+ar_tpa+2
cpi wL,IP3
brne DoArpX
lds wL,packet+ar_tpa+3
cpi wL,IP4
brne DoArpX
; If we got to here, then we have a valid ARP request for our IP address
sbr flags,2 ;set ARP flag
DoArpX:
ret
;
; Process IP packet for ICMP or UDP requests
;
DoIP:
lds wL,packet+ip_proto ;compare to this packet's proto
cpi wL,IPT_ICMP ; to ICMP?
breq DoICMP ;go process the ICMP packet
cpi wL,IPT_UDP ; to UDP?
breq DoUDP ;go process the UDP packet
ret ;just return, we dont process this type
;
; Process UDP Port 7 echo requests
;
DoUDP:
lds wL,packet+u_dst+1 ;compare to UDP packet
cpi wL,7 ;port we're listing for requests on
brne DoUDPDone
sbr flags,4 ;we have a request for our port 7
DoUDPDone:
ret
;
; Process ICMP (ping) requests
;
DoICMP:
sbr flags,8 ;set flag to indicate ICMP ping request
ret
;
; Calc checksum. Reads packet at offset zL/zH for
; lengthH/lengthL bytes and calculates the checksum
; in valueH/valueL.
;
cksum: clr chksumL ;we do the arithmetic
clr chksumM ; using a 24
clr chksumH ; bit area
sbrs lengthL,0 ;odd length?
rjmp cksumC
mov yL,zL
mov yH,zH
add yL,lengthL
adc yH,lengthH
clr wL
st y,wL ;clear byte after last
adiw lengthL,1
cksumC: lsr lengthH
ror lengthL
cksuml: ld wH,z+ ;get high byte of 16-bit word
ld wL,z+
add chksumL,wL ;add to accum
brcc noLcarry
ldi wL,1
add chksumM,wL
brcc noLcarry
add chksumH,wL
noLcarry:
add chksumM,wH ;add in the high byte
brcc noHcarry
inc chksumH
noHcarry:
subi lengthL,1
sbci lengthH,0
clr wL
cpi lengthL,0
cpc lengthH,wL
breq CkDone
brpl cksuml
CkDone: add chksumL,chksumH ;add in the third byte of 24 bit area
brcc CkDone1
inc chksumM
CkDone1:mov valueL,chksumL
com valueL
mov valueH,chksumM
com valueH
ret
;
; Transmit Event
;
TransmitEvent:
ret
;
; Processes the pending interrupt requests from the Interrupt Status Queue
;
ProcessISQ:
; Read the ISQ
NextEvt:
Dinput
ior portISQ ;read interrupt status queue
mov valueL,wL ;save value low
ior portISQ+1 ;read interrupt status queue high
mov valueH,wL ;save value high
tst valueL ;get val
breq EvtRet
cpi valueL,REG_NUM_RX_EVENT
breq evtRecv
cpi valueL,REG_NUM_TX_EVENT
breq evtTran ;Ingore BufEvent, RxMiss, and TxCol
rjmp NextEvt
evtRecv:
rcall ReceiveEvent
rjmp NextEvt
evtTran:
rcall TransmitEvent
rjmp NextEvt
EvtRet: ret
;
; Initializes the chip
;
InitChip:
ppWR ppLineCtl,LINE_CTL_10BASET ;set to 10BaseT
ppWR ppTestCtl,TEST_CTL_FDX ;set to full duplex
ppWR ppRxCfg,RX_CFG_RX_OK_IE ;enable RxOK interrupt
ppWR ppRxCtl,(RX_CTL_RX_OK_A|RX_CTL_IND_A|RX_CTL_BCAST_A)
ppWR ppTxCfg,TX_CFG_ALL_IE
;
; Important: The IA needs to be byte revered IA=aa:bb:cc:dd:ee:ff
;
ppWR ppIndAddr,(MAC2<<8|MAC1) ;0xbbaa Write
ppWR ppIndAddr+2,(MAC4<<8|MAC3) ;0xddcc out
ppWR ppIndAddr+4,(MAC6<<8|MAC5) ;0xffee 48 bit IA
ppWR ppIntNum,0x00 ;INT is on INTRQ0
ppRD ppBusCtl ;get Bus Control
sbr valueH,0x80 ;enable irq
rcall WritePP
ppRD ppLineCtl ;get Line Control
sbr valueL,0xc0 ;set SerRxOn and SerTxOn
rcall WritePP
ret
;
; Resets the CS8900
;
ResetChip:
ppWR ppSelfCtl,SELF_CTL_RESET ;issue a reset to the chip
ResetWait:
ldi scratch,1 ;wait for
rcall wait ;a millisecond
ppRD ppSelfCtl ;get the Self Control status
sbrc valueL,6 ;see it bit 6 (RESET) was cleared
rjmp ResetWait ;no, then still in reset, wait some more
ppRD ppSelfSt ;get self status
sbrs valueL,7 ;bit 7 is INITD
rjmp ResetWait ; when set, initialization of the CS8900 is done
ret
;
; Verifies that the CS8900 is attached and sets the STATUS,Z flag to
; indicate success or not set if failure.
;
VerChip:
Dinput ;make the data bus input
; first, get the signature at portPtr which should be 0x3000
ior portPtr ;read PacketPage Ptr
mov valueL,wL ;save value low
ior portPtr+1 ;read PacketPage Ptr for high order byte
mov valueH,wL ;save high low
tst valueL ;should be 0 (i.e. 0x3000 low is 0x00)
brne VerBad
cpi valueH,0x30 ;high part of 0x3000
brne VerBad
ppRD ppEISA ;get the EISA number whoch should be 0x630E
cpi valueL,0x0e
brne VerBad
cpi valueH,0x63
brne VerBad
ppRD ppProdID ;get the Product ID which should be 000x xxxx 0000 0000
;where x xxxx = 0 0011 for rev E and 0 0101 for rev F
tst valueL ;set return status
VerBad: ret ;return with Z indicating success or not.
;
; Writes the packet for lengthL/lengthH
;
WritePacket:
Doutput
ldi wL,TX_CMD_START_ALL
iow portTxCmd
clr wL
iow portTxCmd+1
lds wL,packet+pktLenL ;length
iow portTxLength ; of packet
lds wL,packet+pktLenH ; to send
iow portTxLength+1
WPGetStat:
ppRD ppBusSt ;get BusStatus
sbrs valueH,0 ;is BUS_ST_RDY4TXNOW (ready for transmit)
rjmp WPGetStat ;no, wait for it
Doutput
ldi zL,low(packet+pktDest0H)
ldi zH,high(packet+pktDest0H)
lds lengthH,packet+pktLenH
lds lengthL,packet+pktLenL
sbrs lengthL,0 ;odd length?
rjmp PacketEven ;nope, continue
adiw lengthL,1 ;increment length
PacketEven:
lsr lengthH ;divide high by 2 and set carry appropriately
ror lengthL ;rotate carry into lower and divide by 2
PacketWriteLoop:
ld wL,z+ ;get next byte
iow portRxTxData
ld wL,z+ ;get next byte
iow portRxTxData+1
sbiw lengthL,1 ;decrement lengthL/lengthH
brpl PacketWriteLoop
ret
;
; Writes the value at valueH/valueL to the PagePacket register who's
; address is in offsetH/offsetL
;
WritePP:
Doutput ;make the data bus output
mov wL,offsetL ;get the low order byte
iow portPtr ;write to PacketPage Ptr
mov wL,offsetH ;get the high order byte
iow portPtr+1 ;write to PacketPage ptr
mov wL,valueL ;get low order value to write
iow portData ;write to PacketPage data
mov wL,valueH ;get high order data
iow portData+1 ;write to PacketPage data
ret
;
; Reads the PagePacket at offsetH/offsetL and returns the result in
; valueH/valueL.
;
ReadPP:
Doutput ;make the data bus output
mov wL,offsetL ;get the offset to read
iow portPtr ;write to PacketPage Ptr
mov wL,offsetH ;get the high order offset
iow portPtr+1 ;PagePacket Pointer Register high byte
Dinput ;make the data bus input
ior portData ;read the PacketPage data
mov valueL,wL ;save value low
ior portData+1 ;read the high order byte
mov valueH,wL ;save the high order byte value
ret
ioRead:
out CAB,wL
cbi CSIG,CHIPSEL
cbi CSIG,IOR
nop
nop
in wL,PIND
sbi CSIG,IOR
sbi CSIG,CHIPSEL
ret
;
ioWrite:
cbi CSIG,CHIPSEL
cbi CSIG,IOW
nop
sbi CSIG,IOW
sbi CSIG,CHIPSEL
ret
file: /Techref/atmel/avr/tcpip/atmel-crystal.asm, 43KB, , updated: 1999/6/4 13:02, local time: 2025/5/2 20:29,
|
| ©2025 These pages are served without commercial sponsorship. (No popup ads, etc...).Bandwidth abuse increases hosting cost forcing sponsorship or shutdown. This server aggressively defends against automated copying for any reason including offline viewing, duplication, etc... Please respect this requirement and DO NOT RIP THIS SITE. Questions? <A HREF="http://www.linistepper.com/Techref/atmel/avr/tcpip/atmel-crystal.asm"> atmel avr tcpip atmel-crystal</A> |
Did you find what you needed?
|