From 7399a60725efd7b66abbe6551bf87079ef0bc8de Mon Sep 17 00:00:00 2001 From: Oliver Schmidt Date: Thu, 27 Feb 2014 22:00:07 +0100 Subject: [PATCH] Added W5100 UDP driver. This file isn't technically related to ip65. It uses the W5100 IP stack to implement UDP frame RX/TX. The code heavily optimized for size (in contrast to speed). --- supplement/w5100_udp.s | 379 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 379 insertions(+) create mode 100644 supplement/w5100_udp.s diff --git a/supplement/w5100_udp.s b/supplement/w5100_udp.s new file mode 100644 index 0000000..e7917de --- /dev/null +++ b/supplement/w5100_udp.s @@ -0,0 +1,379 @@ +.feature c_comments + +/****************************************************************************** + +Copyright (c) 2014, Oliver Schmidt +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL OLIVER SCHMIDT BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************/ + +ptr := $06 ; 2 byte pointer value +tmp := $08 ; 1 byte temporary value +bas := $09 ; 1 byte socket 1 Base Address (hibyte) +sha := $19 ; 2 byte physical addr shadow ($F000-$FFFF) +len := $1B ; 2 byte frame length +adv := $1D ; 2 byte pointer register advancement + +mode := $C0C4 +addr := $C0C5 +data := $C0C7 + +.export init +.export recv_init, recv_byte, recv_done +.export send_init, send_byte, send_done + +;------------------------------------------------------------------------------ + +init: + ; Set ip_parms pointer + sta ptr + stx ptr+1 + + ; S/W Reset + lda #$80 + sta mode +: lda mode + bmi :- + + ; Indirect Bus I/F mode, Address Auto-Increment + lda #$03 + sta mode + + ; Gateway IP Address Register: IP address of router on local network + ldx #$00 ; Hibyte + ldy #$01 ; Lobyte + jsr set_addr + ldy #3*4 ; ip_parms::cfg_gateway + jsr set_ipv4value + + ; Subnet Mask Register: Netmask of local network + ; -> addr is already set + ldy #2*4 ; ip_parms::cfg_netmask + jsr set_ipv4value + + ; Source Hardware Address Register: MAC Address + ; -> addr is already set + ldx #$00 +: lda mac,x + sta data + inx + cpx #$06 + bcc :- + + ; Source IP Address Register: IP address of local machine + ; -> addr is already set + ldy #1*4 ; ip_parms::cfg_ip + jsr set_ipv4value + + ; RX Memory Size Register: Assign 4KB each to sockets 0 and 1 + ldx #$00 ; Hibyte + ldy #$1A ; Lobyte + jsr set_addr + lda #$0A + sta data + + ; TX Memory Size Register: Assign 4KB each to sockets 0 and 1 + ; -> addr is already set + ; -> A is still $0A + sta data + + ; Socket 1 Destination IP Address Register: Destination IP address + ; This has to be the last call to set_ipv4value because it writes + ; as a side effect to 'hdr' and it is the destination IP address + ; that has to be present in 'hdr' after initialization + ldy #$0C + jsr set_addrsocket1 + ldy #0*4 ; ip_parms::serverip + jsr set_ipv4value + + ; Socket 1 Destination Port Register: 6502 + ; -> addr is already set + jsr set_data6502 + + ; Socket 1 Source Port Register: 6502 + ldy #$04 + jsr set_addrsocket1 + jsr set_data6502 + + ; Socket 1 Mode Register: UDP + ldy #$00 + jsr set_addrsocket1 + lda #$02 + sta data + + ; Socket 1 Command Register: OPEN + ; addr is already set + lda #$01 + sta data + rts + +;------------------------------------------------------------------------------ + +set_ipv4value: + ldx #$03 +: lda (ptr),y + iny + sta data + sta hdr+2,x + dex + bpl :- + rts + +;------------------------------------------------------------------------------ + +set_data6502: + lda #<6502 + ldx #>6502 + stx data ; Hibyte + sta data ; Lobyte + rts + +;------------------------------------------------------------------------------ + +recv_init: + ; Socket 1 RX Received Size Register: 0 or volatile ? + lda #$26 ; Socket RX Received Size Register + jsr prolog + bcs :+++ + + ; Socket 0 RX Read Pointer Register + ; -> addr already set + + ; Calculate and set pyhsical address + ldx #>$7000 ; Socket 1 RX Base Address + jsr set_addrphysical + + ; Compare peer IP addr and peer port with expected values + ; in 'hdr' and set C(arry flag) if there's a mismatch + clc + ldx #$05 + stx tmp +: jsr recv_byte ; Doesn't trash C + ldx tmp + eor hdr,x ; Doesn't trash C + beq :+ + sec +: dec tmp + bpl :-- + php ; Save C + + ; Read data length + jsr recv_byte ; Hibyte + sta len+1 + jsr recv_byte ; Lobyte + sta len + + ; Add 8 byte header to set pointer advancement + clc + adc #<$0008 + sta adv + lda len+1 + adc #>$0008 + sta adv+1 + + ; Skip frame if it doesn't originate from our + ; expected communicaion peer + plp ; Restore C + bcs recv_done + + ; Return success with data length + lda len + ldx len+1 + clc +: rts + +;------------------------------------------------------------------------------ + +send_init: + ; Set pointer advancement + sta adv + stx adv+1 + + ; Socket 1 TX Free Size Register: 0 or volatile ? + lda #$20 ; Socket TX Free Size Register + jsr prolog + bcs :+ + + ; Socket 1 TX Free Size Register: < advancement ? + cpx adv ; Lobyte + sbc adv+1 ; Hibyte + bcc rts_cs + + ; Socket 1 TX Write Pointer Register + ldy #$24 + jsr set_addrsocket1 + + ; Calculate and set pyhsical address + ldx #>$5000 ; Socket 1 TX Base Address + jsr set_addrphysical + + ; Return success + clc +: rts + +;------------------------------------------------------------------------------ + +prolog: + ; Check for completion of previous command + ; Socket 1 Command Register: 0 ? + jsr set_addrcmdreg1 + ldx data + bne rts_cs ; Not completed -> error + + ; Socket Size Register: not 0 ? + tay ; Select Size Register + jsr get_wordsocket1 + stx ptr ; Lobyte + sta ptr+1 ; Hibyte + ora ptr + bne :+ +rts_cs: sec ; Error (size == 0) + rts + + ; Socket Size Register: volatile ? +: jsr get_wordsocket1 + cpx ptr ; Lobyte + bne rts_cs ; Volatile size -> error + cmp ptr+1 ; Hibyte + bne rts_cs ; Volatile size -> error + clc ; Sucess (size != 0) + rts + +;------------------------------------------------------------------------------ + +recv_byte: + ; Read byte + lda data + + ; Increment physical addr shadow lobyte + inc sha + beq incsha + rts + +;------------------------------------------------------------------------------ + +send_byte: + ; Write byte + sta data + + ; Increment physical addr shadow lobyte + inc sha + beq incsha + rts + + ; Increment physical addr shadow hibyte +incsha: inc sha+1 + beq set_addrbase + rts + +;------------------------------------------------------------------------------ + +recv_done: + ; Set parameters for commit code + lda #$40 ; RECV + ldy #$28 ; Socket RX Read Pointer Register + bne epilog ; Always + +;------------------------------------------------------------------------------ + +send_done: + ; Set parameters for commit code + lda #$20 ; SEND + ldy #$24 ; Socket TX Write Pointer Register + + ; Advance pointer register +epilog: jsr set_addrsocket1 + tay ; Save command + clc + lda ptr + adc adv + tax + lda ptr+1 + adc adv+1 + sta data ; Hibyte + stx data ; Lobyte + + ; Set command register + tya ; Restore command + jsr set_addrcmdreg1 + sta data + sec ; When coming from _recv_init -> error + rts + +;------------------------------------------------------------------------------ + +set_addrphysical: + lda data ; Hibyte + ldy data ; Lobyte + sty ptr + sta ptr+1 + and #>$0FFF ; Socket Mask Address (hibyte) + stx bas ; Socket Base Address (hibyte) + ora bas + tax + ora #>$F000 ; Move sha/sha+1 to $F000-$FFFF + sty sha + sta sha+1 +set_addr: + stx addr ; Hibyte + sty addr+1 ; Lobyte + rts + +;------------------------------------------------------------------------------ + +set_addrcmdreg1: + ldy #$01 ; Socket Command Register +set_addrsocket1: + ldx #>$0500 ; Socket 1 register base address + bne set_addr ; Always + +;------------------------------------------------------------------------------ + +set_addrbase: + ldx bas ; Socket Base Address (hibyte) + ldy #<$0000 ; Socket Base Address (lobyte) + beq set_addr ; Always + +;------------------------------------------------------------------------------ + +get_wordsocket1: + jsr set_addrsocket1 + lda data ; Hibyte + ldx data ; Lobyte + rts + +;------------------------------------------------------------------------------ + +.rodata + +mac: .byte $00, $08, $DC ; OUI of WIZnet + .byte $11, $11, $11 + +;------------------------------------------------------------------------------ + +.data + +hdr: .word 6502 ; Destination Port + .res 4 ; Destination IP Address