From 65294a5577c458dc04ad5191fdcd72adb97a78c4 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Sat, 21 Feb 2015 20:42:31 +0100 Subject: [PATCH] add tty over udp (will need mac to insert padding) --- liteeth/common.py | 4 ++ liteeth/core/tty/__init__.py | 97 ++++++++++++++++++++++++++++++++++++ targets/tty.py | 42 ++++++++++++++++ targets/udp.py | 1 - test/Makefile | 4 ++ test/test_tty.py | 35 +++++++++++++ 6 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 liteeth/core/tty/__init__.py create mode 100644 targets/tty.py create mode 100644 test/test_tty.py diff --git a/liteeth/common.py b/liteeth/common.py index eff3b01b7..3d00ad2fa 100644 --- a/liteeth/common.py +++ b/liteeth/common.py @@ -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 index 000000000..a0102c4f2 --- /dev/null +++ b/liteeth/core/tty/__init__.py @@ -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 index 000000000..28cda9d8f --- /dev/null +++ b/targets/tty.py @@ -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 diff --git a/targets/udp.py b/targets/udp.py index 3ec5b65ac..9ce15ce53 100644 --- a/targets/udp.py +++ b/targets/udp.py @@ -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" diff --git a/test/Makefile b/test/Makefile index 0556486b3..0dd57189a 100644 --- a/test/Makefile +++ b/test/Makefile @@ -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 index 000000000..af0e5d087 --- /dev/null +++ b/test/test_tty.py @@ -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)