From c9af38790a52f090eab041860f3787affa599b54 Mon Sep 17 00:00:00 2001 From: Oliver Schmidt Date: Sat, 1 Aug 2015 18:57:58 +0200 Subject: [PATCH] Added context to W5100 UDP driver. In order to ease exploring the W5100 UDP driver a simple test program using it was added. Additionally a communication peer program was introduced. The latter builds as-is for Windows using i.e. the VC++ command line 'cl w5100_peer.c'. --- supplement/w5100_udp.s | 114 +++++++++++++++++++++++++++++++---------- test/Makefile | 12 ++++- test/w5100_peer.c | 112 ++++++++++++++++++++++++++++++++++++++++ test/w5100_udp_c.c | 96 ++++++++++++++++++++++++++++++++++ test/w5100_udp_s.s | 41 +++++++++++++++ 5 files changed, 346 insertions(+), 29 deletions(-) create mode 100644 test/w5100_peer.c create mode 100644 test/w5100_udp_c.c create mode 100644 test/w5100_udp_s.s diff --git a/supplement/w5100_udp.s b/supplement/w5100_udp.s index e7917de..fea59ec 100644 --- a/supplement/w5100_udp.s +++ b/supplement/w5100_udp.s @@ -29,24 +29,31 @@ 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 +ptr := $06 ; 2 byte pointer value +sha := $08 ; 2 byte physical addr shadow ($F000-$FFFF) +adv := $EB ; 2 byte pointer register advancement +len := $ED ; 2 byte frame length +tmp := $FA ; 1 byte temporary value +bas := $FB ; 1 byte socket 1 Base Address (hibyte) + +mode := $C0B4 +addr := $C0B5 +data := $C0B7 + ;------------------------------------------------------------------------------ init: +; Input +; AX: Address of ip_parms (serverip, cfg_ip, cfg_netmask, cfg_gateway) +; Output +; None +; Remark +; The ip_parms are only accessed during this function. + ; Set ip_parms pointer sta ptr stx ptr+1 @@ -99,6 +106,11 @@ init: ; -> A is still $0A sta data + ; Socket 1 Source Port Register: 6502 + ldy #$04 + jsr set_addrsocket1 + jsr set_data6502 + ; 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 @@ -112,11 +124,6 @@ init: ; -> 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 @@ -124,7 +131,7 @@ init: sta data ; Socket 1 Command Register: OPEN - ; addr is already set + ; -> addr is already set lda #$01 sta data rts @@ -153,12 +160,20 @@ set_data6502: ;------------------------------------------------------------------------------ recv_init: +; Input +; None +; Output +; C: Clear if ready to receive +; AX: If C is clear then number of bytes to receive +; Remark +; To be called before recv_byte. + ; 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 + ; Socket 1 RX Read Pointer Register ; -> addr already set ; Calculate and set pyhsical address @@ -207,6 +222,13 @@ recv_init: ;------------------------------------------------------------------------------ send_init: +; Input +; AX: Number of bytes to send +; Output +; C: Clear if ready to send +; Remark +; To be called before send_byte. + ; Set pointer advancement sta adv stx adv+1 @@ -219,7 +241,7 @@ send_init: ; Socket 1 TX Free Size Register: < advancement ? cpx adv ; Lobyte sbc adv+1 ; Hibyte - bcc rts_cs + bcc sec_rts ; Not enough free size -> error ; Socket 1 TX Write Pointer Register ldy #$24 @@ -240,7 +262,7 @@ prolog: ; Socket 1 Command Register: 0 ? jsr set_addrcmdreg1 ldx data - bne rts_cs ; Not completed -> error + bne sec_rts ; Not completed -> error ; Socket Size Register: not 0 ? tay ; Select Size Register @@ -249,21 +271,30 @@ prolog: sta ptr+1 ; Hibyte ora ptr bne :+ -rts_cs: sec ; Error (size == 0) + +sec_rts: + sec ; Error (size == 0) rts ; Socket Size Register: volatile ? : jsr get_wordsocket1 cpx ptr ; Lobyte - bne rts_cs ; Volatile size -> error + bne sec_rts ; Volatile size -> error cmp ptr+1 ; Hibyte - bne rts_cs ; Volatile size -> error - clc ; Sucess (size != 0) + bne sec_rts ; Volatile size -> error + clc ; Success (size != 0) rts ;------------------------------------------------------------------------------ recv_byte: +; Input +; None +; Output +; A: Byte received +; Remark +; May be called as often as indicated by recv_init. + ; Read byte lda data @@ -275,6 +306,13 @@ recv_byte: ;------------------------------------------------------------------------------ send_byte: +; Input +; A: Byte to send +; Output +; None +; Remark +; Should be called as often as indicated to send_init. + ; Write byte sta data @@ -283,14 +321,24 @@ send_byte: beq incsha rts +incsha: ; Increment physical addr shadow hibyte -incsha: inc sha+1 + inc sha+1 beq set_addrbase rts ;------------------------------------------------------------------------------ recv_done: +; Input +; None +; Output +; None +; Remark +; Mark data indicated by recv_init as processed (independently from how +; often recv_byte was called), if not called then next call of recv_init +; will just indicate the very same data again. + ; Set parameters for commit code lda #$40 ; RECV ldy #$28 ; Socket RX Read Pointer Register @@ -299,12 +347,22 @@ recv_done: ;------------------------------------------------------------------------------ send_done: +; Input +; None +; Output +; None +; Remark +; Actually send data indicated to send_init (independently from how often +; send_byte was called), if not called then send_init (and send_byte) are +; just NOPs. + ; Set parameters for commit code lda #$20 ; SEND ldy #$24 ; Socket TX Write Pointer Register +epilog: ; Advance pointer register -epilog: jsr set_addrsocket1 + jsr set_addrsocket1 tay ; Save command clc lda ptr @@ -319,7 +377,7 @@ epilog: jsr set_addrsocket1 tya ; Restore command jsr set_addrcmdreg1 sta data - sec ; When coming from _recv_init -> error + sec ; When coming from recv_init -> error rts ;------------------------------------------------------------------------------ @@ -336,6 +394,7 @@ set_addrphysical: ora #>$F000 ; Move sha/sha+1 to $F000-$FFFF sty sha sta sha+1 + set_addr: stx addr ; Hibyte sty addr+1 ; Lobyte @@ -345,6 +404,7 @@ set_addr: set_addrcmdreg1: ldy #$01 ; Socket Command Register + set_addrsocket1: ldx #>$0500 ; Socket 1 register base address bne set_addr ; Always diff --git a/test/Makefile b/test/Makefile index 96f59a0..584cd3e 100644 --- a/test/Makefile +++ b/test/Makefile @@ -118,8 +118,16 @@ ip65demo.dsk: httpd.bin httpd-slotscan.bin java -jar $(AC) -cc65 $@ webserver-slot3 B < httpd.bin java -jar $(AC) -cc65 $@ webserver-slotscan B < httpd-slotscan.bin +w5100_%.bin: ../supplement/w5100_%.s w5100_%_s.s w5100_%_c.c + cl65 -o $@ -t apple2enh -m $(basename $@).map $^ + +w5100.dsk: w5100_udp.bin + cp prodos.dsk $@ + java -jar $(AC) -cc65 $@ udp bin < w5100_udp.bin + clean: make -C ../ip65 clean make -C ../drivers clean - -rm -f *.prg *.bin *.vicprg *.map - -rm -f ip65.d64 ip65.dsk ip65demo.dsk + -rm -f ../supplement/*.o + -rm -f *.o *.prg *.bin *.vicprg *.map + -rm -f ip65.d64 ip65.dsk ip65demo.dsk w5100.dsk diff --git a/test/w5100_peer.c b/test/w5100_peer.c new file mode 100644 index 0000000..6e9f3e5 --- /dev/null +++ b/test/w5100_peer.c @@ -0,0 +1,112 @@ +#include +#include + +#define WIN32_LEAN_AND_MEAN +#include +#pragma comment(lib, "ws2_32.lib") + +void main(void) +{ + printf("Init\n"); + WSADATA wsa; + if (WSAStartup(MAKEWORD(2, 2), &wsa) != 0) + { + return; + } + + SOCKET s = socket(AF_INET, SOCK_DGRAM , IPPROTO_UDP); + if (s == INVALID_SOCKET) + { + return; + } + + u_long arg = 1; + if (ioctlsocket(s, FIONBIO, &arg) == SOCKET_ERROR) + { + return; + } + + SOCKADDR_IN local; + local.sin_family = AF_INET; + local.sin_addr.s_addr = INADDR_ANY; + local.sin_port = htons(6502); + if (bind(s, (SOCKADDR *)&local, sizeof(local)) == SOCKET_ERROR) + { + return; + } + + SOCKADDR_IN remote; + remote.sin_addr.s_addr = INADDR_NONE; + + printf("(S)end or e(X)it\n"); + char key; + do + { + int len; + unsigned char buf[1500]; + + if (kbhit()) + { + key = getch(); + } + else + { + key = '\0'; + } + + if (key == 's') + { + if (remote.sin_addr.s_addr == INADDR_NONE) + { + printf("Peer Addr Unknown As Yet\n", len); + } + else + { + unsigned i; + + len = 512; + for (i = 0; i < len; ++i) + { + buf[i] = i; + } + printf("Send Len $%04X To %s", len, inet_ntoa(remote.sin_addr)); + if (sendto(s, buf, len, 0, (SOCKADDR *)&remote, sizeof(remote)) == SOCKET_ERROR) + { + return; + } + printf(".\n"); + } + } + + unsigned remote_size = sizeof(remote); + len = recvfrom(s, buf, sizeof(buf), 0, (SOCKADDR *)&remote, &remote_size); + if (len == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + { + return; + } + len = 0; + } + if (len) + { + unsigned i; + + printf("Recv Len $%04X From %s", len, inet_ntoa(remote.sin_addr)); + for (i = 0; i < len; ++i) + { + if ((i % 24) == 0) + { + printf("\n$%04X:", i); + } + printf(" %02X", buf[i]); + } + printf(".\n"); + } + } + while (key != 'x'); + + closesocket(s); + WSACleanup(); + printf("Done\n"); +} diff --git a/test/w5100_udp_c.c b/test/w5100_udp_c.c new file mode 100644 index 0000000..c7cfec7 --- /dev/null +++ b/test/w5100_udp_c.c @@ -0,0 +1,96 @@ +#include +#include + +void __fastcall__ init(void *parms); + +unsigned recv_init(void); +unsigned char recv_byte(void); +void recv_done(void); + +unsigned __fastcall__ send_init(unsigned len); +void __fastcall__ send_byte(unsigned char val); +void send_done(void); + +struct +{ + unsigned char serverip [4]; + unsigned char cfg_ip [4]; + unsigned char cfg_netmask[4]; + unsigned char cfg_gateway[4]; +} +parms = +{ + {192, 168, 0, 2}, + {192, 168, 0, 123}, + {255, 255, 255, 0}, + {192, 168, 0, 1} +}; + +void main(void) +{ + char key; + + videomode(VIDEOMODE_80COL); + printf("Init\n"); + init(&parms); + + printf("(S)end or e(X)it\n"); + do + { + unsigned len; + + if (kbhit()) + { + key = cgetc(); + } + else + { + key = '\0'; + } + + if (key == 's') + { + unsigned i; + + len = 512; + printf("Send Len $%04X To %d.%d.%d.%d", len, parms.serverip[0], + parms.serverip[1], + parms.serverip[2], + parms.serverip[3]); + while (!send_init(len)) + { + printf("!"); + } + for (i = 0; i < len; ++i) + { + send_byte(i); + } + send_done(); + printf(".\n"); + } + + len = recv_init(); + if (len) + { + unsigned i; + + printf("Recv Len $%04X From %d.%d.%d.%d", len, parms.serverip[0], + parms.serverip[1], + parms.serverip[2], + parms.serverip[3]); + for (i = 0; i < len; ++i) + { + if ((i % 24) == 0) + { + printf("\n$%04X:", i); + } + printf(" %02X", recv_byte()); + } + recv_done(); + printf(".\n"); + } + } + while (key != 'x'); + + printf("Done\n"); +} diff --git a/test/w5100_udp_s.s b/test/w5100_udp_s.s new file mode 100644 index 0000000..9753f6c --- /dev/null +++ b/test/w5100_udp_s.s @@ -0,0 +1,41 @@ +.export _init +.export _recv_init, _recv_byte, _recv_done +.export _send_init, _send_byte, _send_done + +.import init +.import recv_init, recv_byte, recv_done +.import send_init, send_byte, send_done + +_init: + jmp init + +_recv_init: + jsr recv_init + bcc :+ + lda #<$0000 + ldx #>$0000 +: rts + +_recv_byte: + jsr recv_byte + ldx #>$0000 + rts + +_recv_done: + jmp recv_done + +_send_init: + jsr send_init + bcc :+ + lda #<$0000 + ldx #>$0000 + rts +: lda #<$0001 + ldx #>$0001 + rts + +_send_byte: + jmp send_byte + +_send_done: + jmp send_done