From 1d447f2ae1e60fba9d8574317b316b653accd2e2 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Fri, 30 Jan 2015 13:23:06 +0100 Subject: [PATCH] ip: add skeleton --- liteeth/__init__.py | 22 +++++----- liteeth/arp/__init__.py | 10 +---- liteeth/common.py | 9 +++++ liteeth/ip/__init__.py | 90 +++++++++++++++++++++++++++++++++++++++++ liteeth/test/Makefile | 3 ++ liteeth/test/ip_tb.py | 48 ++++++++++++++++++++++ 6 files changed, 161 insertions(+), 21 deletions(-) create mode 100644 liteeth/test/ip_tb.py diff --git a/liteeth/__init__.py b/liteeth/__init__.py index 50b5c0f3b..38f150cef 100644 --- a/liteeth/__init__.py +++ b/liteeth/__init__.py @@ -2,25 +2,23 @@ from liteeth.common import * from liteeth.generic.arbiter import Arbiter from liteeth.generic.dispatcher import Dispatcher from liteeth.mac import LiteEthMAC +from liteeth.arp import LiteEthARP +from liteeth.ip import LiteEthIP class LiteEthIPStack(Module, AutoCSR): - def __init__(self, phy, - mac_address= 0x12345678abcd, - ip_address="192.168.0.10"): + def __init__(self, phy, mac_address, ip_address): self.phy = phy self.submodules.mac = mac = LiteEthMAC(phy, 8, interface="mac", with_hw_preamble_crc=True) self.submodules.arp = arp = LiteEthARP(mac_address, ip_address) - self.submodules.ip = ip = LiteEthMACIP() + self.submodules.ip = ip = LiteEthIP(ip_address, arp.table) # MAC dispatch - self.submodules.mac_dispatcher = mac_dispatcher = Dispatcher(mac.source, [arp.sink, ip.sink], one_hot=True) + self.submodules.mac_dispatcher = Dispatcher(mac.source, [arp.sink, ip.sink], one_hot=True) self.comb += \ - Case(mac.source.eth_type, { - ethernet_type_arp : [mac_dispatcher.sel.eq(1)], - ethernet_type_ip : [mac_dispatcher.sel.eq(2)], - "default" : [mac_dispatcher.sel.eq(0)], + Case(mac.source.ethernet_type, { + ethernet_type_arp : [self.mac_dispatcher.sel.eq(1)], + ethernet_type_ip : [self.mac_dispatcher.sel.eq(2)], + "default" : [self.mac_dispatcher.sel.eq(0)], }) # MAC arbitrate - self.submodules.mac_arbiter = mac_arbiter = Arbiter([arp.source, ip.source], mac.sink) - - + self.submodules.mac_arbiter = Arbiter([arp.source, ip.source], mac.sink) diff --git a/liteeth/arp/__init__.py b/liteeth/arp/__init__.py index 4e5af42e6..9d6551d2c 100644 --- a/liteeth/arp/__init__.py +++ b/liteeth/arp/__init__.py @@ -96,6 +96,7 @@ class LiteEthARPRX(Module): fsm.act("IDLE", sink.ack.eq(1), If(sink.stb & sink.sop, + sink.ack.eq(0), NextState("CHECK") ) ) @@ -134,15 +135,6 @@ class LiteEthARPRX(Module): ) ) -arp_table_request_layout = [ - ("ip_address", 32) -] - -arp_table_response_layout = [ - ("failed", 1), - ("mac_address", 48) -] - class LiteEthARPTable(Module): def __init__(self): self.sink = sink = Sink(_arp_table_layout) # from arp_rx diff --git a/liteeth/common.py b/liteeth/common.py index 42e3ea0fb..d1ce2cc2b 100644 --- a/liteeth/common.py +++ b/liteeth/common.py @@ -114,6 +114,15 @@ def eth_arp_description(dw): ] return EndpointDescription(layout, packetized=True) +arp_table_request_layout = [ + ("ip_address", 32) +] + +arp_table_response_layout = [ + ("failed", 1), + ("mac_address", 48) +] + def eth_ipv4_description(dw): layout = _layout_from_header(ipv4_header) + [ ("data", dw), diff --git a/liteeth/ip/__init__.py b/liteeth/ip/__init__.py index 55030397b..1aa47367b 100644 --- a/liteeth/ip/__init__.py +++ b/liteeth/ip/__init__.py @@ -17,3 +17,93 @@ class LiteEthIPV4Packetizer(LiteEthPacketizer): eth_mac_description(8), ipv4_header, ipv4_header_len) + +class LiteEthIPTX(Module): + def __init__(self, ip_address, arp_table): + self.sink = sink = Sink(eth_ipv4_description(8)) + self.source = Source(eth_mac_description(8)) + ### + packetizer = LiteEthIPV4Packetizer() + self.submodules += packetizer + source = packetizer.sink + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("SEND_MAC_ADDRESS_REQUEST") + ) + ) + fsm.act("SEND_MAC_ADDRESS_REQUEST", + arp_table.request.stb.eq(1), + arp_table.request.ip_address.eq(sink.destination_ip_address), + If(arp_table.request.stb & arp_table.request.ack, + NextState("WAIT_MAC_ADDRESS_RESPONSE") + ) + ) + fsm.act("WAIT_MAC_ADDRESS_RESPONSE", + # XXX add timeout + If(arp_table.response.stb, + # XXX manage failed + NextState("SEND") + ) + ) + fsm.act("SEND", + Record.connect(packetizer.source, self.source), + # XXX compute check sum + + # XXX add timeout + If(arp_table.response.stb, + # XXX manage failed + NextState("SEND") + ) + ) + +class LiteEthIPRX(Module): + def __init__(self, ip_address): + self.sink = Sink(eth_mac_description(8)) + self.source = source = Source(eth_ipv4_description(8)) + ### + depacketizer = LiteEthIPV4Depacketizer() + self.submodules += depacketizer + self.comb += Record.connect(self.sink, depacketizer.sink) + sink = depacketizer.source + + fsm = FSM(reset_state="IDLE") + self.submodules += fsm + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("CHECK") + ) + ) + valid = Signal() + self.comb += valid.eq(1) # XXX FIXME + fsm.act("CHECK", + If(valid, + NextState("PRESENT") + ).Else( + NextState("DROP") + ) + ), + fsm.act("PRESENT", + Record.connect(sink, source), + If(source.stb & source.eop & source.ack, + NextState("IDLE") + ) + ) + fsm.act("DROP", + sink.ack.eq(1), + If(source.stb & source.eop & source.ack, + NextState("IDLE") + ) + ) + +class LiteEthIP(Module): + def __init__(self, ip_address, arp_table): + self.submodules.tx = LiteEthIPTX(ip_address, arp_table) + self.submodules.rx = LiteEthIPRX(ip_address) + self.sink, self.source = self.rx.sink, self.tx.source diff --git a/liteeth/test/Makefile b/liteeth/test/Makefile index f7cfac631..8cdf05c1e 100644 --- a/liteeth/test/Makefile +++ b/liteeth/test/Makefile @@ -15,3 +15,6 @@ mac_wishbone_tb: arp_tb: $(CMD) arp_tb.py + +ip_tb: + $(CMD) ip_tb.py diff --git a/liteeth/test/ip_tb.py b/liteeth/test/ip_tb.py new file mode 100644 index 000000000..fa751b600 --- /dev/null +++ b/liteeth/test/ip_tb.py @@ -0,0 +1,48 @@ +from migen.fhdl.std import * +from migen.bus import wishbone +from migen.bus.transactions import * +from migen.sim.generic import run_simulation + +from liteeth.common import * +from liteeth import LiteEthIPStack + +from liteeth.test.common import * +from liteeth.test.model import phy, mac, arp + +ip_address = 0x12345678 +mac_address = 0x12345678abcd + +class TB(Module): + def __init__(self): + self.submodules.phy_model = phy.PHY(8, debug=True) + self.submodules.mac_model = mac.MAC(self.phy_model, debug=True, loopback=False) + self.submodules.arp_model = arp.ARP(self.mac_model, mac_address, ip_address, debug=True) + + self.submodules.ip = LiteEthIPStack(self.phy_model, mac_address, ip_address) + + # use sys_clk for each clock_domain + self.clock_domains.cd_eth_rx = ClockDomain() + self.clock_domains.cd_eth_tx = ClockDomain() + self.comb += [ + self.cd_eth_rx.clk.eq(ClockSignal()), + self.cd_eth_rx.rst.eq(ResetSignal()), + self.cd_eth_tx.clk.eq(ClockSignal()), + self.cd_eth_tx.rst.eq(ResetSignal()), + ] + + def gen_simulation(self, selfp): + selfp.cd_eth_rx.rst = 1 + selfp.cd_eth_tx.rst = 1 + yield + selfp.cd_eth_rx.rst = 0 + selfp.cd_eth_tx.rst = 0 + + for i in range(100): + yield + + #selfp.ip.sink.stb = 1 + #selfp.ip.sink.destination_ip_address = 0x12345678 + #selfp.ip.sink.source_ip_address = ip_address + +if __name__ == "__main__": + run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)