diff --git a/HTTPD.PO b/HTTPD.PO
new file mode 100644
index 0000000..315e107
Binary files /dev/null and b/HTTPD.PO differ
diff --git a/src/libsrc/inet.pla b/src/libsrc/inet.pla
index 73aa6b2..b9ca313 100644
--- a/src/libsrc/inet.pla
+++ b/src/libsrc/inet.pla
@@ -45,7 +45,7 @@ export byte[t_inet] iNet
 //
 // List of loadable network device drivers
 //
-byte netDrivers = "WIZNET"
+byte netDrivers = "UTHERNET2"
 byte            = "UTHERNET"
 byte            = ""
 word driver = @netDrivers
diff --git a/src/libsrc/uthernet2.pla b/src/libsrc/uthernet2.pla
new file mode 100644
index 0000000..2400f04
--- /dev/null
+++ b/src/libsrc/uthernet2.pla
@@ -0,0 +1,962 @@
+//
+// Uthernet II Wiznet 5100 based ethernet card
+//
+// TCP/IP is built into hardware, so no dependencies on the software
+// layers, like the Uthernet
+//
+import cmdsys
+    predef syscall, call, getc, gets, putc, puts, putln
+    predef isugt, isuge, isult, isule
+    predef memset, memcpy, modaddr, modexec
+    predef heapmark, heapallocalign, heapalloc, heaprelease, heapavail
+    byte MACHID
+end
+//
+// Net object
+//
+import inet
+   word iNet
+end
+struc t_inet
+    word initIP
+    word serviceIP
+    word openUDP
+    word sendUDP
+    word closeUDP
+    word listenTCP
+    word connectTCP
+    word sendTCP
+    word closeTCP
+    word setInterfaceIP
+    word getInterfaceHA
+end
+//
+// Module don't free memory
+//
+const modkeep     = $2000
+const modinitkeep = $4000
+//
+// Wiznet registers
+//
+const WIZ_MR     = $00
+const WIZ_GWR    = $01
+const WIZ_SUBR   = $05
+const WIZ_SHAR   = $09
+const WIZ_SIPR   = $0F
+const WIZ_IR     = $15
+const WIZ_IMR    = $16
+const WIZ_RTR    = $17
+const WIZ_RCR    = $19
+const WIZ_RMSR   = $1A
+const WIZ_TMSR   = $1B
+const WIZ_PATR   = $1C
+const WIZ_PTMR   = $28
+const WIZ_PMGC   = $29
+const WIZ_UIPR   = $2A
+const WIZ_UPRT   = $2E
+//
+// Wiznet socket registers
+//
+const WIZ_SREGS   = $0400
+const WIZ_SSIZE   = $0100
+const WIZ_SOCK0   = $0400
+const WIZ_SOCK1   = $0500
+const WIZ_SOCK2   = $0600
+const WIZ_SOCK3   = $0700
+const WIZ_SnMR    = $00
+const WIZ_SnCR    = $01
+const WIZ_SnIR    = $02
+const WIZ_SnSR    = $03
+const WIZ_SnPORT  = $04
+const WIZ_SnDHAR  = $06
+const WIZ_SnDIPR  = $0C
+const WIZ_SnDPORT = $10
+const WIZ_SnMSSR  = $12
+const WIZ_SnPROTO = $14
+const WIZ_SnTOS   = $15
+const WIZ_SnTTL   = $16
+const WIZ_SnFSR   = $20
+const WIZ_SnTXRD  = $22
+const WIZ_SnTXWR  = $24
+const WIZ_SnRSR   = $26
+const WIZ_SnRXRD  = $28
+//
+// Wiznet socket data
+//
+const WIZ_TXMEM  = $4000
+const WIZ_TXSIZE = $0800
+const WIZ_TXMASK = WIZ_TXSIZE-1
+const WIZ_TXMEM0 = $4000
+const WIZ_TXMEM1 = $4800
+const WIZ_TXMEM2 = $5000
+const WIZ_TXMEM3 = $5800
+const WIZ_RXMEM  = $6000
+const WIZ_RXSIZE = $0800
+const WIZ_RXMASK = WIZ_RXSIZE-1
+const WIZ_RXMEM0 = $6000
+const WIZ_RXMEM1 = $6800
+const WIZ_RXMEM2 = $7000
+const WIZ_RXMEM3 = $7800
+//
+// Wiznet indirect registers
+//
+byte slot, regidx, regdata
+word saveidx
+//
+// Wiznet MAC address
+//
+byte[6] wizMAC = $00,$0A,$99,$1E,$02,$B0
+//
+// Wiznet IP addresses
+//
+byte[4] localip
+byte[4] subnet
+byte[4] gateway
+//
+// Predefine service routine
+//
+predef wizServiceIP
+//
+// Segment list element
+//
+struc t_segment
+    word seg_buf
+    word seg_len
+end
+//
+// Max Ethernet frame size
+//
+const MAX_FRAME_SIZE = 1518
+const MAC_BROADCAST  = $FFFF
+const MAC_SIZE       = 6
+//
+// Ethernet header
+//
+struc t_ethrhdr
+    byte[MAC_SIZE] ethr_dst
+    byte[MAC_SIZE] ethr_src
+    word           ethr_payload
+end
+const PAYLOAD_IP  = $0008 // BE format
+const PAYLOAD_ARP = $0608 // BE format
+//
+// IP datagram header
+//
+const IP4ADR_SIZE = 4
+struc t_iphdr
+    byte ip_vers_hlen
+    byte ip_service
+    word ip_length
+    word ip_id
+    word ip_flags_fragofst
+    byte ip_ttl
+    byte ip_proto
+    word ip_chksm
+    byte[IP4ADR_SIZE] ip_src
+    byte[IP4ADR_SIZE] ip_dst
+    byte[] ip_options
+end
+const IP_BROADCAST  = $FFFF
+const IP_PROTO_ICMP = $01
+const IP_PROTO_UDP  = $11
+const IP_PROTO_TCP  = $06
+word bcast = IP_BROADCAST, IP_BROADCAST
+//
+// ICMP type/codes
+//
+const IP_PROTO_ICMP   = 1
+const ICMP_ECHO_REQST = 8
+const ICMP_ECHO_REPLY = 0
+//
+// ICMP message format
+//
+struc t_icmp
+    byte icmp_type
+    byte icmp_code
+    word icmp_chksm
+    word[2] icmp_header
+end
+//
+// UDP IPv4 psuedo header
+//
+struc t_piphdr
+    byte[IP4ADR_SIZE] pip_src
+    byte[IP4ADR_SIZE] pip_dst
+    byte             pip_zero
+    byte             pip_proto
+    word             pip_len
+end
+//
+// UDP header
+//
+struc t_udphdr
+    word udp_src
+    word udp_dst
+    word udp_len
+    word udp_chksm
+end
+//
+// TCP header
+//
+struc t_tcphdr
+    word tcp_src
+    word tcp_dst
+    word tcp_len
+    word tcp_chksm
+end
+//
+// Local network parameters
+//
+const MAX_WIZ_CHANNELS	= 4
+//
+// Channel protocols
+//
+const WIZ_PROTO_CLOSED     = 0
+const WIZ_PROTO_TCP        = 1
+const WIZ_PROTO_UDP	   = 2
+const WIZ_PROTO_IP	   = 3
+const WIZ_PROTO_RAW	   = 4
+//
+// State transistions
+//
+const TCP_STATE_CLOSED	= 0
+const TCP_STATE_CLOSING = 1
+const TCP_STATE_LISTEN  = 2
+const TCP_STATE_CONNECT = 3
+const TCP_STATE_OPEN    = 4
+//
+// HW channels
+//
+struc t_channel
+    byte    channel_proto
+    byte    channel_state
+    word    channel_regs
+    word    channel_txmem
+    word    channel_rxmem
+    word    channel_lclport
+    word    channel_remport
+    byte[4] channel_remip
+    word    channel_recv_func
+    word    channel_recv_parm
+end
+byte[t_channel * MAX_WIZ_CHANNELS] wizChannel
+//
+// Service ICMP hook
+//
+export word hookICMP
+//
+// Defines for ASM routines
+//
+asm equates
+	!SOURCE	"vmsrc/plvmzp.inc"
+end
+//
+// Swap bytes in word
+//
+asm swab
+	LDA	ESTKL,X
+	LDY	ESTKH,X
+	STA	ESTKH,X
+	STY	ESTKL,X
+	RTS
+end
+//
+// Wiznet I/O functions
+//
+// POKE WORD TO I/O SPACE
+// Note: Big Endian format
+//
+asm _pokeiow
+	LDA	ESTKH,X
+end
+asm _pokeiowl
+	STA	$C000
+	LDA	ESTKL,X
+end
+asm _pokeiowh
+	STA	$C000
+	RTS
+end
+//
+// POKE BYTE TO I/O SPACE
+//
+asm _pokeio
+	LDA	ESTKL,X
+end
+asm _pokeiol
+	STA	$C000
+	RTS
+end
+//
+// PEEK BYTE FROM I/O SPACE
+//
+asm _peekio
+	DEX
+end
+asm _peekiol
+	LDA	$C000
+	STA	ESTKL,X
+	LDA	#$00
+	STA	ESTKH,X
+	RTS
+end
+//
+// PEEK WORD FROM I/O SPACE
+// Note: Big Endian format
+//
+asm _peekiow
+	DEX
+end
+asm _peekiowl
+	LDA	$C000
+	STA	ESTKH,X
+end
+asm _peekiowh
+	LDA	$C000
+	STA	ESTKL,X
+	RTS
+end
+//
+// WRITE DATA INTO I/O SPACE
+// pokedata(BUF, LEN)
+//
+asm pokedata
+	LDA	ESTKL+1,X
+	STA	SRCL
+	LDA	ESTKH+1,X
+	STA	SRCH
+	LDY     ESTKL,X
+	BEQ	POKELP
+	LDY	#$00
+	INC     ESTKH,X
+POKELP	LDA	(SRC),Y
+end
+asm _pokedata
+	STA	$C000
+	INY
+	BNE	+
+    	INC	SRCH
++	DEC	ESTKL,X
+	BNE	POKELP
+	DEC	ESTKH,X
+	BNE	POKELP
+	INX
+	RTS
+end
+//
+// READ DATA FROM I/O SPACE
+// peekdata(BUF, LEN)
+//
+asm peekdata
+	LDA	ESTKL+1,X
+	STA	DSTL
+	LDA	ESTKH+1,X
+	STA	DSTH
+	LDY	ESTKL,X
+	BEQ	PEEKLP
+	LDY	#$00
+	INC     ESTKH,X
+end
+asm _peekdata
+PEEKLP	LDA	$C000
+	STA	(DST),Y
+	INY
+	BNE	+
+    	INC	DSTH
++	DEC	ESTKL,X
+	BNE	PEEKLP
+	DEC	ESTKH,X
+	BNE	PEEKLP
+	INX
+	RTS
+end
+def pokeiow(io, data)
+    _pokeiowl.1 = io
+    _pokeiowh.1 = io+1
+    return _pokeiow(data)
+end
+def pokeio(io, data)
+    _pokeiol.1 = io
+    return _pokeio(data)
+end
+def peekio(io)
+    _peekiol.1 = io
+    return _peekio()
+end
+def peekiow(io)
+    _peekiowl.1 = io
+    _peekiowh.1 = io+1
+    return _peekiow()
+end
+def pokereg(reg, data)
+    _pokeiow(reg)
+    return _pokeio(data)
+end
+def peekreg(reg)
+    _pokeiow(reg)
+    return _peekio()
+end
+def pokeregs(reg, buf, len)
+    _pokeiow(reg)
+    return pokedata(buf, len)
+end
+def peekregs(reg, buf, len)
+    _pokeiow(reg)
+    return peekdata(buf, len)
+end
+def pokeregw(reg, dataw)
+    _pokeiow(reg)
+    _pokeio(dataw.1)
+    return _pokeio(dataw.0)
+end
+def peekregw(reg)
+    word dataw
+    
+    _pokeiow(reg)
+    dataw.1 = _peekio()
+    _pokeiow(reg + 1)
+    dataw.0 = _peekio()
+    return dataw
+end
+//
+// DEBUG
+//
+def putln
+    return putc($0D)
+end
+def putb(hexb)
+    return call($FDDA, hexb, 0, 0, 0)
+end
+def puth(hex)
+    return call($F941, hex >> 8, hex, 0, 0)
+end
+def puti(i)
+  if i < 0; putc('-'); i = -i; fin
+  if i < 10
+    putc(i + '0')
+  else
+    puti(i / 10)
+    putc(i % 10 + '0')
+  fin
+end
+def putip(ipptr)
+    byte i
+    
+    for i = 0 to 2
+        puti(ipptr->[i]); putc('.')
+    next
+    return puti(ipptr->[i])
+end
+//
+// Send UDP datagram
+//
+def wizSendUDP(wiz, ipdst, portdst, data, len)
+    word wizregs, wizdata, txrr, txwr, splitlen
+    
+    wizregs = wiz=>channel_regs
+    wizdata = wiz=>channel_txmem
+    if !ipdst
+        ipdst = @bcast
+    fin
+    //
+    // Wait for Tx room
+    //
+    repeat; until peekregw(wizregs + WIZ_SnFSR) >= len
+    //
+    // Calc new write ptr, check for split
+    //
+    txwr = peekregw(wizregs + WIZ_SnTXWR)
+    txrr = txwr & WIZ_TXMASK
+    if txrr + len > WIZ_TXSIZE
+        splitlen = WIZ_TXSIZE - txrr
+        pokeregs(wizdata + txrr, data,            splitlen)
+        pokeregs(wizdata,        data + splitlen, len - splitlen)
+     else
+        pokeregs(wizdata + txrr, data, len)
+    fin
+    //
+    // Set destination address/port
+    //
+    pokeregs(wizregs + WIZ_SnDIPR, ipdst, IP4ADR_SIZE)
+    pokeregw(wizregs + WIZ_SnDPORT, portdst)
+    //
+    // Update write pointer and send
+    //
+    pokeregw(wizregs + WIZ_SnTXWR, txwr + len)
+    pokereg(wizregs + WIZ_SnCR, $20) // SEND
+end
+//
+// Open UDP channel and set datagram received callback
+//
+def wizOpenUDP(localport, callback, param)
+    word wiz
+    byte i
+
+    if !localport; return -1; fin // invalid port
+    //
+    // Look for an existing notification on localport
+    //
+    //putc('O')
+    wiz = @wizChannel
+    for i = 1 to MAX_WIZ_CHANNELS
+        if wiz->channel_proto == IP_PROTO_UDP and wiz=>channel_lclport == localport
+            break
+	fin
+	wiz = wiz + t_channel
+    next
+    if i > MAX_WIZ_CHANNELS
+        //
+        // Add notification on localport if room
+        //
+        wiz = @wizChannel
+        for i = 1 to MAX_WIZ_CHANNELS
+            if !wiz->channel_proto
+                break
+	    fin
+	    wiz = wiz + t_channel
+        next
+        if i > MAX_WIZ_CHANNELS
+            return 0
+        fin
+    fin
+    //putc('0' + i);putln
+    //
+    // Fill in this channel and open it
+    //
+    wiz->channel_proto     = WIZ_PROTO_UDP
+    wiz=>channel_lclport   = localport
+    wiz=>channel_recv_func = callback
+    wiz=>channel_recv_parm = param
+    pokeregw(wiz=>channel_regs + WIZ_SnPORT, localport)
+    pokereg(wiz=>channel_regs + WIZ_SnMR, $02) // UDP protocol
+    pokereg(wiz=>channel_regs + WIZ_SnCR, $01) // OPEN
+    return wiz
+end
+//
+// Close UDP port
+//
+def wizCloseUDP(wiz)
+    //putc('S')
+    if isuge(wiz, @wizChannel) and isult(wiz, @wizChannel + MAX_WIZ_CHANNELS * t_channel)
+	//
+	// Clear notiications on this port
+	//
+        if wiz->channel_proto == WIZ_PROTO_UDP
+	    //putc('1' + ((wiz=>channel_regs - WIZ_SREGS) >> 8));putln
+            wiz->channel_proto = WIZ_PROTO_CLOSED
+            pokereg(wiz=>channel_regs + WIZ_SnCR, $10) // CLOSE
+	    return 0
+	fin
+    fin
+    //putc('!');putln
+    //
+    // Invalid port
+    //
+    return -1
+end
+//
+// Open TCP socket in SERVER mode
+//
+def wizListenTCP(lclport, callback, param)
+    word wiz
+    byte i
+
+    //
+    // Look for an existing notification on localport
+    //
+    //putc('L')
+    wiz = @wizChannel
+    for i = 1 to MAX_WIZ_CHANNELS
+        if wiz->channel_proto == WIZ_PROTO_TCP and wiz->channel_state == TCP_STATE_LISTEN and wiz=>channel_lclport == lclport
+            break
+	fin
+	wiz = wiz + t_channel
+    next
+    if i > MAX_WIZ_CHANNELS
+        //
+        // Add notification on localport if room
+        //
+        wiz = @wizChannel
+        for i = 1 to MAX_WIZ_CHANNELS
+            if !wiz->channel_proto
+                break
+	    fin
+	    wiz = wiz + t_channel
+        next
+        if i > MAX_WIZ_CHANNELS
+            return 0
+        fin
+    fin
+    //putc('0' + i);putln
+    //
+    // Fill in this channel and open it
+    //
+    wiz->channel_proto     = WIZ_PROTO_TCP
+    wiz->channel_state     = TCP_STATE_LISTEN
+    wiz=>channel_remip:0   = 0
+    wiz=>channel_remip:2   = 0
+    wiz=>channel_remport   = 0
+    wiz=>channel_lclport   = lclport
+    wiz=>channel_recv_func = callback
+    wiz=>channel_recv_parm = param
+    pokereg(wiz=>channel_regs + WIZ_SnMR, $01) // TCP protocol
+    pokeregw(wiz=>channel_regs + WIZ_SnPORT, lclport)
+    pokereg(wiz=>channel_regs + WIZ_SnCR, $01) // OPEN
+    while peekreg(wiz=>channel_regs + WIZ_SnSR) <> $13; loop // Wait for init
+    pokereg(wiz=>channel_regs + WIZ_SnCR, $02) // LISTEN
+    return wiz
+end
+//
+// Open TCP socket in CLIENT mode
+//
+def wizConnectTCP(remip, remport, lclport, callback, param)
+    word wiz
+    byte i
+
+    //
+    // Look for an existing notification on localport
+    //
+    wiz = @wizChannel
+    for i = 1 to MAX_WIZ_CHANNELS
+        if wiz->channel_proto == WIZ_PROTO_TCP and wiz->channel_state == TCP_STATE_CONNECT and wiz=>channel_lclport == lclport
+            break
+	fin
+	wiz = wiz + t_channel
+    next
+    if i > MAX_WIZ_CHANNELS
+        //
+        // Add notification on localport if room
+        //
+        wiz = @wizChannel
+        for i = 1 to MAX_WIZ_CHANNELS
+            if !wiz->channel_proto
+                break
+	    fin
+	    wiz = wiz + t_channel
+        next
+        if i > MAX_WIZ_CHANNELS
+            return 0
+        fin
+    fin
+    //
+    // Fill in this channel and open it
+    //
+    wiz->channel_proto     = WIZ_PROTO_TCP
+    wiz->channel_state     = TCP_STATE_CONNECT
+    wiz=>channel_remip:0   = remip=>0
+    wiz=>channel_remip:2   = remip=>2
+    wiz=>channel_remport   = remport
+    wiz=>channel_lclport   = lclport
+    wiz=>channel_recv_func = callback
+    wiz=>channel_recv_parm = param
+    pokereg(wiz=>channel_regs + WIZ_SnMR, $01) // TCP protocol
+    pokeregs(wiz=>channel_regs + WIZ_SnDIPR, remip, IP4ADR_SIZE)
+    pokeregw(wiz=>channel_regs + WIZ_SnDPORT, remport)
+    pokeregw(wiz=>channel_regs + WIZ_SnPORT, lclport)
+    pokereg(wiz=>channel_regs + WIZ_SnCR, $01) // OPEN
+    while peekreg(wiz=>channel_regs + WIZ_SnSR) <> $13; loop // Wait for init
+    pokereg(wiz=>channel_regs + WIZ_SnCR, $04) // CONNECT
+    return wiz
+end
+//
+// Write to TCP socket
+//
+def wizSendTCP(wiz, data, len)
+    word wizregs, wizdata, txrr, txwr, splitlen
+    
+    if wiz->channel_state <> TCP_STATE_OPEN; return -1; fin
+    //putc('W');puti(len);putc(':')
+    wizregs = wiz=>channel_regs
+    wizdata = wiz=>channel_txmem
+    //
+    // Wait for Tx room
+    //
+    repeat; until peekregw(wizregs + WIZ_SnFSR) >= len
+    //
+    // Calc new write ptr, check for split
+    //
+    txwr = peekregw(wizregs + WIZ_SnTXWR)
+    txrr = txwr & WIZ_TXMASK
+    if txrr + len > WIZ_TXSIZE
+        splitlen = WIZ_TXSIZE - txrr
+        pokeregs(wizdata + txrr, data,            splitlen)
+        pokeregs(wizdata,        data + splitlen, len - splitlen)
+        //putc('(');puti(splitlen);putc(',');puti(len-splitlen);putc(')')
+     else
+        pokeregs(wizdata + txrr, data, len)
+    fin
+    //puth(txrr);putc('-');putc('>');puth(txwr+len);putln
+    //
+    // Update write pointer and send
+    //
+    pokeregw(wizregs + WIZ_SnTXWR, txwr + len)
+    pokereg(wizregs + WIZ_SnCR, $20) // SEND
+end
+//
+// Close TCP socket
+//
+def wizCloseTCP(wiz)
+    if isuge(wiz, @wizChannel) and isult(wiz, @wizChannel + MAX_WIZ_CHANNELS * t_channel)
+	//
+	// Clear notiications on this port
+	//
+        if wiz->channel_proto == WIZ_PROTO_TCP and (wiz->channel_state == TCP_STATE_OPEN or wiz->channel_state == TCP_STATE_CLOSING) 
+            wiz->channel_state = TCP_STATE_CLOSING
+            pokereg(wiz=>channel_regs + WIZ_SnCR, $08) // DISCON
+	    repeat
+	        wizServiceIP()
+	    until wiz->channel_state == TCP_STATE_CLOSED
+	    wiz->channel_proto = WIZ_PROTO_CLOSED
+	    return 0
+	fin
+    fin
+    //
+    // Invalid port
+    //
+    return -1
+end
+//
+// Service incoming packets
+//
+def wizServiceIP
+    word wiz, wizregs, wizdata, rxlen, rxrr, rxwr, rxpkt, splitlen
+    byte ir, i, sir
+    
+    ir = peekreg(WIZ_IR)
+    if ir and ir <> $FF // Ignore spurious read of IR
+        //putc('I');putb(ir)
+        wiz = @wizChannel
+        for i = 0 to 3
+            when ir & (1 << i)
+                is 1
+                is 2
+                is 4
+                is 8
+                    wizregs = wiz=>channel_regs
+                    wizdata = wiz=>channel_rxmem
+                    sir = peekreg(wizregs + WIZ_SnIR)
+                    when wiz->channel_proto
+                        is WIZ_PROTO_TCP
+			    if sir & $01
+			        //putc('C')
+				//
+				// Connect TCP socket
+				//
+				when wiz->channel_state
+				    is TCP_STATE_LISTEN
+				        peekregs(wiz=>channel_regs + WIZ_SnDIPR, @wiz=>channel_remip, IP4ADR_SIZE)
+					wiz=>channel_remport = peekregw(wiz=>channel_regs + WIZ_SnDPORT)
+				    is TCP_STATE_CONNECT
+				        wiz->channel_state = TCP_STATE_OPEN
+					break
+				    otherwise
+				        //putc('?')
+				wend
+			    fin
+                            if sir & $04
+                                //putc('R')
+                                //
+                                // Receive TCP packet
+                                //
+                                rxlen = peekregw(wizregs + WIZ_SnRSR)
+                                rxrr  = peekregw(wizregs + WIZ_SnRXRD)
+                                rxwr  = rxrr & WIZ_RXMASK
+                                rxpkt = heapalloc(rxlen)
+				//puti(rxlen);putc(':')
+				if rxwr + rxlen > WIZ_RXSIZE
+                                    splitlen = WIZ_RXSIZE - rxwr
+                                    peekregs(wizdata + rxwr, rxpkt,            splitlen)
+                                    peekregs(wizdata,        rxpkt + splitlen, rxlen - splitlen)
+				    //putc('(');puti(splitlen);putc(',');puti(rxlen-splitlen);putc(')')
+                                else
+                                    peekregs(wizdata + rxwr, rxpkt, rxlen)
+                                fin
+				//puth(rxwr);putc('-');putc('>');puth(rxwr+rxlen);putln
+                                pokeregw(wizregs + WIZ_SnRXRD, rxrr + rxlen)
+                                pokereg(wizregs + WIZ_SnCR, $40) // RECV
+                                wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,wiz=>channel_lclport,rxpkt,rxlen,wiz=>channel_recv_parm)
+                                heaprelease(rxpkt)
+                            fin
+			    if sir & $02
+			        //putc('S')
+				//
+				// Close TCP socket
+				//
+				when wiz->channel_state
+				    is TCP_STATE_OPEN
+				        wiz->channel_state = TCP_STATE_CLOSING
+					wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,0,wiz=>channel_lclport,0,wiz=>channel_recv_parm)
+					break
+				    is TCP_STATE_CLOSING
+				        wiz->channel_state = TCP_STATE_CLOSED
+				        pokereg(wiz=>channel_regs + WIZ_SnCR, $10) // CLOSE
+					break
+				    otherwise
+				        //putc('?')
+				wend
+			    fin
+			    if sir & $08
+			        //putc('T')
+				//
+				// Timeout on TCP socket
+				//
+				when wiz->channel_state
+				    is TCP_STATE_OPEN
+				        wiz->channel_state = TCP_STATE_CLOSING
+					wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,wiz=>channel_lclport,0,0,wiz=>channel_recv_parm)
+					break
+				    is TCP_STATE_CONNECT
+					wiz=>channel_recv_func(@wiz=>channel_remip,wiz=>channel_remport,wiz=>channel_lclport,0,0,wiz=>channel_recv_parm)
+				    is TCP_STATE_CLOSING
+				        wiz->channel_state = TCP_STATE_CLOSED
+				        pokereg(wiz=>channel_regs + WIZ_SnCR, $10) // CLOSE
+					break
+				    otherwise
+				        //putc('?')
+				wend
+			    fin
+			    //if sir & $10
+			        //putc('W');putc('O');putc('K');puth(peekregw(wiz=>channel_regs+WIZ_SnTXWR));putln
+				//
+				// Write TCP socket OK
+				//
+			    //fin
+                            break			    
+                        is WIZ_PROTO_UDP
+                            //putc('U');putb(sir)
+                            if sir & $04
+                                //putc('R')
+                                //
+                                // Receive UDP packet
+                                //
+                                rxlen = peekregw(wizregs + WIZ_SnRSR)
+                                rxrr  = peekregw(wizregs + WIZ_SnRXRD)
+                                rxwr  = rxrr & WIZ_RXMASK
+                                rxpkt = heapalloc(rxlen)
+                                if rxwr + rxlen >= WIZ_RXSIZE
+                                    //putc('!')
+                                    splitlen = WIZ_RXSIZE - rxwr
+                                    peekregs(wizdata + rxwr, rxpkt,            splitlen)
+                                    peekregs(wizdata,        rxpkt + splitlen, rxlen - splitlen)
+                                else
+                                    peekregs(wizdata + rxwr, rxpkt, rxlen)
+                                fin
+                                //putc('=');putip(rxpkt);putc(' ');puti(rxlen)
+                                //putc('/');puti(swab(rxpkt=>6))
+                                //putc(' ');puth(rxrr);putc(' ');puth(rxwr);putln
+                                pokeregw(wizregs + WIZ_SnRXRD, rxrr + rxlen)
+                                pokereg(wizregs + WIZ_SnCR, $40) // RECV
+                                wiz=>channel_recv_func(rxpkt,swab(rxpkt=>4),rxpkt+8,rxlen-8,wiz=>channel_recv_parm)
+                                heaprelease(rxpkt)
+                            fin
+                            break
+                        otherwise
+                    wend
+                    pokereg(wiz=>channel_regs + WIZ_SnIR, sir) // Clear SnIR
+                    ir = ir ^ (1 << i)
+                break
+            wend
+            wiz = wiz + t_channel
+        next
+        if ir
+            //
+            // Clear IR for now
+            //
+            pokereg(WIZ_IR, ir)
+        fin
+    fin    
+end
+//
+// Set the local IP addresses
+//
+def setWizIP(newIP, newSubnet, newGateway)
+    if newIP
+        localip:0 = newIP=>0; localip:2 = newIP=>2
+	pokeregs(WIZ_SIPR, newIP, IP4ADR_SIZE)
+    fin
+    if newSubnet
+        subnet:0 = newSubnet=>0; subnet:2 = newSubnet=>2
+	pokeregs(WIZ_SUBR, newSubnet, IP4ADR_SIZE)
+    fin
+    if newGateway
+	gateway:0 = newGateway=>0; gateway:2 = newGateway=>2
+	pokeregs(WIZ_GWR, newGateway, IP4ADR_SIZE)
+    fin
+end
+//
+// Get the interface hardware address
+//
+def getWizHA(ha)
+    if ha
+        ha=>0 = wizMAC:0; ha=>2 = wizMAC:2; ha=>4 = wizMAC:4
+    fin
+    return MAC_SIZE
+end
+//
+// Identify Uthernet II card and initialize
+//
+for slot = $F0 downto $90 step $10
+    regdata = peekio(slot)
+    if (regdata & $E4) == $00
+        pokeio(slot, $03) // Try setting auto-increment indirect I/F
+	if peekio(slot) == $03
+	    saveidx = peekiow(slot + 1)
+	    peekio(slot + 3) // Dummy read to data register should increment index
+	    if peekiow(slot + 1) == saveidx + 1
+	        //
+		// Good chance this is it
+		//
+		pokeio(slot, $80) // RESET
+		regidx      = slot + 1
+		regdata     = slot + 3
+		_pokedata.1 = regdata
+		_peekdata.1 = regdata
+		pokeio(slot, $03) // Auto-increment indirect I/F + enable ping
+		//
+		// The following looks redundant, but it sets up the peek/poke locations
+		// for peekreg(s)/pokereg(s)
+		//
+		pokeiow(regidx, WIZ_MR)
+                pokeio(regdata, $03) // Auto-increment indirect I/F + enable ping
+                peekio(regdata)
+		//
+		// Initialize common registers
+		//
+		pokeregs(WIZ_SHAR, @wizMAC, 6) // MAC addr
+                pokeregw(WIZ_RTR, 5000)        // Timeout period to 500ms
+                pokereg(WIZ_RMSR, $55)         // 2K Rx memory/channel
+                pokereg(WIZ_TMSR, $55)         // 2K Tx memory/channel
+                //
+                // Fill channel structure
+                //
+                saveidx = @wizChannel
+                for slot = 0 to 3
+                    saveidx=>channel_regs  = WIZ_SREGS + (WIZ_SSIZE  * slot)
+                    saveidx=>channel_txmem = WIZ_TXMEM + (WIZ_TXSIZE * slot)
+                    saveidx=>channel_rxmem = WIZ_RXMEM + (WIZ_RXSIZE * slot)
+                    saveidx = saveidx + t_channel
+                next
+		//
+		// Fill in Net class
+		//
+		iNet:serviceIP      = @wizServiceIP
+		iNet:openUDP        = @wizOpenUDP
+		iNet:sendUDP        = @wizSendUDP
+		iNet:closeUDP       = @wizCloseUDP
+		iNet:listenTCP      = @wizListenTCP
+		iNet:connectTCP     = @wizConnectTCP
+		iNet:sendTCP        = @wizSendTCP
+		iNet:closeTCP       = @wizCloseTCP
+		iNet:setInterfaceIP = @setWizIP
+		iNet:getInterfaceHA = @getWizHA
+                return modkeep
+	    fin
+        fin
+	pokeio(slot, regdata) // Restore register
+    fin
+next
+//
+// Not found
+//
+return -1
+done
diff --git a/src/libsrc/wiznet.pla b/src/libsrc/wiznet.pla
index c24b611..8ef71ad 100644
--- a/src/libsrc/wiznet.pla
+++ b/src/libsrc/wiznet.pla
@@ -397,20 +397,20 @@ def peekreg(reg)
     return _peekio()
 end
 def pokeregs(reg, buf, len)
-    word i
-
-    len = len - 1
-    for i = 0 to len
-        _pokeiow(reg + i)
-	_pokeio(buf->[i])
-    next
+    _pokeiow(reg)
+    return pokedata(buf, len)
+//    word i
+//    len = len - 1
+//    for i = 0 to len
+//        _pokeiow(reg + i)
+//	_pokeio(buf->[i])
+//    next
 end
 def peekregs(reg, buf, len)
-// There is an issue missing data on back-to-back reads
     _pokeiow(reg)
     return peekdata(buf, len)
+// There is an issue missing data on back-to-back reads
 //    word i
-
 //    len = len - 1
 //    for i = 0 to len
 //        _pokeiow(reg + i)
diff --git a/src/makefile b/src/makefile
index 9b71f6c..2be09e3 100644
--- a/src/makefile
+++ b/src/makefile
@@ -10,6 +10,7 @@ SB      = SB\#FF2000
 ROD     = ROD\#FE1000
 SIEVE   = SIEVE\#FE1000
 WIZNET  = WIZNET\#FE1000
+UTHERNET2= UTHERNET2\#FE1000
 UTHERNET= UTHERNET\#FE1000
 ETHERIP = ETHERIP\#FE1000
 INET    = INET\#FE1000
@@ -48,7 +49,7 @@ TXTTYPE	= .TXT
 #SYSTYPE	= \#FF2000
 #TXTTYPE	= \#040000
 
-all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03) $(CMD) $(MEMMGR) $(MEMTEST) $(FIBER) $(SB) $(MON) $(ROD) $(SIEVE) $(WIZNET) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1)
+all: $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03) $(CMD) $(MEMMGR) $(MEMTEST) $(FIBER) $(SB) $(MON) $(ROD) $(SIEVE) $(UTHERNET2) $(UTHERNET) $(ETHERIP) $(INET) $(DHCP) $(HTTPD) $(ROGUE) $(ROGUEMAP) $(ROGUECOMBAT) $(ROGUEIO) $(HGR1)
 
 clean:
 	-rm *FE1000 *FF2000 $(PLASM) $(PLVM) $(PLVM01) $(PLVM02) $(PLVM03)
@@ -129,14 +130,14 @@ $(SIEVE): samplesrc/sieve.pla $(PLVM02) $(PLASM)
 	./$(PLASM) -AM < samplesrc/sieve.pla > samplesrc/sieve.a
 	acme --setpc 4094 -o $(SIEVE) samplesrc/sieve.a
 
-$(WIZNET): libsrc/wiznet.pla $(PLVM02) $(PLASM)
-	./$(PLASM) -AM < libsrc/wiznet.pla > libsrc/wiznet.a
-	acme --setpc 4094 -o $(WIZNET) libsrc/wiznet.a
-
 $(UTHERNET): libsrc/uthernet.pla $(PLVM02) $(PLASM)
 	./$(PLASM) -AM < libsrc/uthernet.pla > libsrc/uthernet.a
 	acme --setpc 4094 -o $(UTHERNET) libsrc/uthernet.a
 
+$(UTHERNET2): libsrc/uthernet2.pla $(PLVM02) $(PLASM)
+	./$(PLASM) -AM < libsrc/uthernet2.pla > libsrc/uthernet2.a
+	acme --setpc 4094 -o $(UTHERNET2) libsrc/uthernet2.a
+
 $(ETHERIP): libsrc/etherip.pla $(PLVM02) $(PLASM)
 	./$(PLASM) -AM < libsrc/etherip.pla > libsrc/etherip.a
 	acme --setpc 4094 -o $(ETHERIP) libsrc/etherip.a