| |
ttydio.asm
;+
; **-udp-udp receive handler.
;
; return with ret.
;-
#define UDP_FUNC UDP_DATA
import_udp:
rcall pcode
#if defined(SHOW_UDP_REQUESTS)
pprintr "UDP src",IP_SRCADDR,4
pprintr ":",UDP_DP,2
#endif
pr2s buf,UDP_DP,2 ; get destination port
pcmpwi buf,BSWAP(UDP_CMD_PORT) ; check if it matches
pjumpne udp_bail
pr2s buf,IP_SRCADDR,4
pr2s buf+10,UDP_FUNC,1 ; get function code byte
pandwi buf+10,0xff
pjumpeq login_check
pcmpn buf,client_ip,4
pjumpne nak_request ; sorry - you're not logged in
pjump check_port
login_check:
pandwi client_ip,0xffff ; check client ip
pjumpeq go_func ; anything is OK if nobody's logged in
pcmpn buf,client_ip,4 ; check against client
pjumpne nak_request ; sorry
check_port:
#if defined(CHECK_UDP_REQUESTOR_PORT)
pr2s buf,UDP_SP,2 ; get requestor port
pcmpwi buf,[client_port] ; check port
pjumpne nak_request ; sorry
#endif
go_func:
asm
lds r20,buf+10
movwi z,udp_functab
andi r20,7
add zl,r20
clr r20
adc zh,r20 ; get jump address
icall
ret
udp_functab:
rjmp loginout ; 00 - loginout
rjmp read_timer ; 01 - read timer info
rjmp set_clock_div ; 02 - set clock divisor
ret ; 03 - unused
ret ; 04 - unused
ret ; 05 - memory packet test
rjmp async_poll ; 06 - async poller
rjmp udp_output_test ; 07 - output tester
async_poll:
rcall pcode
pmovbi async_poll_active,1
pjump ack_request
do_async_poll:
pser_getc buf ; get another char
pjumpeq do_pret ; none left
pcall start_udp_output ; condition output
pputc [byte buf] ; put first byte
next_async:
pser_getc buf ; get another char
pjumpeq async_done ; none left
pputc [byte buf] ; put char
pjump next_async ; go do next one
async_done:
pcall udp_flush_and_send ; transmit the packet
do_pret:
pret
;+
; **-udp_output_test-output testor.
;
; inputs:
; UDP_DATA+1 = packet count (word)
; UDP_DATA+3 = packet length (word)
;
; outputs:
; none, except the desire to blast packets is recorded, and packet
; blasting begins when the next trip through the main loop happens.
;-
udp_output_test:
rcall pcode
pr2s udp_pkt_count,UDP_DATA+1,2
pr2s udp_pkt_len,UDP_DATA+1+2,2
pjump udp_bail
udp_loop_processing:
rcall pcode
pmovb buf,async_poll_active
pandwi buf,0xff
pjumpeq udp_loop1
pcall do_async_poll
udp_loop1:
pandwi udp_pkt_count,0xffff
pjumpeq udp_bail
pmovwi MEM_UDP_LEN,[udp_pkt_len]
pf2x UDP_DATA,movedata,[udp_pkt_len]
pcall mem_udp_send
psubwi udp_pkt_count,1
pjumpne udp_bail
pjump ack_request ; not right - uses reply and there's no req!
;+
; **-udp_flush_and_send-flush and send memory packet.
;
; inputs:
; boardaddr = current board address (word)
; xmit_page = current transmit page (byte)
;
; outputs:
; packet is sent to original client
;-
udp_flush_and_send:
bflush ; flush anything remaining
pmovbi putc_b,0 ; regular putchar now
pmovwi buf,[boardaddr]
pmovb buf+3,xmit_page
pmovbi buf+2,UDP_DATA
psubwi buf,[buf+2] ; length of data
pi2x UDP_LEN,[buf] ; store length
pjump udp_send_client ; send it
;+
; **-loginout-log in or out.
;
; inputs:
; UDP_DATA+1 = 0-logout, else login (byte)
;
; outputs:
; reply packet sent
;-
loginout:
rcall pcode
pr2s buf,UDP_DATA+1,1 ; get logon/logoff function code
pandwi buf,0xff ; check it
pjumpeq log_out ; logging out
pcall set_client
ack_request:
pi2x UDP_DATA,1 ; good ack
pjump reply_request
log_out:
pclrw client_ip
pjump ack_request
;+
; **-set_client-remember requestor as client for future autonomous sends.
;
; inputs:
; current receive packet contains client info
;
; outputs:
; appropriate info copied to memory packet buffer.
;
; caveats:
; called via pcall/pret
;-
set_client:
pr2s client_ip,IP_SRCADDR,4 ; remember client's IP
pr2s client_port,UDP_SP,2 ; and port number
pmemcpy MEM_ETH_DEST,ETH_SRC,6 ; and ether
pmemcpy MEM_IP_SRCADDR,my_ip,4 ; source ip == me
pmovwi MEM_UDP_SP,BSWAP(UDP_CMD_PORT) ; and port
pmemcpy MEM_ETH_SRC,my_ether,6 ; and ether
pmovwi MEM_ETH_PT,0x0008 ; set PT=IP
pmovwi MEM_IP_HVTOS,0x0045 ; 4500
pmovwi MEM_IP_TTLP,0x1101 ; UDP proto and TTL=1
pret
;+
; **-start_udp_output-start output of UDP packet via pputc/putchar.
;
; inputs:
; none
;
; outputs:
; boardaddr/boardlen/putc_b set appropriately.
;-
start_udp_output:
pmovb boardaddr+1,xmit_page ; get transmit page
pmovbi boardaddr,UDP_DATA ; set offset
pmovbi boardlen,0 ; nothing in buffer
pmovbi putc_b,1 ; set output for board
pret
;+
; **-nak_request-blow him off!
;-
nak_request:
pi2x UDP_DATA,0
reply_request:
ps2x UDP_DATA+1,client_ip,4
pi2x UDP_LEN,5
pcall udp_reply
asm
ret
;+
; 00
;-
read_timer:
rcall pcode
send_timer_info:
;
; this needs work because the timer is being written at interrupt level
; and there needs to be an interlock. alternative is to read it until two
; successive reads match.
;
#define TI_TIMER UDP_DATA
#define TI_LOOPS TI_TIMER+4
#define TI_CLOCKDIV TI_LOOPS+4
#define TI_ARPREQ TI_CLOCKDIV+1
#define TI_LEN TI_ARPREQ+2-TI_TIMER
ps2x TI_TIMER,timer,4 ; store timer
ps2x TI_LOOPS,loop_count,4 ; main loop count
ps2x TI_CLOCKDIV,clock_div,1 ; and divisor
ps2x TI_ARPREQ,arp_requests,2 ; # of arp requests
pi2x UDP_LEN,TI_LEN
pcall udp_reply
udp_bail:
asm
ret
;+
; **-udp_send_client-send UDP to client.
;
; inputs:
; UDP_DATA, UDP_LEN valid
;-
udp_send_client:
pi2x UDP_DP,[client_port]
pi2x UDP_SP,BSWAP(UDP_CMD_PORT) ; set source port
ps2x IP_DSTADDR,client_ip,4 ; set dest ip
ps2x IP_SRCADDR,my_ip,4 ; source ip
pjump udp_send
;+
; **-movedata-move data to packet.
;
; inputs:
; none
;
; outputs:
; data moved
;
; notes:
; demonstrates how to use pf2x with initial setup processing vs.
; "during the loop" processing.
;-
movedata:
movwi z,movedata_next
clrw y
clrw x
movedata_next:
mov i0,yl
mov i1,yh ; i0/i1 = next word of data
f2x_checksum y,r10 ; accumulate checksum - r10 destroyed
incw y ; increment the "data"
ret
;+
; 01 XX
;
; where XX = new clock divisor.
;-
set_clock_div:
rcall pcode
pr2s clock_div,UDP_DATA+1,1 ; get new divisor
pjump send_timer_info
;+
; **-timer0ovf_isr-timer 0 overflow ISR.
;-
timer0ovf_isr:
push r16
push r17
in r17,sreg
push r17
lds r16,clock_div
out tcnt0,r16
pushw y
movwi y,timer
ldi r17,4 ; width of timer in bytes
rcall incn
popw y
pop r17
out sreg,r17
pop r17
pop r16
reti
;+
; **-incn-increment N-byte counter.
;
; inputs:
; y -> counter
; r17 = width in bytes
;-
incn:
push r0
clr r0
sec
incn_next:
ld r16,y
adc r16,r0
st y+,r16
brcc incn_done
dec r17
brne incn_next
incn_done:
pop r0
ret
;+
; **-zeron-zero N bytes.
;
; inputs:
; y -> bytes
; r18 = count (word)
;-
zeron:
clr r0
znn:
st y+,r0
dec r18l
brne znn
dec r18h
brpl znn
ret
;+
; **-udp_send-send a UDP datagram.
;
; inputs:
; transmit buffer:
; UDP_DATA = user data to be sent
; UDP_LEN = native byte order length of data to send
;-
udp_reply:
ps2x IP_SRCADDR,my_ip,4 ; set source ip
pr2x IP_DSTADDR,IP_SRCADDR,4 ; set requestor IP as dest
pr2x UDP_DP,UDP_SP,2 ; swap source/destination ports
pr2x UDP_SP,UDP_DP,2
udp_send:
px2s buf,UDP_LEN,2
paddwi buf,UDP_HEADER_LEN ; total length
pi2x UDP_LEN,[swap buf] ; write swapped to UDP_LEN
paddwi buf,IP_HEADER_LEN
pi2x IP_LEN,[swap buf] ; write swapped to IP_LEN
;
; build packet and send.
;
; this is bogus - you have to double-pump the TTLP values. !!!needs work!-SDF
pi2x IP_TTLP,0x1101 ; TTL=01, proto=UDP
pcall ip_header_1
pcall udp_checksum
px2s buf,IP_LEN,2 ; read back the length
pmovwi buf,[swap buf] ; swap bytes
paddwi buf,6+6+2 ; compute length with ether header
xmit_frame [buf] ; out she goes
pret
;+
; **-mem_udp_send-send a UDP datagram from ram.
;
; inputs:
; transmit buffer:
; MEM_UDP_DATA = user data to be sent
; MEM_UDP_LEN = native byte order length of data to send
;
; checksum algorithm:
;
; ip_chksum = 0 ;
; ip_chksum = ~checksum(IPH,IPHLEN)
; udp_chksum = 0
; ph.src = ip.src
; ph.dst = ip.dst
; ph.mbzprot = 0|(ip.prot<<8)
; ph.len = udp_len (UDP data only, not header)
; ph_chksum = checksum(UDP_HDR,UDP_LEN+UDP_HEADER_LEN)
; udp_chksum = ~checksum(PH_HDR,PH_HEADER_LEN)
;-
#define PH_HEADER rcv_hdr+en_rbuf_nhdr
#define PH_SRCADDR PH_HEADER+0
#define PH_DSTADDR PH_HEADER+4
#define PH_MBZPROT PH_HEADER+8
#define PH_LEN PH_HEADER+10
#define PH_CHKSUM PH_HEADER+12
#define PH_HEADER_LEN 14
#define MOVW(x,y) pmovwi x,[y]
#define UDP_CHECKSUM_DONE
mem_udp_send:
#if defined(UDP_MEM_SEND_DEBUG)
pprintv " MVCHK=",[chkacc]
pclrw chkacc
pmem_chksum MEM_UDP_DATA,[MEM_UDP_LEN]
pprintv " UDPCHK=",[chkacc]
#endif
;
; compute UDP length and store in UDP_LEN field and PH_LEN field.
;
MOVW(buf,MEM_UDP_LEN) ; get length (native order)
paddwi buf,UDP_HEADER_LEN ; total length
MOVW(MEM_UDP_LEN,swap buf) ; set UDP length
;
; checksum UDP data, and store checksum (uncomplemented) in pseudoheader.
;
pclrw MEM_UDP_CHKSUM ; zero UDP checksum
#if defined(UDP_CHECKSUM_DONE)
pmem_chksum MEM_UDP_HEADER,UDP_HEADER_LEN
#else
pclrw chkacc ; reset accumulator
pmem_chksum MEM_UDP_HEADER,[buf] ; compute UDP checksum
#endif
MOVW(PH_CHKSUM,chkacc) ; store checksum in pseudoheader
paddwi buf,IP_HEADER_LEN
MOVW(MEM_IP_LEN,swap buf) ; set IP length
;
; the IP header should be ready, zero its checksum, checksum it, and
; store complemented checksum back in header.
;
pclrw chkacc
pclrw MEM_IP_CHKSUM ; zero IP header checksum
pmem_chksum MEM_IPH,IP_HEADER_LEN ; checksum IP header
pxorwi chkacc,-1 ; complement the ip checksum
#if defined(LOG_MEM_CHKSUM)
pprintv "IPCK ",[chkacc]
#endif
MOVW(MEM_IP_CHKSUM,chkacc) ; store in IP header
;
; finally, checksum the pseudoheader and store complemented checksum
; in UDP header.
;
pmemcpy PH_SRCADDR,MEM_IP_SRCADDR,8 ; source/dest IP addrs
pmovwi PH_MBZPROT,0x1100 ; UDP proto in PH
MOVW(PH_LEN,MEM_UDP_LEN) ; store net order length in ph
pclrw chkacc
pmem_chksum PH_HEADER,PH_HEADER_LEN ; checksum pseudoheader
pxorwi chkacc,-1 ; complement
MOVW(MEM_UDP_CHKSUM,chkacc) ; store in UDP header checksum
#if defined(LOG_MEM_CHKSUM)
pprintv "PHCK ",[chkacc]
#endif
;
; compute total packet size and send.
;
MOVW(buf,swap MEM_IP_LEN) ; ip length total
paddwi buf,6+6+2 ; compute length with ether header
#if defined(UDP_CHECKSUM_DONE)
;
; if the checksum has already been computed, it also means the packet
; data is in the frame buffer, so just load the headers.
;
ps2x 0,MEM_ETH_DEST,6+6+2+IP_HEADER_LEN+UDP_HEADER_LEN
#else
;
; load everything.
;
ps2x 0,MEM_ETH_DEST,[buf] ; copy packet to board
#endif
xmit_frame [buf] ; out she goes
#if defined(LOG_MEM_CHKSUM)
pprintv "PKLEN ",[buf]
#endif
pret
Back
|
|
|