add arp_tb and fixes (able to send a valid ARP request to the model)

This commit is contained in:
Florent Kermarrec 2015-01-30 00:03:16 +01:00
parent 08e83af62d
commit 18a7d66b5e
11 changed files with 160 additions and 63 deletions

View File

@ -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",

View File

@ -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),

View File

@ -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,

View File

@ -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)

View File

@ -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 += [

View File

@ -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

View File

@ -12,3 +12,6 @@ mac_core_tb:
mac_wishbone_tb:
$(CMD) mac_wishbone_tb.py
arp_tb:
$(CMD) arp_tb.py

54
liteeth/test/arp_tb.py Normal file
View File

@ -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)

View File

@ -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

View File

@ -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:

View File

@ -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)