add tty over udp (will need mac to insert padding)
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Sat, 21 Feb 2015 19:42:31 +0000 (20:42 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Sat, 21 Feb 2015 20:26:52 +0000 (21:26 +0100)
liteeth/common.py
liteeth/core/tty/__init__.py [new file with mode: 0644]
targets/tty.py [new file with mode: 0644]
targets/udp.py
test/Makefile
test/test_tty.py [new file with mode: 0644]

index eff3b01b7830b27e4e6a4cd4e349d54c9d690b21..3d00ad2faa595a46b2fd44a2d6138e66cf99aac0 100644 (file)
@@ -278,3 +278,7 @@ def eth_etherbone_mmap_description(dw):
                ("data", dw)
        ]
        return EndpointDescription(payload_layout, param_layout, packetized=True)
+
+def eth_tty_description(dw):
+       payload_layout = [("data", dw)]
+       return EndpointDescription(payload_layout, packetized=False)
diff --git a/liteeth/core/tty/__init__.py b/liteeth/core/tty/__init__.py
new file mode 100644 (file)
index 0000000..a0102c4
--- /dev/null
@@ -0,0 +1,97 @@
+from liteeth.common import *
+from liteeth.generic import *
+
+class LiteEthTTYTX(Module):
+       def __init__(self, ip_address, udp_port, fifo_depth=None):
+               self.sink = sink = Sink(eth_tty_description(8))
+               self.source = source = Source(eth_udp_user_description(8))
+               ###
+               if fifo_depth is None:
+                       self.comb += [
+                               source.stb.eq(sink.stb),
+                               source.sop.eq(1),
+                               source.eop.eq(1),
+                               source.length.eq(1),
+                               source.data.eq(sink.data),
+                               sink.ack.eq(source.ack)
+                       ]
+               else:
+                       self.submodules.fifo = fifo = SyncFIFO([("data", 8)], fifo_depth)
+                       self.comb += Record.connect(sink, fifo.sink)
+
+                       self.submodules.level = level = FlipFlop(max=fifo_depth)
+                       self.comb += level.d.eq(fifo.fifo.level)
+
+                       self.submodules.counter = counter = Counter(max=fifo_depth)
+
+                       self.submodules.fsm = fsm = FSM(reset_state="IDLE")
+                       fsm.act("IDLE",
+                               If(fifo.source.stb,
+                                       level.ce.eq(1),
+                                       counter.reset.eq(1),
+                                       NextState("SEND")
+                               )
+                       )
+                       fsm.act("SEND",
+                               source.stb.eq(fifo.source.stb),
+                               source.sop.eq(counter.value == 0),
+                               If(level.q == 0,
+                                       source.eop.eq(1),
+                               ).Else(
+                                       source.eop.eq(counter.value == (level.q-1)),
+                               ),
+                               source.src_port.eq(udp_port),
+                               source.dst_port.eq(udp_port),
+                               source.ip_address.eq(ip_address),
+                               If(level.q == 0,
+                                       source.length.eq(1),
+                               ).Else(
+                                       source.length.eq(level.q),
+                               ),
+                               source.data.eq(fifo.source.data),
+                               fifo.source.ack.eq(source.ack),
+                               If(source.stb & source.ack,
+                                       counter.ce.eq(1),
+                                       If(source.eop,
+                                               NextState("IDLE")
+                                       )
+                               )
+                       )
+
+class LiteEthTTYRX(Module):
+       def __init__(self, ip_address, udp_port, fifo_depth=None):
+               self.sink = sink = Sink(eth_udp_user_description(8))
+               self.source = source = Source(eth_tty_description(8))
+               ###
+               valid = Signal()
+               self.comb += valid.eq(
+                       (sink.ip_address == ip_address) &
+                       (sink.dst_port == udp_port)
+               )
+               if fifo_depth is None:
+                       self.comb += [
+                               source.stb.eq(sink.stb & valid),
+                               source.data.eq(sink.data),
+                               sink.ack.eq(source.ack)
+                       ]
+               else:
+                       self.submodules.fifo = fifo = SyncFIFO([("data", 8)], fifo_depth)
+                       self.comb += [
+                               fifo.sink.stb.eq(sink.stb & valid),
+                               fifo.sink.data.eq(sink.data),
+                               sink.ack.eq(fifo.sink.ack),
+                               Record.connect(fifo.source, source)
+                       ]
+
+class LiteEthTTY(Module):
+       def __init__(self, udp, ip_address, udp_port,
+                       rx_fifo_depth=64,
+                       tx_fifo_depth=64):
+               self.submodules.tx = tx = LiteEthTTYTX(ip_address, udp_port, tx_fifo_depth)
+               self.submodules.rx = rx = LiteEthTTYRX(ip_address, udp_port, rx_fifo_depth)
+               udp_port = udp.crossbar.get_port(udp_port, dw=8)
+               self.comb += [
+                       Record.connect(tx.source, udp_port.sink),
+                       Record.connect(udp_port.source, rx.sink)
+               ]
+               self.sink, self.source = self.tx.sink, self.rx.source
diff --git a/targets/tty.py b/targets/tty.py
new file mode 100644 (file)
index 0000000..28cda9d
--- /dev/null
@@ -0,0 +1,42 @@
+from litescope.common import *
+from litescope.frontend.la import LiteScopeLA
+from litescope.core.port import LiteScopeTerm
+
+from liteeth.common import *
+from liteeth.generic import *
+
+from targets.base import BaseSoC
+from liteeth.core.tty import LiteEthTTY
+
+class TTYSoC(BaseSoC):
+       default_platform = "kc705"
+       def __init__(self, platform):
+               BaseSoC.__init__(self, platform,
+                       mac_address=0x10e2d5000000,
+                       ip_address="192.168.1.40")
+               self.submodules.tty = LiteEthTTY(self.core.udp, convert_ip("192.168.1.12"), 10000)
+               self.comb += Record.connect(self.tty.source, self.tty.sink)
+
+class TTYSoCDevel(TTYSoC):
+       csr_map = {
+               "la":                   20
+       }
+       csr_map.update(TTYSoC.csr_map)
+       def __init__(self, platform):
+               TTYSoC.__init__(self, platform)
+               debug = (
+                       self.tty.sink.stb,
+                       self.tty.sink.ack,
+                       self.tty.sink.data,
+
+                       self.tty.source.stb,
+                       self.tty.source.ack,
+                       self.tty.source.data
+               )
+               self.submodules.la = LiteScopeLA(debug, 4096)
+               self.la.trigger.add_port(LiteScopeTerm(self.la.dw))
+
+       def do_exit(self, vns):
+               self.la.export(vns, "test/la.csv")
+
+default_subtarget = TTYSoC
index 3ec5b65ac0ed1efeccd51cdb718670044524e6d0..9ce15ce53eb1060bb0cf3f07ba218a3edeea8701 100644 (file)
@@ -6,7 +6,6 @@ from liteeth.common import *
 from liteeth.generic import *
 
 from targets.base import BaseSoC
-from liteeth.core import LiteEthUDPIPCore
 
 class UDPSoC(BaseSoC):
        default_platform = "kc705"
index 0556486b3168418475c78834825235e3fd7132b0..0dd57189adc72b494c0fb28955a7d9bac71caf69 100644 (file)
@@ -14,3 +14,7 @@ test_udp:
 
 test_etherbone:
        $(CMD) test_etherbone.py
+
+test_tty:
+       $(CMD) test_tty.py
+
diff --git a/test/test_tty.py b/test/test_tty.py
new file mode 100644 (file)
index 0000000..af0e5d0
--- /dev/null
@@ -0,0 +1,35 @@
+import socket
+import threading
+
+test_message = "LiteEth virtual TTY Hello world"
+
+def test(fpga_ip, udp_port, test_message):
+       tx_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+       rx_sock  = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+       rx_sock.bind(("", udp_port))
+
+       def receive():
+               data, addr = rx_sock.recvfrom(8192)
+               rx_packet = []
+               for byte in data:
+                       rx_packet.append(int(byte))
+               for e in rx_packet:
+                       print(chr(e))
+
+       def send():
+               tx_sock.sendto(bytes(test_message, "utf-8"), (fpga_ip, udp_port))
+
+       receive_thread = threading.Thread(target=receive)
+       receive_thread.start()
+
+       send_thread = threading.Thread(target=send)
+       send_thread.start()
+
+       try:
+               send_thread.join(10)
+               receive_thread.join(0.1)
+       except KeyboardInterrupt:
+               pass
+
+test_message = "LiteEth virtual TTY Hello world\n"
+test("192.168.1.40", 10000, test_message)