from liteeth.mac import LiteEthMAC
class LiteEthIPStack(Module, AutoCSR):
- def __init__(self, phy):
+ def __init__(self, phy,
+ mac_address= 0x12345678abcd,
+ ip_address="192.168.0.10"):
self.phy = phy
self.submodules.mac = mac = LiteEthMAC(phy, 8, interface="mac", with_hw_preamble_crc=True)
- self.submodules.arp = arp = LiteEthARP()
+ self.submodules.arp = arp = LiteEthARP(mac_address, ip_address)
self.submodules.ip = ip = LiteEthMACIP()
# MAC dispatch
self.submodules.mac_dispatcher = mac_dispatcher = Dispatcher(mac.source, [arp.sink, ip.sink], one_hot=True)
- self.comb += [
- If(mac.source.eth_type == ethernet_type_arp,
- mac_dispatcher.sel.eq(1)
- ).Elif(mac.source.eth_type == ethernet_type_ip,
- mac_dispatcher.sel.eq(2)
- )
- ]
+ 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)],
+ })
# MAC arbitrate
self.submodules.mac_arbiter = mac_arbiter = Arbiter([arp.source, ip.source], mac.sink)
from liteeth.generic.depacketizer import LiteEthDepacketizer
from liteeth.generic.packetizer import LiteEthPacketizer
+def _arp_table_description():
+ layout = [
+ ("reply", 1),
+ ("request", 1),
+ ("ip_address", 32),
+ ("mac_address", 48)
+ ]
+ return EndpointDescription(layout, packetized=False)
+
class LiteEthARPDepacketizer(LiteEthDepacketizer):
def __init__(self):
LiteEthDepacketizer.__init__(self,
eth_mac_description(8),
arp_header,
arp_header_length)
+
+class LiteSATACommandTX(Module):
+ def __init__(self, transport):
+ self.sink = sink = Sink(command_tx_description(32))
+
+
+class LiteEthARPTX(Module):
+ def __init__(self, mac_address, ip_address):
+ self.sink = sink = Sink(_arp_table_description())
+ self.source = Source(eth_mac_description(8))
+ ###
+ packetiser = LiteEthARPPacketizer()
+ 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,
+ NextState("SEND")
+ )
+ )
+ self.comb += [
+ source.hardware_type.eq(arp_hwtype_ethernet),
+ source.protocol_type.eq(arp_proto_ip),
+ source.hardware_address_length.eq(6),
+ source.protocol_address_length.eq(4),
+ source.source_mac_address.eq(mac_address),
+ source.source_ip_address.eq(ip_address),
+ If(sink.reply,
+ source.operation.eq(arp_opcode_reply),
+ source.destination_mac_address.eq(sink.mac_address),
+ source.destination_ip_address.eq(sink.ip_address)
+ ).Elif(sink.request,
+ source.operation.eq(arp_opcode_request),
+ source.destination_mac_address.eq(0xffffffffffff),
+ source.destination_ip_address.eq(sink.ip_address)
+ )
+ ]
+ fsm.act("SEND_REQUEST",
+ source.stb.eq(1),
+ Record.connect(packetizer.source, self.source),
+ If(self.source.stb & self.source.eop & self.source.ack,
+ NextState("IDLE")
+ )
+ )
+
+class LiteEthARPRX(Module):
+ def __init__(self, mac_address, ip_address):
+ self.sink = Sink(eth_mac_description(8))
+ self.source = source = Source(_arp_table_description())
+ ###
+ depacketiser = LiteEthARPDepacketizer()
+ 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,
+ NextState("CHECK")
+ )
+ )
+ valid = Signal()
+ self.comb += valid.eq(
+ sink.stb &
+ (sink.hardware_type == arp_hwtype_ethernet) &
+ (sink.protocol_type == arp_proto_ip) &
+ (sink.hardware_address_length == 6) &
+ (sink.protocol_address_length == 4) &
+ (sink.destination_ip_address == ip_address)
+ )
+ reply = Signal()
+ request = Signal()
+ self.comb += Case(sink.operation, {
+ arp_opcode_request : [request.eq(1)],
+ arp_opcode_reply : [reply.eq(1)],
+ "default" : []
+ })
+ self.comb += [
+ source.ip_address.eq(sink.source_ip_address),
+ source.mac_address.eq(sink.source_mac_address)
+ ]
+ fsm.act("CHECK",
+ If(valid,
+ source.stb.eq(1),
+ source.reply.eq(reply),
+ source.request.eq(request)
+ ),
+ NextState.eq("TERMINATE")
+ ),
+ fsm.act("TERMINATE",
+ sink.ack.eq(1),
+ If(sink.stb & sink.source.eop & sink.source.ack,
+ NextState("IDLE")
+ )
+ )
+
+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_description()) # from arp_rx
+ self.source = source = Source(_arp_table_description()) # to arp_tx
+
+ # Request/Response interface
+ self.request = request = Sink(arp_table_request_layout)
+ self.response = response = Source(arp_table_response_layout)
+
+ fsm = FSM(reset_state="IDLE")
+ self.submodules += fsm
+ fsm.act("IDLE",
+ If(sink.stb & sink.request,
+ NextState("SEND_REPLY")
+ ).Elif(sink.stb & sink.reply,
+ NextState("UPDATE_TABLE")
+ ).Elif(request.stb,
+ NextState("CHECK_TABLE")
+ )
+ )
+ fsm.act("SEND_REPLY",
+ source.stb.eq(1),
+ source.reply.eq(1),
+ source.ip_address.eq(sink.ip_address),
+ If(source.ack,
+ NextState("IDLE")
+ )
+ )
+ fsm.act("UPDATE_TABLE",
+ # XXX update memory
+ NextState("IDLE")
+ )
+ found = Signal()
+ fsm.act("CHECK_TABLE",
+ # XXX add a kind of CAM?
+ If(found,
+ NexState.eq("PRESENT_RESPONSE")
+ ).Else(
+ NextState.eq("SEND_REQUEST")
+ )
+ )
+ fsm.act("SEND_REQUEST",
+ source.stb.eq(1),
+ source.request.eq(1),
+ source.ip_address.eq(request.ip_address),
+ If(source.ack,
+ NextState("IDLE")
+ )
+ )
+ fsm.act("PRESENT_RESPONSE",
+ response.stb.eq(1),
+ response.failed.eq(0), # XXX add timeout to trigger failed
+ response.mac_address.eq(0x12345678abcd), # XXX get mac address from table
+ If(response.ack,
+ NextState("IDLE")
+ )
+ )
+
+class LiteEthARP(Module):
+ def __init__(self, mac_address, ip_address):
+ self.submodules.tx = LiteEthARPTX(mac_address, ip_address)
+ self.submodules.rx = LiteEthARPRX(mac_address, ip_address)
+ self.submodules.table = LiteEthARPTable()
+ self.comb += [
+ Record.connect(self.rx.source, self.table.sink),
+ Record.connect(self.table.source, self.tx.sink)
+ ]
+ self.sink, self.source = self.rx.sink, self.tx.source
+ self.request, self.response = self.table.request, self.table.response