# main.sl - TCP/IP stack for my CPU # Copyright (C) 2003 James Bowman # # This is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this software; see the file COPYING. If not, write to # the Free Software Foundation, 59 Temple Place - Suite 330, # Boston, MA 02111-1307, USA. # define(WORD_SIZE, 16) define(hilo, `eval((($1) << 8) + (0xff & ($2)))') define(pp,eval(1024 - 16)) define(alloc, `eval(pp - $1) define(`pp', eval(pp - $1))') define(WANT_MON, 1) # The host monitor, for development define(WANT_GATE_TRACE, 0) define(CHECKSUM_PANIC,0) # Should checksum errors cause an alert? define(ALERT_DETAILS,1) # Should an alert dump out RTL8019 state define(WARN_STALLS,0) # TCP stalls get an alert? # `gate' can write the source line number out - for a crude kind of # execution trace define(__LINE__, `0x`'__line__ ') ifelse(WANT_GATE_TRACE, 1, ` define(gate, LINE hex4 cr) ',` define(gate, ) ') define(mySeq, alloc(2)) define(rmSeq, alloc(2)) define(rmPort, alloc(1)) define(ringReadPtr, alloc(1)) define(appendPtr, alloc(1)) ifelse(WARN_STALLS,1,` define(idle, alloc(1)) ') # 0x947 #: silly # -1 out1 # sleep1 # 0 out1 # sleep1 # 0x41 outch # >silly >cold :cold hex8 ifelse(WANT_MON,1,[ ######################################################################## # SIMPLE MONITOR ######################################################################## cr # This monitor listens for byte commands on the input channel. These are: # 1 Write value to address # 2 Jump to main # 3 Dump out memory :interact 0x40 outch inch 1- ?eq >mon_write # 1: write 1- ?eq main # 2: run >interact : mon_write ifelse(WORD_SIZE, 16, ` in16 in16 ! >interact ',` in32 in16 ! >interact : in32 in16 in16 16 lshift or; ') : in16 inch inch 8 lshift or; : inch 0 inb1 # Wait for '1' start bit ?eq- >inch : inb8 0 # Accumulate 8 data bits inb4 inb4 >waitHostEdge # consume '0' stop bit : inb4 inb2 : inb2 inb1 : inb1 waitHostEdge in0 rshift1 >2a+b0 : cr 10 >outch : hex8 dup rshift8 rshift8 hex4 : hex4 dup rshift8 hex2 : hex2 dup rshift4 hex1 : hex1 0xf and -10 + ?lt >low 7 + :low 0x3a + : outch waitHostEdge 1 outbit 8 : outch_loop swap dup outbit rshift1 swap 1- ?ne >outch_loop 0 outbit >2drop : outbit and1 out1 # First wait until hostCLK is zero :waitHostEdge hostCLK ?ne- >waitHostEdge :waitHostEdge1 hostCLK ?eq- >waitHostEdge1 : return ; : hostCLK in0 : and1 1 and; ],[ >main : and1 1 and; :return ; ]) ######################################################################## # STACK MANIPLUATION ######################################################################## : 2dup over : _over over; : tuck dup # copy top item to third position : -rot down swap up # rotate top to third position : _swap swap; : rot swap down swap up; # rotate third item to top : 0_0 0 # -- 0 0 : tuck0 0 swap; # a -- 0 a ######################################################################## # ARITHMETIC ######################################################################## : neg not : 1+ 1 +; : 1- -1 +; : - neg +; # a b -- 2a+(b&1) : 2a+b0 and1 # a b -- 2a+b : 2a+b over + +; : rshift ?eq >_drop swap rshift1 swap 1- >rshift : 2* dup : _+ +; : lshift ?eq >_drop swap 2* swap 1- >lshift : rshift11 rshift1 : rshift10 rshift1 : rshift9 rshift1 : rshift8 rshift1 : rshift7 rshift1 : rshift6 rshift1 : rshift5 rshift1 : rshift4 rshift1 : rshift3 rshift1 : rshift2 rshift1 rshift1; : 2- -2 +; : 2+ 2 +; : max # a b -- max(a,b) 2dup - # a b -- a b a-b ?gt- >_drop nip; ######################################################################## # MEMORY OPERATORS ######################################################################## define(port, `eval(1 << ($1))') : ! J! : _drop drop; : out1 port(8) : O! out- drop; : 2drop drop drop; : in0 0 in; ######################################################################## # SLEEP ######################################################################## ifelse(WORD_SIZE, 16, ` : msleep 1 >dloop1 : sleep1 eval(40000000 / 262144) : dloop1 0 # 65536 * 4 = 262144 cycles : dloop 1- ?ne >dloop drop 1- ?ne >dloop1 drop; ',` # 40 MHz, 40e6 cycles, load counter with 10e6 : sleep1 eval(10000000 >> 11) 11 lshift : dloop 1- ?ne >dloop # 4 cycles per iteration drop; : sleep1us 10 >dloop : sleep1ms 5000 2* >dloop ') ######################################################################## # ISA ######################################################################## # port(9) is the isa data and direction bus # port(10) is the 4 bit control bus # port(11) is the address bus : and_ff 0xff and; # addr -- value : isa@ 0x100 port(9) out- drop # direction: in port(11) out- drop # address 0xe isaCTL # assert IORD 0x1 in >isaCTL0 # value addr -- : isa! # 2dup swap 0x57 outch 0x20 outch hex4 0x20 outch hex4 cr port(11) out- drop port(9) out- drop 0xd isaCTL : isaCTL0 0xf : isaCTL port(10) out out out out out out out out out out- drop; : isaWritePort swap and_ff swap out- drop : isaIOWR 0xd isaCTL >isaCTL0 ifelse(TEST, ISA, ` : vID $0x`'include(ident) : main cr 0x48 outch 0x20 outch 3 in hex4 cr 0x53 outch 0x20 outch &vID @ hex4 cr : forever 0xf port(11) out- drop 1 hex1 cr sleep1 0x0 port(11) out- drop 0 hex1 cr sleep1 >forever ') ######################################################################## # RTL8019AS ######################################################################## define(addr, `eval($1 | 1024)') define(CR, addr(0x00)) define(PSTART, addr(0x01)) define(PAR0, addr(0x01)) # Page 1 define(PAR2, addr(0x03)) # Page 1 define(PAR4, addr(0x05)) # Page 1 define(CR9346, addr(0x01)) # Page 3 define(PSTOP, addr(0x02)) define(BNRY, addr(0x03)) define(TSR, addr(0x04)) define(TPSR, addr(0x04)) define(TBCR0, addr(0x05)) define(NCR, addr(0x05)) define(TBCR1, addr(0x06)) define(ISR, addr(0x07)) define(CURR, addr(0x07)) # Page 1 define(RSAR0, addr(0x08)) define(CRDA0, addr(0x08)) define(RSAR1, addr(0x09)) define(CRDA1, addr(0x09)) define(RBCR0, addr(0x0A)) define(RBCR1, addr(0x0B)) define(RSR, addr(0x0C)) define(RCR, addr(0x0C)) define(TCR, addr(0x0D)) define(CNTR0, addr(0x0D)) define(DCR, addr(0x0E)) define(CNTR1, addr(0x0E)) define(IMR, addr(0x0F)) define(CNTR2, addr(0x0F)) define(RDMAPORT, addr(0x10)) define(RSTPORT, addr(0x18)) define(ISR_RST, 7) define(ISR_OVW, 4) define(ISR_PRX, 0) define(ISR_RDC, 6) define(ISR_PTX, 1) define(DCRINIT, 0x58) define(RCR_INIT, 0x04) define(TCR_INIT, 0x00) define(IMR_INIT, 0x11) define(TXSTART_INIT, 0x40) define(RXSTART_INIT, 0x46) define(RXSTOP_INIT, 0x60) define(RECEIVER_BUFFER_SIZE, eval(RXSTOP_INIT - RXSTART_INIT)) : rtl8019readRDMA RDMAPORT : rtl8019read >isa@ : rtl8019write16 # vv addr -- 2dup rtl8019write swap swab swap 1+ : rtl8019write # v addr -- >isa! : rtl8019writeMem dup @ # ptr vv dup dup swab # ptr vv v0 v1 0x1f and 0x400 or rtl8019write ?lt- >_drop 1+ >rtl8019writeMem : rtl8019page1 eval((1 << 6) | 0x22) >rtl8019writeCR : rtl8019page0 eval((0 << 6) | 0x22) : rtl8019writeCR CR >rtl8019write ifelse(ALERT_DETAILS,1,` : rtl8019dump eval((0 << 6) | 0x22) rtl8019regdump eval((1 << 6) | 0x22) rtl8019regdump eval((2 << 6) | 0x22) rtl8019regdump eval((3 << 6) | 0x22) rtl8019regdump >rtl8019page0 : rtl8019regdump # page -- rtl8019writeCR CR :shag dup rtl8019read hex2 0x20 outch 1+ dup eval(CR+0x10) xor ?ne- >shag >cr : lshift8 8 >lshift : alert ifelse(WANT_MON, 1, ` 0x21 outch hex4 cr ifelse(ALERT_DETAILS,1,` rtl8019dump ringReadPtr @ lshift8 dup hex4 cr 40 ndump ') ') >cold ifelse(ALERT_DETAILS,1,` # Display n words of packet memory start at p : ndump # p n -- ?eq cr ?eq >2drop 1- swap dup R@ # n' p v hex4 0x20 outch 2+ swap >ndump ') : R@ ifelse(A, A, ` dup RXSTOP_INIT swab - ?lt- >pok # dup hex4 0x20 outch eval(RXSTOP_INIT - RXSTART_INIT) swab - #dup hex4 cr : pok ') RSAR0 rtl8019write16 0x2 RBCR0 rtl8019write16 0xA rtl8019writeCR # Remote Read, Start Command : rtl8019readRDMA16 rtl8019readRDMA swab isa@ or; define(pack88, `eval((($1) << 8) + ($2))') : IP23 $pack88(0, 199) : IP01 $pack88(192,168) : MAC45 $pack88(0x9A,0xBC) : MAC23 $pack88(0x56,0x7F) : MAC01 $pack88(0x14,0x34) : regset $pack88(DCR, DCRINIT) $pack88(ISR, 0xff) $pack88(RBCR0, 0x00) $pack88(RBCR0+1, 0x00) $pack88(RCR, 0x04) $pack88(TCR, 0x02) $pack88(PSTART, RXSTART_INIT) $pack88(BNRY, RXSTART_INIT) $pack88(PSTOP, RXSTOP_INIT) $pack88(CR, 0x61) # Page 1 $pack88(CURR, RXSTART_INIT) $pack88(PAR0+0, 0x14) $pack88(PAR0+1, 0x34) $pack88(PAR0+2, 0x56) $pack88(PAR0+3, 0x7F) $pack88(PAR0+4, 0x9A) $pack88(PAR0+5, 0xBC) $pack88(CR, 0x21) # page 0 $pack88(DCR, DCRINIT) $pack88(CR, 0x22) # go! $pack88(ISR, 0xff) $pack88(IMR, IMR_INIT) $pack88(0x80 + TCR, TCR_INIT) : vID $0x`'include(ident) : main cr 0x48 outch 0x20 outch 3 in hex4 cr 0x53 outch 0x20 outch &vID @ hex4 cr 0x1f isaCTL msleep isaCTL0 msleep 0x21 rtl8019writeCR # stop the NIC, abort DMA, page 0 msleep ®set rtl8019writeMem : watch __LINE__ ISR rtl8019read eval(1 << ISR_OVW) and ?ne- >alert drop : forever 0x999 hex4 cr eval((0 << 6) | 0x22) rtl8019regdump sleep1 >forever ') ifelse(` ######################################################################## # I2C AND STA013 ######################################################################## : i2c02 0 i2c # SCL 0 SDA 1 : i2c2 2 # SCL 1 SDA 1 # sclsda -- : i2c 2* out1 >sleep1us # dup rshift1 hex1 0x20 outch and1 1 xor hex1 >cr : i2c_start i2c02 # SCL 0 SDA 1 # SCL 1 SDA 1 3 i2c # SCL 1 SDA 0 : i2c1 1 >i2c # SCL 0 SDA 0 : i2c_stop 3 i2c # SCL 1 SDA 0 >i2c2 # SCL 1 SDA 1 : sta013_sendreg i2c_start 0x86 i2c_byte # byte -- : i2c_byte 8 : i2c_bit swap 2* dup rshift8 1 and_reverse dup i2c # SCL 0 SDA X dup 2 or i2c # SCL 1 SDA X i2c # SCL 0 SDA X swap 1- ?ne >i2c_bit 2drop i2c02 # SCL 0 SDA 1 # SCL 1 SDA 1 # Uncomment this to return the SDA line state # in0 rshift2 and1 0 i2c # SCL 0 SDA 1 >i2c1 # SCL 0 SDA 0 # -- byte : i2c_receive 0 8 : i2c_receive_bit swap i2c02 # SCL 0 SDA 1 # SCL 1 SDA 1 in0 rshift2 2a+b0 swap 1- ?ne >i2c_receive_bit >_drop # reg -- value : sta013_read sta013_sendreg i2c_start 0x87 i2c_byte i2c_receive >i2c_stop ######################################################################## # MAIN ######################################################################## define(OFF_PKT_FLAGS, 0) define(OFF_PKT_NEXTPAGE, 1) define(OFF_PKT_LEN, 2) define(OFF_PKT_SIZE, 4) define(`BASE', `eval(OFF_PKT_SIZE + $1)') define(OFF_ETH_DEST, BASE(0)) define(OFF_ETH_SRC, BASE(6)) define(OFF_ETH_TYPE, BASE(12)) define(OFF_ETH_SIZE, BASE(14)) define(`BASE', `eval(OFF_ETH_SIZE + $1)') define(OFF_ARP_HARD_TYPE, BASE(0)) define(OFF_ARP_PROT_TYPE, BASE(2)) define(OFF_ARP_HARD_SIZE, BASE(4)) define(OFF_ARP_PROT_SIZE, BASE(5)) define(OFF_ARP_OPCODE, BASE(6)) define(OFF_ARP_SETH, BASE(8)) define(OFF_ARP_SIP, BASE(14)) define(OFF_ARP_TETH, BASE(18)) define(OFF_ARP_TIP, BASE(24)) define(OFF_ARP_SIZE, BASE(28)) define(OFF_IP, BASE(0)) define(OFF_IP_VHLTOS, BASE(0)) define(OFF_IP_LENGTH, BASE(2)) define(OFF_IP_IPID, BASE(4)) define(OFF_IP_IPOFFSET, BASE(6)) define(OFF_IP_TTLPROTO, BASE(8)) define(OFF_IP_CHKSUM, BASE(10)) define(OFF_IP_SRCIP, BASE(12)) define(OFF_IP_DSTIP, BASE(16)) define(OFF_IP_SIZE, BASE(20)) define(`BASE', `eval(OFF_IP_SIZE + $1)') define(OFF_ICMP_TYPE, BASE(0)) define(OFF_ICMP_IDENTIFIER, BASE(4)) define(OFF_UDP, BASE(0)) define(OFF_UDP_SPORT, BASE(0)) define(OFF_UDP_DPORT, BASE(2)) define(OFF_UDP_LENGTH, BASE(4)) define(OFF_UDP_CHKSUM, BASE(6)) define(OFF_UDP_DATA, BASE(8)) define(OFF_TCP, BASE(0)) define(OFF_TCP_SPORT, BASE(0)) define(OFF_TCP_DPORT, BASE(2)) define(OFF_TCP_SEQ, BASE(4)) define(OFF_TCP_ACK, BASE(8)) define(OFF_TCP_LENFLG, BASE(12)) define(OFF_TCP_WINDOW, BASE(14)) define(OFF_TCP_CHKSUM, BASE(16)) define(OFF_TCP_URG, BASE(18)) define(OFF_TCP_DATA, BASE(20)) define(ARP_REQUEST, 1) define(ARP_REPLY, 2) define(UIP_ETHTYPE_IP, 0x0800) define(UIP_ETHTYPE_ARP, 0x0806) define(IP_PROTO_ICMP, 1) define(IP_PROTO_IGMP, 2) define(IP_PROTO_TCP, 6) define(IP_PROTO_UDP, 17) define(ICMP_ECHO_REPLY, 0) define(ICMP_ECHO, 8) define(TCP_FIN, 0x01) define(TCP_SYN, 0x02) define(TCP_RST, 0x04) define(TCP_PSH, 0x08) define(TCP_ACK, 0x10) define(TCP_URG, 0x20) # The TCP states used in the uip_conn->tcpstateflags. define(CLOSED, 0) define(SYN_RCVD, 1) define(SYN_SENT, 2) define(ESTABLISHED, 3) define(FIN_WAIT_1, 4) define(FIN_WAIT_2, 5) define(CLOSING, 6) define(TIME_WAIT, 7) define(LAST_ACK, 8) define(TS_MASK, 15) $0x`'include(ident) : vID $0x`'include(ident) $0x`'include(ident) : main 0x01 : jim dup hex2 cr 1+ sleep1 >jim : halt >halt ifelse(WANT_MON, 1, ` cr &vID @ hex4 cr ') #hi : spew_debug 1 in hex8 cr >spew_debug : accept 0x2a outch in16 inch port(2) or O! >accept 8 out1 sleep1 0 out1 sleep1 0x02 0x05 writereg # clock divide by 2 0x10 0x02 writereg # disable black comp allreg 0x40 ocr 116 632 + debug >cold : flash 1 ocr sleep1 2 ocr sleep1 4 ocr sleep1 8 ocr sleep1 0x10 ocr sleep1 0x20 ocr sleep1 0x40 ocr sleep1 0x80 ocr sleep1 >flash : ocr dup hex2 cr dup 0x1f writereg dup 0x22 writereg 0x25 >writereg 0 : finc dup debug sleep1 16 + 1023 and >finc 0 : diff read1 2dup xor 0xfff and ?ne- >change drop >diff : change nip dup hex8 cr >diff : read1 1 in 1 in 2dup xor ?eq- >_drop 2drop >read1 : spew 1 in hex8 cr >spew # dup 0x1000 and ?ne- >spew dup hex8 cr # rshift1 0x480 + debug >spew >cold : debug port(1) out- drop; : allreg 0x01 : allreg_1 dup showreg 1+ dup 0x2b xor ?ne- >allreg_1 drop; : showreg dup hex2 0x20 outch readreg hex2 >cr : readreg i2c_start 0xaa i2c_byte i2c_byte i2c_start 0xab i2c_byte i2c_receive >i2c_stop : writereg i2c_start 0xaa i2c_byte i2c_byte i2c_byte >i2c_stop >cold : gulu 1 # SCL 0 SDA 0 i2c sleep1 3 # SCL 1 SDA 0 # 0 # SCL 0 SDA 1 i2c sleep1 >gulu : spaces 0x20 outch 1- ?ne >spaces drop; : find1 dup hex2 1 spaces i2c_start i2c_byte i2c_stop hex1 4 spaces ; 0 : felix dup hex8 cr 1 + 2 i2c >felix >cold 0 : groove dup hex8 cr 947 + >groove ifelse(` # Old, unused code : lo16 255 8 lshift 255 +; : !16 dup rshift1 swap and1 ?ne- >!odd : !even dup @ lo16 not and rot lo16 and or swap >! : !odd dup @ lo16 and rot 16 lshift or swap >! : cycle 0xf and 0x500 + dup hex4 cr dup debug 1+ sleep1ms >cycle ') ')