From: Florent Kermarrec Date: Thu, 5 Feb 2015 23:38:56 +0000 (+0100) Subject: reorganize core (to add crossbar to ip) X-Git-Tag: 24jan2021_ls180~2604^2~73 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=81343e99615876bea9e588e85bacdb8c82d9a248;p=litex.git reorganize core (to add crossbar to ip) --- diff --git a/liteeth/core/arp.py b/liteeth/core/arp.py deleted file mode 100644 index d7fd26de..00000000 --- a/liteeth/core/arp.py +++ /dev/null @@ -1,265 +0,0 @@ -from liteeth.common import * -from liteeth.generic.depacketizer import LiteEthDepacketizer -from liteeth.generic.packetizer import LiteEthPacketizer - -_arp_table_layout = [ - ("reply", 1), - ("request", 1), - ("ip_address", 32), - ("mac_address", 48) - ] - -class LiteEthARPDepacketizer(LiteEthDepacketizer): - def __init__(self): - LiteEthDepacketizer.__init__(self, - eth_mac_description(8), - eth_arp_description(8), - arp_header, - arp_header_len) - -class LiteEthARPPacketizer(LiteEthPacketizer): - def __init__(self): - LiteEthPacketizer.__init__(self, - eth_arp_description(8), - eth_mac_description(8), - arp_header, - arp_header_len) - -class LiteEthARPTX(Module): - def __init__(self, mac_address, ip_address): - self.sink = sink = Sink(_arp_table_layout) - self.source = Source(eth_mac_description(8)) - ### - packetizer = LiteEthARPPacketizer() - self.submodules += packetizer - source = packetizer.sink - - counter = Counter(max=max(arp_header_len, eth_min_len)) - self.submodules += counter - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - counter.reset.eq(1), - If(sink.stb, - sink.ack.eq(0), - NextState("SEND") - ) - ) - self.comb += [ - source.sop.eq(counter.value == 0), - source.eop.eq(counter.value == max(arp_header_len, eth_min_len)-1), - source.hwtype.eq(arp_hwtype_ethernet), - source.proto.eq(arp_proto_ip), - source.hwsize.eq(6), - source.protosize.eq(4), - source.sender_mac.eq(mac_address), - source.sender_ip.eq(ip_address), - If(sink.reply, - source.opcode.eq(arp_opcode_reply), - source.target_mac.eq(sink.mac_address), - source.target_ip.eq(sink.ip_address) - ).Elif(sink.request, - source.opcode.eq(arp_opcode_request), - source.target_mac.eq(0xffffffffffff), - source.target_ip.eq(sink.ip_address) - ) - ] - fsm.act("SEND", - source.stb.eq(1), - Record.connect(packetizer.source, self.source), - self.source.target_mac.eq(source.target_mac), - self.source.sender_mac.eq(mac_address), - self.source.ethernet_type.eq(ethernet_type_arp), - If(self.source.stb & self.source.ack, - sink.ack.eq(source.eop), - counter.ce.eq(1), - If(self.source.eop, - 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_layout) - ### - depacketizer = LiteEthARPDepacketizer() - self.submodules += depacketizer - self.comb += Record.connect(self.sink, depacketizer.sink) - sink = depacketizer.source - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(sink.stb & sink.sop, - sink.ack.eq(0), - NextState("CHECK") - ) - ) - valid = Signal() - self.comb += valid.eq( - sink.stb & - (sink.hwtype == arp_hwtype_ethernet) & - (sink.proto == arp_proto_ip) & - (sink.hwsize == 6) & - (sink.protosize == 4) & - (sink.target_ip == ip_address) - ) - reply = Signal() - request = Signal() - self.comb += Case(sink.opcode, { - arp_opcode_request : [request.eq(1)], - arp_opcode_reply : [reply.eq(1)], - "default" : [] - }) - self.comb += [ - source.ip_address.eq(sink.sender_ip), - source.mac_address.eq(sink.sender_mac) - ] - fsm.act("CHECK", - If(valid, - source.stb.eq(1), - source.reply.eq(reply), - source.request.eq(request) - ), - NextState("TERMINATE") - ), - fsm.act("TERMINATE", - sink.ack.eq(1), - If(sink.stb & sink.eop, - NextState("IDLE") - ) - ) - -class LiteEthARPTable(Module): - def __init__(self, clk_freq, max_requests=8): - self.sink = sink = Sink(_arp_table_layout) # from arp_rx - self.source = source = Source(_arp_table_layout) # to arp_tx - - # Request/Response interface - self.request = request = Sink(arp_table_request_layout) - self.response = response = Source(arp_table_response_layout) - ### - request_timeout = Timeout(clk_freq//10) - request_counter = Counter(max=max_requests) - request_pending = FlipFlop() - request_ip_address = FlipFlop(32) - self.submodules += request_timeout, request_counter, request_pending, request_ip_address - self.comb += [ - request_timeout.ce.eq(request_pending.q), - request_pending.d.eq(1), - request_ip_address.d.eq(request.ip_address) - ] - - # Note: Only store 1 IP/MAC couple, can be improved with a real - # table in the future to improve performance when packet are - # targeting multiple destinations. - update = Signal() - cached_valid = Signal() - cached_ip_address = Signal(32) - cached_mac_address = Signal(48) - cached_timeout = Timeout(clk_freq*10) - self.submodules += cached_timeout - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - # Note: for simplicicy, if APR table is busy response from arp_rx - # is lost. This is compensated by the protocol (retry) - If(sink.stb & sink.request, - NextState("SEND_REPLY") - ).Elif(sink.stb & sink.reply & request_pending.q, - NextState("UPDATE_TABLE"), - ).Elif(request_counter.value == max_requests-1, - NextState("PRESENT_RESPONSE") - ).Elif(request.stb | (request_pending.q & request_timeout.reached), - 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", - request_pending.reset.eq(1), - update.eq(1), - NextState("CHECK_TABLE") - ) - self.sync += [ - If(update, - cached_valid.eq(1), - cached_ip_address.eq(sink.ip_address), - cached_mac_address.eq(sink.mac_address), - cached_timeout.reset.eq(1) - ).Else( - cached_timeout.ce.eq(1), - If(cached_timeout.reached, - cached_valid.eq(0) - ) - ) - ] - found = Signal() - fsm.act("CHECK_TABLE", - If(cached_valid, - If(request_ip_address.q == cached_ip_address, - request_ip_address.reset.eq(1), - NextState("PRESENT_RESPONSE"), - ).Elif(request.ip_address == cached_ip_address, - request.ack.eq(request.stb), - NextState("PRESENT_RESPONSE"), - ).Else( - request_ip_address.ce.eq(request.stb), - NextState("SEND_REQUEST") - ) - ).Else( - request_ip_address.ce.eq(request.stb), - NextState("SEND_REQUEST") - ) - ) - fsm.act("SEND_REQUEST", - source.stb.eq(1), - source.request.eq(1), - source.ip_address.eq(request_ip_address.q), - If(source.ack, - request_timeout.reset.eq(1), - request_counter.reset.eq(request.stb), - request_counter.ce.eq(1), - request_pending.ce.eq(1), - request.ack.eq(1), - NextState("IDLE") - ) - ) - self.comb += [ - If(request_counter == max_requests-1, - response.failed.eq(1), - request_counter.reset.eq(1), - request_pending.reset.eq(1) - ), - response.mac_address.eq(cached_mac_address) - ] - fsm.act("PRESENT_RESPONSE", - response.stb.eq(1), - If(response.ack, - NextState("IDLE") - ) - ) - -class LiteEthARP(Module): - def __init__(self, mac, mac_address, ip_address, clk_freq): - self.submodules.tx = LiteEthARPTX(mac_address, ip_address) - self.submodules.rx = LiteEthARPRX(mac_address, ip_address) - self.submodules.table = LiteEthARPTable(clk_freq) - self.comb += [ - Record.connect(self.rx.source, self.table.sink), - Record.connect(self.table.source, self.tx.sink) - ] - mac_port = mac.crossbar.get_port(ethernet_type_arp) - self.comb += [ - Record.connect(self.tx.source, mac_port.sink), - Record.connect(mac_port.source, self.rx.sink) - ] diff --git a/liteeth/core/arp/__init__.py b/liteeth/core/arp/__init__.py new file mode 100644 index 00000000..d7fd26de --- /dev/null +++ b/liteeth/core/arp/__init__.py @@ -0,0 +1,265 @@ +from liteeth.common import * +from liteeth.generic.depacketizer import LiteEthDepacketizer +from liteeth.generic.packetizer import LiteEthPacketizer + +_arp_table_layout = [ + ("reply", 1), + ("request", 1), + ("ip_address", 32), + ("mac_address", 48) + ] + +class LiteEthARPDepacketizer(LiteEthDepacketizer): + def __init__(self): + LiteEthDepacketizer.__init__(self, + eth_mac_description(8), + eth_arp_description(8), + arp_header, + arp_header_len) + +class LiteEthARPPacketizer(LiteEthPacketizer): + def __init__(self): + LiteEthPacketizer.__init__(self, + eth_arp_description(8), + eth_mac_description(8), + arp_header, + arp_header_len) + +class LiteEthARPTX(Module): + def __init__(self, mac_address, ip_address): + self.sink = sink = Sink(_arp_table_layout) + self.source = Source(eth_mac_description(8)) + ### + packetizer = LiteEthARPPacketizer() + self.submodules += packetizer + source = packetizer.sink + + counter = Counter(max=max(arp_header_len, eth_min_len)) + self.submodules += counter + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + sink.ack.eq(1), + counter.reset.eq(1), + If(sink.stb, + sink.ack.eq(0), + NextState("SEND") + ) + ) + self.comb += [ + source.sop.eq(counter.value == 0), + source.eop.eq(counter.value == max(arp_header_len, eth_min_len)-1), + source.hwtype.eq(arp_hwtype_ethernet), + source.proto.eq(arp_proto_ip), + source.hwsize.eq(6), + source.protosize.eq(4), + source.sender_mac.eq(mac_address), + source.sender_ip.eq(ip_address), + If(sink.reply, + source.opcode.eq(arp_opcode_reply), + source.target_mac.eq(sink.mac_address), + source.target_ip.eq(sink.ip_address) + ).Elif(sink.request, + source.opcode.eq(arp_opcode_request), + source.target_mac.eq(0xffffffffffff), + source.target_ip.eq(sink.ip_address) + ) + ] + fsm.act("SEND", + source.stb.eq(1), + Record.connect(packetizer.source, self.source), + self.source.target_mac.eq(source.target_mac), + self.source.sender_mac.eq(mac_address), + self.source.ethernet_type.eq(ethernet_type_arp), + If(self.source.stb & self.source.ack, + sink.ack.eq(source.eop), + counter.ce.eq(1), + If(self.source.eop, + 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_layout) + ### + depacketizer = LiteEthARPDepacketizer() + self.submodules += depacketizer + self.comb += Record.connect(self.sink, depacketizer.sink) + sink = depacketizer.source + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("CHECK") + ) + ) + valid = Signal() + self.comb += valid.eq( + sink.stb & + (sink.hwtype == arp_hwtype_ethernet) & + (sink.proto == arp_proto_ip) & + (sink.hwsize == 6) & + (sink.protosize == 4) & + (sink.target_ip == ip_address) + ) + reply = Signal() + request = Signal() + self.comb += Case(sink.opcode, { + arp_opcode_request : [request.eq(1)], + arp_opcode_reply : [reply.eq(1)], + "default" : [] + }) + self.comb += [ + source.ip_address.eq(sink.sender_ip), + source.mac_address.eq(sink.sender_mac) + ] + fsm.act("CHECK", + If(valid, + source.stb.eq(1), + source.reply.eq(reply), + source.request.eq(request) + ), + NextState("TERMINATE") + ), + fsm.act("TERMINATE", + sink.ack.eq(1), + If(sink.stb & sink.eop, + NextState("IDLE") + ) + ) + +class LiteEthARPTable(Module): + def __init__(self, clk_freq, max_requests=8): + self.sink = sink = Sink(_arp_table_layout) # from arp_rx + self.source = source = Source(_arp_table_layout) # to arp_tx + + # Request/Response interface + self.request = request = Sink(arp_table_request_layout) + self.response = response = Source(arp_table_response_layout) + ### + request_timeout = Timeout(clk_freq//10) + request_counter = Counter(max=max_requests) + request_pending = FlipFlop() + request_ip_address = FlipFlop(32) + self.submodules += request_timeout, request_counter, request_pending, request_ip_address + self.comb += [ + request_timeout.ce.eq(request_pending.q), + request_pending.d.eq(1), + request_ip_address.d.eq(request.ip_address) + ] + + # Note: Only store 1 IP/MAC couple, can be improved with a real + # table in the future to improve performance when packet are + # targeting multiple destinations. + update = Signal() + cached_valid = Signal() + cached_ip_address = Signal(32) + cached_mac_address = Signal(48) + cached_timeout = Timeout(clk_freq*10) + self.submodules += cached_timeout + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + # Note: for simplicicy, if APR table is busy response from arp_rx + # is lost. This is compensated by the protocol (retry) + If(sink.stb & sink.request, + NextState("SEND_REPLY") + ).Elif(sink.stb & sink.reply & request_pending.q, + NextState("UPDATE_TABLE"), + ).Elif(request_counter.value == max_requests-1, + NextState("PRESENT_RESPONSE") + ).Elif(request.stb | (request_pending.q & request_timeout.reached), + 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", + request_pending.reset.eq(1), + update.eq(1), + NextState("CHECK_TABLE") + ) + self.sync += [ + If(update, + cached_valid.eq(1), + cached_ip_address.eq(sink.ip_address), + cached_mac_address.eq(sink.mac_address), + cached_timeout.reset.eq(1) + ).Else( + cached_timeout.ce.eq(1), + If(cached_timeout.reached, + cached_valid.eq(0) + ) + ) + ] + found = Signal() + fsm.act("CHECK_TABLE", + If(cached_valid, + If(request_ip_address.q == cached_ip_address, + request_ip_address.reset.eq(1), + NextState("PRESENT_RESPONSE"), + ).Elif(request.ip_address == cached_ip_address, + request.ack.eq(request.stb), + NextState("PRESENT_RESPONSE"), + ).Else( + request_ip_address.ce.eq(request.stb), + NextState("SEND_REQUEST") + ) + ).Else( + request_ip_address.ce.eq(request.stb), + NextState("SEND_REQUEST") + ) + ) + fsm.act("SEND_REQUEST", + source.stb.eq(1), + source.request.eq(1), + source.ip_address.eq(request_ip_address.q), + If(source.ack, + request_timeout.reset.eq(1), + request_counter.reset.eq(request.stb), + request_counter.ce.eq(1), + request_pending.ce.eq(1), + request.ack.eq(1), + NextState("IDLE") + ) + ) + self.comb += [ + If(request_counter == max_requests-1, + response.failed.eq(1), + request_counter.reset.eq(1), + request_pending.reset.eq(1) + ), + response.mac_address.eq(cached_mac_address) + ] + fsm.act("PRESENT_RESPONSE", + response.stb.eq(1), + If(response.ack, + NextState("IDLE") + ) + ) + +class LiteEthARP(Module): + def __init__(self, mac, mac_address, ip_address, clk_freq): + self.submodules.tx = LiteEthARPTX(mac_address, ip_address) + self.submodules.rx = LiteEthARPRX(mac_address, ip_address) + self.submodules.table = LiteEthARPTable(clk_freq) + self.comb += [ + Record.connect(self.rx.source, self.table.sink), + Record.connect(self.table.source, self.tx.sink) + ] + mac_port = mac.crossbar.get_port(ethernet_type_arp) + self.comb += [ + Record.connect(self.tx.source, mac_port.sink), + Record.connect(mac_port.source, self.rx.sink) + ] diff --git a/liteeth/core/ip.py b/liteeth/core/ip.py deleted file mode 100644 index 04be1ce7..00000000 --- a/liteeth/core/ip.py +++ /dev/null @@ -1,188 +0,0 @@ -from liteeth.common import * -from liteeth.generic.depacketizer import LiteEthDepacketizer -from liteeth.generic.packetizer import LiteEthPacketizer - -class LiteEthIPV4Depacketizer(LiteEthDepacketizer): - def __init__(self): - LiteEthDepacketizer.__init__(self, - eth_mac_description(8), - eth_ipv4_description(8), - ipv4_header, - ipv4_header_len) - -class LiteEthIPV4Packetizer(LiteEthPacketizer): - def __init__(self): - LiteEthPacketizer.__init__(self, - eth_ipv4_description(8), - eth_mac_description(8), - ipv4_header, - ipv4_header_len) - -class LiteEthIPV4Checksum(Module): - def __init__(self, skip_header=False): - self.header = Signal(ipv4_header_len*8) - self.value = Signal(16) - - s = Signal(17) - r = Signal(17) - for i in range(ipv4_header_len//2): - if skip_header and i == 5: - pass - else: - s_next = Signal(17) - r_next = Signal(17) - self.comb += [ - s_next.eq(r + self.header[i*16:(i+1)*16]), - r_next.eq(Cat(s_next[:16]+s_next[16], Signal())) - ] - s, r = s_next, r_next - self.comb += self.value.eq(~Cat(r[8:16], r[:8])) - -class LiteEthIPTX(Module): - def __init__(self, mac_address, ip_address, arp_table): - self.sink = Sink(eth_ipv4_user_description(8)) - self.source = Source(eth_mac_description(8)) - self.target_unreachable = Signal() - ### - packetizer = LiteEthIPV4Packetizer() - self.submodules += packetizer - self.comb += [ - packetizer.sink.stb.eq(self.sink.stb), - packetizer.sink.sop.eq(self.sink.sop), - packetizer.sink.eop.eq(self.sink.eop), - self.sink.ack.eq(packetizer.sink.ack), - packetizer.sink.target_ip.eq(self.sink.ip_address), - packetizer.sink.protocol.eq(self.sink.protocol), - packetizer.sink.total_length.eq(self.sink.length + (0x5*4)), - packetizer.sink.version.eq(0x4), # ipv4 - packetizer.sink.ihl.eq(0x5), # 20 bytes - packetizer.sink.identification.eq(0), - packetizer.sink.ttl.eq(0x80), - packetizer.sink.sender_ip.eq(ip_address), - packetizer.sink.data.eq(self.sink.data) - ] - sink = packetizer.source - - checksum = LiteEthIPV4Checksum(skip_header=True) - self.submodules += checksum - self.comb += [ - checksum.header.eq(packetizer.header), - packetizer.sink.checksum.eq(checksum.value) - ] - - target_mac = Signal(48) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(sink.stb & sink.sop, - sink.ack.eq(0), - NextState("SEND_MAC_ADDRESS_REQUEST") - ) - ) - self.comb += arp_table.request.ip_address.eq(self.sink.ip_address) - fsm.act("SEND_MAC_ADDRESS_REQUEST", - arp_table.request.stb.eq(1), - If(arp_table.request.stb & arp_table.request.ack, - NextState("WAIT_MAC_ADDRESS_RESPONSE") - ) - ) - fsm.act("WAIT_MAC_ADDRESS_RESPONSE", - If(arp_table.response.stb, - arp_table.response.ack.eq(1), - If(arp_table.response.failed, - self.target_unreachable.eq(1), - NextState("DROP"), - ).Else( - NextState("SEND") - ) - ) - ) - self.sync += If(arp_table.response.stb, target_mac.eq(arp_table.response.mac_address)) - fsm.act("SEND", - Record.connect(packetizer.source, self.source), - self.source.ethernet_type.eq(ethernet_type_ip), - self.source.target_mac.eq(target_mac), - self.source.sender_mac.eq(mac_address), - If(self.source.stb & self.source.eop & self.source.ack, - NextState("IDLE") - ) - ) - fsm.act("DROP", - packetizer.source.ack.eq(1), - If(packetizer.source.stb & packetizer.source.eop & packetizer.source.ack, - NextState("IDLE") - ) - ) - -class LiteEthIPRX(Module): - def __init__(self, mac_address, ip_address): - self.sink = Sink(eth_mac_description(8)) - self.source = source = Source(eth_ipv4_user_description(8)) - ### - depacketizer = LiteEthIPV4Depacketizer() - self.submodules += depacketizer - self.comb += Record.connect(self.sink, depacketizer.sink) - sink = depacketizer.source - - checksum = LiteEthIPV4Checksum(skip_header=False) - self.submodules += checksum - self.comb += checksum.header.eq(depacketizer.header) - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(sink.stb & sink.sop, - sink.ack.eq(0), - NextState("CHECK") - ) - ) - valid = Signal() - self.comb += valid.eq( - sink.stb & - (sink.target_ip == ip_address) & - (sink.version == 0x4) & - (sink.ihl == 0x5) & - (checksum.value == 0) - ) - - fsm.act("CHECK", - If(valid, - NextState("PRESENT") - ).Else( - NextState("DROP") - ) - ) - self.comb += [ - source.sop.eq(sink.sop), - source.eop.eq(sink.eop), - source.length.eq(sink.total_length - (sink.ihl*4)), - source.protocol.eq(sink.protocol), - source.ip_address.eq(sink.target_ip), - source.data.eq(sink.data), - source.error.eq(sink.error) - ] - fsm.act("PRESENT", - source.stb.eq(sink.stb), - sink.ack.eq(source.ack), - If(source.stb & source.eop & source.ack, - NextState("IDLE") - ) - ) - fsm.act("DROP", - sink.ack.eq(1), - If(sink.stb & sink.eop & sink.ack, - NextState("IDLE") - ) - ) - -class LiteEthIP(Module): - def __init__(self, mac, mac_address, ip_address, arp_table): - self.submodules.tx = LiteEthIPTX(mac_address, ip_address, arp_table) - self.submodules.rx = LiteEthIPRX(mac_address, ip_address) - mac_port = mac.crossbar.get_port(ethernet_type_ip) - self.comb += [ - Record.connect(self.tx.source, mac_port.sink), - Record.connect(mac_port.source, self.rx.sink) - ] - self.sink, self.source = self.tx.sink, self.rx.source diff --git a/liteeth/core/ip/__init__.py b/liteeth/core/ip/__init__.py new file mode 100644 index 00000000..04be1ce7 --- /dev/null +++ b/liteeth/core/ip/__init__.py @@ -0,0 +1,188 @@ +from liteeth.common import * +from liteeth.generic.depacketizer import LiteEthDepacketizer +from liteeth.generic.packetizer import LiteEthPacketizer + +class LiteEthIPV4Depacketizer(LiteEthDepacketizer): + def __init__(self): + LiteEthDepacketizer.__init__(self, + eth_mac_description(8), + eth_ipv4_description(8), + ipv4_header, + ipv4_header_len) + +class LiteEthIPV4Packetizer(LiteEthPacketizer): + def __init__(self): + LiteEthPacketizer.__init__(self, + eth_ipv4_description(8), + eth_mac_description(8), + ipv4_header, + ipv4_header_len) + +class LiteEthIPV4Checksum(Module): + def __init__(self, skip_header=False): + self.header = Signal(ipv4_header_len*8) + self.value = Signal(16) + + s = Signal(17) + r = Signal(17) + for i in range(ipv4_header_len//2): + if skip_header and i == 5: + pass + else: + s_next = Signal(17) + r_next = Signal(17) + self.comb += [ + s_next.eq(r + self.header[i*16:(i+1)*16]), + r_next.eq(Cat(s_next[:16]+s_next[16], Signal())) + ] + s, r = s_next, r_next + self.comb += self.value.eq(~Cat(r[8:16], r[:8])) + +class LiteEthIPTX(Module): + def __init__(self, mac_address, ip_address, arp_table): + self.sink = Sink(eth_ipv4_user_description(8)) + self.source = Source(eth_mac_description(8)) + self.target_unreachable = Signal() + ### + packetizer = LiteEthIPV4Packetizer() + self.submodules += packetizer + self.comb += [ + packetizer.sink.stb.eq(self.sink.stb), + packetizer.sink.sop.eq(self.sink.sop), + packetizer.sink.eop.eq(self.sink.eop), + self.sink.ack.eq(packetizer.sink.ack), + packetizer.sink.target_ip.eq(self.sink.ip_address), + packetizer.sink.protocol.eq(self.sink.protocol), + packetizer.sink.total_length.eq(self.sink.length + (0x5*4)), + packetizer.sink.version.eq(0x4), # ipv4 + packetizer.sink.ihl.eq(0x5), # 20 bytes + packetizer.sink.identification.eq(0), + packetizer.sink.ttl.eq(0x80), + packetizer.sink.sender_ip.eq(ip_address), + packetizer.sink.data.eq(self.sink.data) + ] + sink = packetizer.source + + checksum = LiteEthIPV4Checksum(skip_header=True) + self.submodules += checksum + self.comb += [ + checksum.header.eq(packetizer.header), + packetizer.sink.checksum.eq(checksum.value) + ] + + target_mac = Signal(48) + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("SEND_MAC_ADDRESS_REQUEST") + ) + ) + self.comb += arp_table.request.ip_address.eq(self.sink.ip_address) + fsm.act("SEND_MAC_ADDRESS_REQUEST", + arp_table.request.stb.eq(1), + If(arp_table.request.stb & arp_table.request.ack, + NextState("WAIT_MAC_ADDRESS_RESPONSE") + ) + ) + fsm.act("WAIT_MAC_ADDRESS_RESPONSE", + If(arp_table.response.stb, + arp_table.response.ack.eq(1), + If(arp_table.response.failed, + self.target_unreachable.eq(1), + NextState("DROP"), + ).Else( + NextState("SEND") + ) + ) + ) + self.sync += If(arp_table.response.stb, target_mac.eq(arp_table.response.mac_address)) + fsm.act("SEND", + Record.connect(packetizer.source, self.source), + self.source.ethernet_type.eq(ethernet_type_ip), + self.source.target_mac.eq(target_mac), + self.source.sender_mac.eq(mac_address), + If(self.source.stb & self.source.eop & self.source.ack, + NextState("IDLE") + ) + ) + fsm.act("DROP", + packetizer.source.ack.eq(1), + If(packetizer.source.stb & packetizer.source.eop & packetizer.source.ack, + NextState("IDLE") + ) + ) + +class LiteEthIPRX(Module): + def __init__(self, mac_address, ip_address): + self.sink = Sink(eth_mac_description(8)) + self.source = source = Source(eth_ipv4_user_description(8)) + ### + depacketizer = LiteEthIPV4Depacketizer() + self.submodules += depacketizer + self.comb += Record.connect(self.sink, depacketizer.sink) + sink = depacketizer.source + + checksum = LiteEthIPV4Checksum(skip_header=False) + self.submodules += checksum + self.comb += checksum.header.eq(depacketizer.header) + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("CHECK") + ) + ) + valid = Signal() + self.comb += valid.eq( + sink.stb & + (sink.target_ip == ip_address) & + (sink.version == 0x4) & + (sink.ihl == 0x5) & + (checksum.value == 0) + ) + + fsm.act("CHECK", + If(valid, + NextState("PRESENT") + ).Else( + NextState("DROP") + ) + ) + self.comb += [ + source.sop.eq(sink.sop), + source.eop.eq(sink.eop), + source.length.eq(sink.total_length - (sink.ihl*4)), + source.protocol.eq(sink.protocol), + source.ip_address.eq(sink.target_ip), + source.data.eq(sink.data), + source.error.eq(sink.error) + ] + fsm.act("PRESENT", + source.stb.eq(sink.stb), + sink.ack.eq(source.ack), + If(source.stb & source.eop & source.ack, + NextState("IDLE") + ) + ) + fsm.act("DROP", + sink.ack.eq(1), + If(sink.stb & sink.eop & sink.ack, + NextState("IDLE") + ) + ) + +class LiteEthIP(Module): + def __init__(self, mac, mac_address, ip_address, arp_table): + self.submodules.tx = LiteEthIPTX(mac_address, ip_address, arp_table) + self.submodules.rx = LiteEthIPRX(mac_address, ip_address) + mac_port = mac.crossbar.get_port(ethernet_type_ip) + self.comb += [ + Record.connect(self.tx.source, mac_port.sink), + Record.connect(mac_port.source, self.rx.sink) + ] + self.sink, self.source = self.tx.sink, self.rx.source diff --git a/liteeth/core/udp.py b/liteeth/core/udp.py deleted file mode 100644 index 7a6c503f..00000000 --- a/liteeth/core/udp.py +++ /dev/null @@ -1,123 +0,0 @@ -from liteeth.common import * -from liteeth.generic.depacketizer import LiteEthDepacketizer -from liteeth.generic.packetizer import LiteEthPacketizer - -class LiteEthUDPDepacketizer(LiteEthDepacketizer): - def __init__(self): - LiteEthDepacketizer.__init__(self, - eth_ipv4_user_description(8), - eth_udp_description(8), - udp_header, - udp_header_len) - -class LiteEthUDPPacketizer(LiteEthPacketizer): - def __init__(self): - LiteEthPacketizer.__init__(self, - eth_udp_description(8), - eth_ipv4_user_description(8), - udp_header, - udp_header_len) - -class LiteEthUDPTX(Module): - def __init__(self, ip_address): - self.sink = Sink(eth_udp_user_description(8)) - self.source = Source(eth_ipv4_user_description(8)) - ### - packetizer = LiteEthUDPPacketizer() - self.submodules += packetizer - self.comb += [ - packetizer.sink.stb.eq(self.sink.stb), - packetizer.sink.sop.eq(self.sink.sop), - packetizer.sink.eop.eq(self.sink.eop), - self.sink.ack.eq(packetizer.sink.ack), - packetizer.sink.src_port.eq(self.sink.src_port), - packetizer.sink.dst_port.eq(self.sink.dst_port), - packetizer.sink.length.eq(self.sink.length + udp_header_len), - packetizer.sink.checksum.eq(0), - packetizer.sink.data.eq(self.sink.data) - ] - sink = packetizer.source - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(sink.stb & sink.sop, - sink.ack.eq(0), - NextState("SEND") - ) - ) - fsm.act("SEND", - Record.connect(packetizer.source, self.source), - self.source.length.eq(packetizer.sink.length + ipv4_header_len), - self.source.protocol.eq(udp_protocol), - self.source.ip_address.eq(self.sink.ip_address), - If(self.source.stb & self.source.eop & self.source.ack, - NextState("IDLE") - ) - ) - -class LiteEthUDPRX(Module): - def __init__(self, ip_address): - self.sink = Sink(eth_ipv4_user_description(8)) - self.source = source = Source(eth_udp_user_description(8)) - ### - depacketizer = LiteEthUDPDepacketizer() - self.submodules += depacketizer - self.comb += Record.connect(self.sink, depacketizer.sink) - sink = depacketizer.source - - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - sink.ack.eq(1), - If(sink.stb & sink.sop, - sink.ack.eq(0), - NextState("CHECK") - ) - ) - valid = Signal() - self.comb += valid.eq( - sink.stb & - (self.sink.protocol == udp_protocol) & - (self.sink.ip_address == ip_address) - ) - - fsm.act("CHECK", - If(valid, - NextState("PRESENT") - ).Else( - NextState("DROP") - ) - ) - self.comb += [ - source.sop.eq(sink.sop), - source.eop.eq(sink.eop), - source.src_port.eq(sink.src_port), - source.dst_port.eq(sink.dst_port), - source.ip_address.eq(0), - source.length.eq(sink.length - udp_header_len), - source.data.eq(sink.data), - source.error.eq(sink.error) - ] - fsm.act("PRESENT", - source.stb.eq(sink.stb), - sink.ack.eq(source.ack), - 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 LiteEthUDP(Module): - def __init__(self, ip, ip_address): - self.submodules.tx = LiteEthUDPTX(ip_address) - self.submodules.rx = LiteEthUDPRX(ip_address) - self.comb += [ - Record.connect(self.tx.source, ip.sink), - Record.connect(ip.source, self.rx.sink) - ] - self.sink, self.source = self.tx.sink, self.rx.source diff --git a/liteeth/core/udp/__init__.py b/liteeth/core/udp/__init__.py new file mode 100644 index 00000000..7a6c503f --- /dev/null +++ b/liteeth/core/udp/__init__.py @@ -0,0 +1,123 @@ +from liteeth.common import * +from liteeth.generic.depacketizer import LiteEthDepacketizer +from liteeth.generic.packetizer import LiteEthPacketizer + +class LiteEthUDPDepacketizer(LiteEthDepacketizer): + def __init__(self): + LiteEthDepacketizer.__init__(self, + eth_ipv4_user_description(8), + eth_udp_description(8), + udp_header, + udp_header_len) + +class LiteEthUDPPacketizer(LiteEthPacketizer): + def __init__(self): + LiteEthPacketizer.__init__(self, + eth_udp_description(8), + eth_ipv4_user_description(8), + udp_header, + udp_header_len) + +class LiteEthUDPTX(Module): + def __init__(self, ip_address): + self.sink = Sink(eth_udp_user_description(8)) + self.source = Source(eth_ipv4_user_description(8)) + ### + packetizer = LiteEthUDPPacketizer() + self.submodules += packetizer + self.comb += [ + packetizer.sink.stb.eq(self.sink.stb), + packetizer.sink.sop.eq(self.sink.sop), + packetizer.sink.eop.eq(self.sink.eop), + self.sink.ack.eq(packetizer.sink.ack), + packetizer.sink.src_port.eq(self.sink.src_port), + packetizer.sink.dst_port.eq(self.sink.dst_port), + packetizer.sink.length.eq(self.sink.length + udp_header_len), + packetizer.sink.checksum.eq(0), + packetizer.sink.data.eq(self.sink.data) + ] + sink = packetizer.source + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("SEND") + ) + ) + fsm.act("SEND", + Record.connect(packetizer.source, self.source), + self.source.length.eq(packetizer.sink.length + ipv4_header_len), + self.source.protocol.eq(udp_protocol), + self.source.ip_address.eq(self.sink.ip_address), + If(self.source.stb & self.source.eop & self.source.ack, + NextState("IDLE") + ) + ) + +class LiteEthUDPRX(Module): + def __init__(self, ip_address): + self.sink = Sink(eth_ipv4_user_description(8)) + self.source = source = Source(eth_udp_user_description(8)) + ### + depacketizer = LiteEthUDPDepacketizer() + self.submodules += depacketizer + self.comb += Record.connect(self.sink, depacketizer.sink) + sink = depacketizer.source + + self.submodules.fsm = fsm = FSM(reset_state="IDLE") + fsm.act("IDLE", + sink.ack.eq(1), + If(sink.stb & sink.sop, + sink.ack.eq(0), + NextState("CHECK") + ) + ) + valid = Signal() + self.comb += valid.eq( + sink.stb & + (self.sink.protocol == udp_protocol) & + (self.sink.ip_address == ip_address) + ) + + fsm.act("CHECK", + If(valid, + NextState("PRESENT") + ).Else( + NextState("DROP") + ) + ) + self.comb += [ + source.sop.eq(sink.sop), + source.eop.eq(sink.eop), + source.src_port.eq(sink.src_port), + source.dst_port.eq(sink.dst_port), + source.ip_address.eq(0), + source.length.eq(sink.length - udp_header_len), + source.data.eq(sink.data), + source.error.eq(sink.error) + ] + fsm.act("PRESENT", + source.stb.eq(sink.stb), + sink.ack.eq(source.ack), + 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 LiteEthUDP(Module): + def __init__(self, ip, ip_address): + self.submodules.tx = LiteEthUDPTX(ip_address) + self.submodules.rx = LiteEthUDPRX(ip_address) + self.comb += [ + Record.connect(self.tx.source, ip.sink), + Record.connect(ip.source, self.rx.sink) + ] + self.sink, self.source = self.tx.sink, self.rx.source