add arp_tb and fixes (able to send a valid ARP request to the model)
This commit is contained in:
parent
08e83af62d
commit
18a7d66b5e
|
@ -17,15 +17,15 @@ class LiteEthARPDepacketizer(LiteEthDepacketizer):
|
|||
eth_mac_description(8),
|
||||
eth_arp_description(8),
|
||||
arp_header,
|
||||
arp_header_length)
|
||||
arp_header_len)
|
||||
|
||||
class LiteEthARPPacketizer(LiteEthDepacketizer):
|
||||
class LiteEthARPPacketizer(LiteEthPacketizer):
|
||||
def __init__(self):
|
||||
LiteEthDepacketizer.__init__(self,
|
||||
LiteEthPacketizer.__init__(self,
|
||||
eth_arp_description(8),
|
||||
eth_mac_description(8),
|
||||
arp_header,
|
||||
arp_header_length)
|
||||
arp_header_len)
|
||||
|
||||
class LiteSATACommandTX(Module):
|
||||
def __init__(self, transport):
|
||||
|
@ -37,15 +37,20 @@ class LiteEthARPTX(Module):
|
|||
self.sink = sink = Sink(_arp_table_description())
|
||||
self.source = Source(eth_mac_description(8))
|
||||
###
|
||||
packetiser = LiteEthARPPacketizer()
|
||||
packetizer = LiteEthARPPacketizer()
|
||||
self.submodules += packetizer
|
||||
source = packetizer.sink
|
||||
|
||||
counter = Counter(max=arp_packet_length)
|
||||
self.submodules += counter
|
||||
|
||||
fsm = FSM(reset_state="IDLE")
|
||||
self.submodules += fsm
|
||||
fsm.act("IDLE",
|
||||
sink.ack.eq(1),
|
||||
If(sink.stb & sink.sop,
|
||||
counter.reset.eq(1),
|
||||
If(sink.stb,
|
||||
sink.ack.eq(0),
|
||||
NextState("SEND")
|
||||
)
|
||||
)
|
||||
|
@ -66,11 +71,20 @@ class LiteEthARPTX(Module):
|
|||
source.destination_ip_address.eq(sink.ip_address)
|
||||
)
|
||||
]
|
||||
fsm.act("SEND_REQUEST",
|
||||
fsm.act("SEND",
|
||||
source.stb.eq(1),
|
||||
source.sop.eq(counter.value == 0),
|
||||
source.eop.eq(counter.value == arp_packet_length-1),
|
||||
Record.connect(packetizer.source, self.source),
|
||||
If(self.source.stb & self.source.eop & self.source.ack,
|
||||
NextState("IDLE")
|
||||
self.source.destination_mac_address.eq(source.destination_mac_address),
|
||||
self.source.source_mac_address.eq(mac_address),
|
||||
self.source.ethernet_type.eq(ethernet_type_arp),
|
||||
If(self.source.stb & self.source.ack,
|
||||
sink.ack.eq(1),
|
||||
counter.ce.eq(1),
|
||||
If(self.source.eop,
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -79,7 +93,7 @@ class LiteEthARPRX(Module):
|
|||
self.sink = Sink(eth_mac_description(8))
|
||||
self.source = source = Source(_arp_table_description())
|
||||
###
|
||||
depacketiser = LiteEthARPDepacketizer()
|
||||
depacketizer = LiteEthARPDepacketizer()
|
||||
self.submodules += depacketizer
|
||||
self.comb += Record.connect(self.sink, depacketizer.sink)
|
||||
sink = depacketizer.source
|
||||
|
@ -118,11 +132,11 @@ class LiteEthARPRX(Module):
|
|||
source.reply.eq(reply),
|
||||
source.request.eq(request)
|
||||
),
|
||||
NextState.eq("TERMINATE")
|
||||
NextState("TERMINATE")
|
||||
),
|
||||
fsm.act("TERMINATE",
|
||||
sink.ack.eq(1),
|
||||
If(sink.stb & sink.source.eop & sink.source.ack,
|
||||
If(sink.stb & sink.eop,
|
||||
NextState("IDLE")
|
||||
)
|
||||
)
|
||||
|
@ -173,9 +187,9 @@ class LiteEthARPTable(Module):
|
|||
fsm.act("CHECK_TABLE",
|
||||
# XXX add a kind of CAM?
|
||||
If(found,
|
||||
NexState.eq("PRESENT_RESPONSE")
|
||||
NextState("PRESENT_RESPONSE")
|
||||
).Else(
|
||||
NextState.eq("SEND_REQUEST")
|
||||
NextState("SEND_REQUEST")
|
||||
)
|
||||
)
|
||||
fsm.act("SEND_REQUEST",
|
||||
|
|
|
@ -46,7 +46,6 @@ class LiteEthDepacketizer(Module):
|
|||
source.sop.eq(0)
|
||||
)
|
||||
self.comb += [
|
||||
source.sop.eq(sop),
|
||||
source.eop.eq(sink.eop),
|
||||
source.data.eq(sink.data),
|
||||
source.error.eq(sink.error),
|
||||
|
|
|
@ -1,11 +1,19 @@
|
|||
from liteeth.common import *
|
||||
import math
|
||||
|
||||
def reverse_bytes(v):
|
||||
n = math.ceil(flen(v)//8)
|
||||
r = []
|
||||
for i in reversed(range(n)):
|
||||
r.append(v[i*8:min((i+1)*8, flen(v))])
|
||||
return Cat(iter(r))
|
||||
|
||||
def _encode_header(h_dict, h_signal, obj):
|
||||
r = []
|
||||
for k, v in sorted(h_dict.items()):
|
||||
start = v.word*32+v.offset
|
||||
start = v.byte*8+v.offset
|
||||
end = start+v.width
|
||||
r.append(h_signal[start:end].eq(getattr(obj, k)))
|
||||
r.append(h_signal[start:end].eq(reverse_bytes(getattr(obj, k))))
|
||||
return r
|
||||
|
||||
class LiteEthPacketizer(Module):
|
||||
|
@ -20,7 +28,7 @@ class LiteEthPacketizer(Module):
|
|||
counter = Counter(max=header_length)
|
||||
self.submodules += counter
|
||||
|
||||
self.comb += header.eq(_encode_header(header_type, header, sink))
|
||||
self.comb += _encode_header(header_type, header, sink)
|
||||
self.sync += [
|
||||
If(load,
|
||||
header_reg.eq(header)
|
||||
|
@ -34,14 +42,15 @@ class LiteEthPacketizer(Module):
|
|||
|
||||
fsm.act("IDLE",
|
||||
sink.ack.eq(1),
|
||||
counter.reset.eq(1),
|
||||
If(sink.stb & sink.sop,
|
||||
load.eq(1),
|
||||
sink.ack.eq(0),
|
||||
source.stb.eq(1),
|
||||
source.sop.eq(1),
|
||||
source.eop.eq(0),
|
||||
source.data.eq(header[:8]),
|
||||
If(source.stb & source.ack,
|
||||
load.eq(1),
|
||||
NextState("SEND_HEADER"),
|
||||
)
|
||||
)
|
||||
|
@ -52,8 +61,9 @@ class LiteEthPacketizer(Module):
|
|||
source.eop.eq(sink.eop),
|
||||
source.data.eq(header_reg[8:16]),
|
||||
If(source.stb & source.ack,
|
||||
sink.ack.eq(1),
|
||||
If(counter == header_length-2,
|
||||
shift.eq(1),
|
||||
counter.ce.eq(1),
|
||||
If(counter.value == header_length-2,
|
||||
NextState("COPY")
|
||||
)
|
||||
)
|
||||
|
@ -61,7 +71,7 @@ class LiteEthPacketizer(Module):
|
|||
fsm.act("COPY",
|
||||
source.stb.eq(sink.stb),
|
||||
source.sop.eq(0),
|
||||
source.eop.eq(sink_eop),
|
||||
source.eop.eq(sink.eop),
|
||||
source.data.eq(sink.data),
|
||||
source.error.eq(sink.error),
|
||||
If(source.stb & source.ack,
|
||||
|
|
|
@ -8,12 +8,12 @@ class LiteEthIPV4Depacketizer(LiteEthDepacketizer):
|
|||
eth_mac_description(8),
|
||||
eth_ipv4_description(8),
|
||||
ipv4_header,
|
||||
ipv4_header_length)
|
||||
ipv4_header_len)
|
||||
|
||||
class LiteEthIPV4Packetizer(LiteEthDepacketizer):
|
||||
class LiteEthIPV4Packetizer(LiteEthPacketizer):
|
||||
def __init__(self):
|
||||
LiteEthDepacketizer.__init__(self,
|
||||
LiteEthPacketizer.__init__(self,
|
||||
eth_ipv4_description(8),
|
||||
eth_mac_description(8),
|
||||
ipv4_header,
|
||||
ipv4_header_length)
|
||||
ipv4_header_len)
|
||||
|
|
|
@ -10,15 +10,15 @@ class LiteEthMACDepacketizer(LiteEthDepacketizer):
|
|||
eth_phy_description(8),
|
||||
eth_mac_description(8),
|
||||
mac_header,
|
||||
mac_header_length)
|
||||
mac_header_len)
|
||||
|
||||
class LiteEthMACPacketizer(LiteEthDepacketizer):
|
||||
class LiteEthMACPacketizer(LiteEthPacketizer):
|
||||
def __init__(self):
|
||||
LiteEthDepacketizer.__init__(self,
|
||||
LiteEthPacketizer.__init__(self,
|
||||
eth_mac_description(8),
|
||||
eth_phy_description(8),
|
||||
mac_header,
|
||||
mac_header_length)
|
||||
mac_header_len)
|
||||
|
||||
class LiteEthMAC(Module, AutoCSR):
|
||||
def __init__(self, phy, dw, interface="mac", endianness="be",
|
||||
|
@ -34,6 +34,7 @@ class LiteEthMAC(Module, AutoCSR):
|
|||
Record.connect(self.core.source, depacketizer.sink)
|
||||
]
|
||||
self.sink, self.source = packetizer.sink, depacketizer.source
|
||||
pass
|
||||
elif interface == "wishbone":
|
||||
self.submodules.interface = wishbone.LiteEthMACWishboneInterface(dw, 2, 2)
|
||||
self.comb += [
|
||||
|
|
|
@ -6,6 +6,10 @@ class LiteEthMACCore(Module, AutoCSR):
|
|||
def __init__(self, phy, dw, endianness="be", with_hw_preamble_crc=True):
|
||||
if dw < phy.dw:
|
||||
raise ValueError("Core data width({}) must be larger than PHY data width({})".format(dw, phy.dw))
|
||||
|
||||
rx_pipeline = [phy]
|
||||
tx_pipeline = [phy]
|
||||
|
||||
# Preamble / CRC (optional)
|
||||
if with_hw_preamble_crc:
|
||||
self._hw_preamble_crc = CSRStatus(reset=1)
|
||||
|
@ -21,18 +25,25 @@ class LiteEthMACCore(Module, AutoCSR):
|
|||
self.submodules += RenameClockDomains(crc32_inserter, "eth_tx")
|
||||
self.submodules += RenameClockDomains(crc32_checker, "eth_rx")
|
||||
|
||||
# Delimiters
|
||||
tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw)
|
||||
rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw)
|
||||
self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
|
||||
self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
|
||||
tx_pipeline += [preamble_inserter, crc32_inserter]
|
||||
rx_pipeline += [preamble_checker, crc32_checker]
|
||||
|
||||
# Converters
|
||||
reverse = endianness == "be"
|
||||
tx_converter = Converter(eth_phy_description(dw), eth_phy_description(phy.dw), reverse=reverse)
|
||||
rx_converter = Converter(eth_phy_description(phy.dw), eth_phy_description(dw), reverse=reverse)
|
||||
self.submodules += RenameClockDomains(tx_converter, "eth_tx")
|
||||
self.submodules += RenameClockDomains(rx_converter, "eth_rx")
|
||||
if dw != phy.dw:
|
||||
# Delimiters
|
||||
tx_last_be = last_be.LiteEthMACTXLastBE(phy.dw)
|
||||
rx_last_be = last_be.LiteEthMACRXLastBE(phy.dw)
|
||||
self.submodules += RenameClockDomains(tx_last_be, "eth_tx")
|
||||
self.submodules += RenameClockDomains(rx_last_be, "eth_rx")
|
||||
|
||||
# Converters
|
||||
reverse = endianness == "be"
|
||||
tx_converter = Converter(eth_phy_description(dw), eth_phy_description(phy.dw), reverse=reverse)
|
||||
rx_converter = Converter(eth_phy_description(phy.dw), eth_phy_description(dw), reverse=reverse)
|
||||
self.submodules += RenameClockDomains(tx_converter, "eth_tx")
|
||||
self.submodules += RenameClockDomains(rx_converter, "eth_rx")
|
||||
|
||||
tx_pipeline += [tx_last_be, tx_converter]
|
||||
rx_pipeline += [rx_last_be, rx_converter]
|
||||
|
||||
# Cross Domain Crossing
|
||||
tx_cdc = AsyncFIFO(eth_phy_description(dw), 4)
|
||||
|
@ -40,14 +51,11 @@ class LiteEthMACCore(Module, AutoCSR):
|
|||
self.submodules += RenameClockDomains(tx_cdc, {"write": "sys", "read": "eth_tx"})
|
||||
self.submodules += RenameClockDomains(rx_cdc, {"write": "eth_rx", "read": "sys"})
|
||||
|
||||
tx_pipeline += [tx_cdc]
|
||||
rx_pipeline += [rx_cdc]
|
||||
|
||||
# Graph
|
||||
if with_hw_preamble_crc:
|
||||
rx_pipeline = [phy, preamble_checker, crc32_checker, rx_last_be, rx_converter, rx_cdc]
|
||||
tx_pipeline = [tx_cdc, tx_converter, tx_last_be, crc32_inserter, preamble_inserter, phy]
|
||||
else:
|
||||
rx_pipeline = [phy, rx_last_be, rx_converter, rx_cdc]
|
||||
tx_pipeline = [tx_cdc, tx_converter, tx_last_be, phy]
|
||||
self.submodules.tx_pipeline = Pipeline(*reversed(tx_pipeline))
|
||||
self.submodules.rx_pipeline = Pipeline(*rx_pipeline)
|
||||
self.submodules.tx_pipeline = Pipeline(*tx_pipeline)
|
||||
|
||||
self.sink, self.source = self.tx_pipeline.sink, self.rx_pipeline.source
|
||||
|
|
|
@ -12,3 +12,6 @@ mac_core_tb:
|
|||
|
||||
mac_wishbone_tb:
|
||||
$(CMD) mac_wishbone_tb.py
|
||||
|
||||
arp_tb:
|
||||
$(CMD) arp_tb.py
|
||||
|
|
|
@ -0,0 +1,54 @@
|
|||
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.mac import LiteEthMAC
|
||||
from liteeth.arp import LiteEthARP
|
||||
|
||||
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.core = LiteEthMAC(phy=self.phy_model, dw=8, with_hw_preamble_crc=True)
|
||||
self.submodules.arp = LiteEthARP(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()),
|
||||
]
|
||||
|
||||
self.comb += [
|
||||
Record.connect(self.arp.source, self.core.sink),
|
||||
Record.connect(self.core.source, self.arp.sink)
|
||||
]
|
||||
|
||||
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.arp.table.request.ip_address = 0x12345678
|
||||
selfp.arp.table.request.stb = 1
|
||||
|
||||
if __name__ == "__main__":
|
||||
run_simulation(TB(), ncycles=256, vcd_name="my.vcd", keep_files=True)
|
|
@ -4,6 +4,8 @@ from liteeth.common import *
|
|||
from liteeth.mac.common import *
|
||||
from liteeth.test.common import *
|
||||
|
||||
from liteeth.test.model import mac
|
||||
|
||||
def print_arp(s):
|
||||
print_with_prefix(s, "[ARP]")
|
||||
|
||||
|
@ -39,10 +41,10 @@ class ARPPacket(Packet):
|
|||
return r
|
||||
|
||||
class ARP(Module):
|
||||
def __init__(self, mac, ip_address, mac_address, debug=False):
|
||||
def __init__(self, mac, mac_address, ip_address, debug=False):
|
||||
self.mac = mac
|
||||
self.mac_address = mac_address
|
||||
self.ip_address = ip_address
|
||||
self.mac_address = mac_addres
|
||||
self.debug = debug
|
||||
self.tx_packets = []
|
||||
self.tx_packet = ARPPacket()
|
||||
|
@ -53,22 +55,26 @@ class ARP(Module):
|
|||
self.mac.set_arp_callback(self.callback)
|
||||
|
||||
def send(self, packet):
|
||||
packet.encode()
|
||||
if self.debug:
|
||||
print_arp(">>>>>>>>")
|
||||
print_arp(packet)
|
||||
packet.encode()
|
||||
self.mac.send(MACPacket(packet))
|
||||
mac_packet = mac.MACPacket(packet)
|
||||
mac_packet.destination_mac_address = packet.destination_mac_address
|
||||
mac_packet.source_mac_address = packet.source_mac_address
|
||||
mac_packet.ethernet_type = ethernet_type_arp
|
||||
self.mac.send(mac_packet)
|
||||
|
||||
def callback(self, packet):
|
||||
packet = ARPPacket(datas)
|
||||
packet = ARPPacket(packet)
|
||||
packet.decode()
|
||||
if self.debug:
|
||||
print_arp("<<<<<<<<")
|
||||
print_arp(packet)
|
||||
self.process_packet()
|
||||
self.process(packet)
|
||||
|
||||
def process(self, packet):
|
||||
if len(packet) != arp_packet_length-arp_header_length:
|
||||
if len(packet) != arp_packet_length-arp_header_len:
|
||||
raise ValueError
|
||||
if packet.hardware_type != arp_hwtype_ethernet:
|
||||
raise ValueError
|
||||
|
@ -85,9 +91,10 @@ class ARP(Module):
|
|||
|
||||
def process_request(self, request):
|
||||
if request.destination_ip_address == self.ip_address:
|
||||
reply = ARPPacket([0]*(arp_packet_length-arp_header_length))
|
||||
reply = ARPPacket([0]*(arp_packet_length-arp_header_len))
|
||||
reply.hardware_type = arp_hwtype_ethernet
|
||||
reply.protocol_type = arp_proto_ip
|
||||
reply.operation = arp_opcode_reply
|
||||
reply.hardware_address_length = 6
|
||||
reply.protocol_address_length = 4
|
||||
reply.source_mac_address = self.mac_address
|
||||
|
@ -100,9 +107,10 @@ class ARP(Module):
|
|||
self.table[reply.source_ip_address] = reply.source_mac_address
|
||||
|
||||
def request(self, ip_address):
|
||||
request = ARPPacket([0]*(arp_packet_length-arp_header_length))
|
||||
request = ARPPacket([0]*(arp_packet_length-arp_header_len))
|
||||
request.hardware_type = arp_hwtype_ethernet
|
||||
request.protocol_type = arp_proto_ip
|
||||
request.operation = arp_opcode_request
|
||||
request.hardware_address_length = 6
|
||||
request.protocol_address_length = 4
|
||||
request.source_mac_address = self.mac_address
|
||||
|
|
|
@ -118,10 +118,10 @@ class MAC(Module):
|
|||
if self.loopback:
|
||||
self.send(packet)
|
||||
else:
|
||||
if self.ethernet_type == ethernet_type_ip:
|
||||
if packet.ethernet_type == ethernet_type_ip:
|
||||
if self.ip_callback is not None:
|
||||
self.ip_callback(packet)
|
||||
elif self.ethernet_type == ethernet_type_arp:
|
||||
elif packet.ethernet_type == ethernet_type_arp:
|
||||
if self.arp_callback is not None:
|
||||
self.arp_callback(packet)
|
||||
else:
|
||||
|
|
|
@ -8,12 +8,12 @@ class LiteEthUDPDepacketizer(LiteEthDepacketizer):
|
|||
eth_ipv4_description(8),
|
||||
eth_udp_description(8),
|
||||
udp_header,
|
||||
udp_header_length)
|
||||
udp_header_len)
|
||||
|
||||
class LiteEthUDPPacketizer(LiteEthDepacketizer):
|
||||
class LiteEthUDPPacketizer(LiteEthPacketizer):
|
||||
def __init__(self):
|
||||
LiteEthDepacketizer.__init__(self,
|
||||
LiteEthPacketizer.__init__(self,
|
||||
eth_udp_description(8),
|
||||
eth_ipv4_description(8),
|
||||
udp_header,
|
||||
udp_header_length)
|
||||
udp_header_len)
|
||||
|
|
Loading…
Reference in New Issue