mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
improve mac model (add header encoding/decoding)
This commit is contained in:
parent
cb9ec51de8
commit
96b08a0cc7
2 changed files with 97 additions and 47 deletions
|
@ -11,15 +11,15 @@ from liteeth.test.model import phy, mac
|
||||||
|
|
||||||
class TB(Module):
|
class TB(Module):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.submodules.hostphy = phy.PHY(8, debug=False)
|
self.submodules.phy_model = phy.PHY(8, debug=False)
|
||||||
self.submodules.hostmac = mac.MAC(self.hostphy, debug=False, loopback=True)
|
self.submodules.mac_model = mac.MAC(self.phy_model, debug=True, loopback=True)
|
||||||
self.submodules.core = LiteEthMACCore(phy=self.hostphy, dw=32, with_hw_preamble_crc=True)
|
self.submodules.core = LiteEthMACCore(phy=self.phy_model, dw=8, with_hw_preamble_crc=True)
|
||||||
|
|
||||||
self.submodules.streamer = PacketStreamer(eth_phy_description(32), last_be=1)
|
self.submodules.streamer = PacketStreamer(eth_phy_description(8), last_be=1)
|
||||||
self.submodules.streamer_randomizer = AckRandomizer(eth_phy_description(32), level=50)
|
self.submodules.streamer_randomizer = AckRandomizer(eth_phy_description(8), level=50)
|
||||||
|
|
||||||
self.submodules.logger_randomizer = AckRandomizer(eth_phy_description(32), level=50)
|
self.submodules.logger_randomizer = AckRandomizer(eth_phy_description(8), level=50)
|
||||||
self.submodules.logger = PacketLogger(eth_phy_description(32))
|
self.submodules.logger = PacketLogger(eth_phy_description(8))
|
||||||
|
|
||||||
# use sys_clk for each clock_domain
|
# use sys_clk for each clock_domain
|
||||||
self.clock_domains.cd_eth_rx = ClockDomain()
|
self.clock_domains.cd_eth_rx = ClockDomain()
|
||||||
|
@ -46,12 +46,16 @@ class TB(Module):
|
||||||
selfp.cd_eth_tx.rst = 0
|
selfp.cd_eth_tx.rst = 0
|
||||||
|
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
streamer_packet = Packet([i for i in range(64)])
|
packet = mac.MACPacket([i for i in range(64)])
|
||||||
yield from self.streamer.send(streamer_packet)
|
packet.destination_mac_address = 0x010203040506
|
||||||
|
packet.source_mac_address = 0x090A0B0C0C0D
|
||||||
|
packet.ethernet_type = 0x0800
|
||||||
|
packet.encode_header()
|
||||||
|
yield from self.streamer.send(packet)
|
||||||
yield from self.logger.receive()
|
yield from self.logger.receive()
|
||||||
|
|
||||||
# check results
|
# check results
|
||||||
s, l, e = check(streamer_packet, self.logger.packet)
|
s, l, e = check(packet, self.logger.packet)
|
||||||
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
|
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
|
|
|
@ -1,30 +1,42 @@
|
||||||
import binascii
|
import math, binascii
|
||||||
|
|
||||||
from liteeth.common import *
|
from liteeth.common import *
|
||||||
from liteeth.mac.common import *
|
from liteeth.mac.common import *
|
||||||
from liteeth.test.common import *
|
from liteeth.test.common import *
|
||||||
|
|
||||||
|
def split_bytes(v, n):
|
||||||
|
r = []
|
||||||
|
r_bytes = v.to_bytes(n, byteorder="little")
|
||||||
|
for byte in r_bytes:
|
||||||
|
r.append(int(byte))
|
||||||
|
return r
|
||||||
|
|
||||||
|
def merge_bytes(b):
|
||||||
|
return int.from_bytes(bytes(b), "little")
|
||||||
|
|
||||||
|
def get_field_data(field, datas):
|
||||||
|
v = merge_bytes(datas[field.byte:field.byte+math.ceil(field.width/8)])
|
||||||
|
return (v >> field.offset) & (2**field.width-1)
|
||||||
|
|
||||||
def print_mac(s):
|
def print_mac(s):
|
||||||
print_with_prefix(s, "[MAC]")
|
print_with_prefix(s, "[MAC]")
|
||||||
|
|
||||||
preamble = [0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5]
|
preamble = split_bytes(eth_preamble, 8)
|
||||||
|
|
||||||
def crc32(l):
|
def crc32(l):
|
||||||
crc = []
|
crc = []
|
||||||
crc_bytes = binascii.crc32(bytes(l)).to_bytes(4, byteorder="little")
|
crc_bytes = split_bytes(binascii.crc32(bytes(l)), 4)
|
||||||
for byte in crc_bytes:
|
for byte in crc_bytes:
|
||||||
crc.append(int(byte))
|
crc.append(int(byte))
|
||||||
return crc
|
return crc
|
||||||
|
|
||||||
# MAC model
|
# MAC model
|
||||||
class MACPacket(list):
|
class MACPacket(Packet):
|
||||||
def __init__(self, init=[]):
|
def __init__(self, init=[]):
|
||||||
self.ongoing = False
|
Packet.__init__(self, init)
|
||||||
self.done = False
|
self.preamble_error = False
|
||||||
for byte in init:
|
self.crc_error = False
|
||||||
self.append(byte)
|
|
||||||
|
|
||||||
class MACRXPacket(MACPacket):
|
|
||||||
def check_remove_preamble(self):
|
def check_remove_preamble(self):
|
||||||
if comp(self[0:8], preamble):
|
if comp(self[0:8], preamble):
|
||||||
for i in range(8):
|
for i in range(8):
|
||||||
|
@ -41,7 +53,28 @@ class MACRXPacket(MACPacket):
|
||||||
else:
|
else:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
class MACTXPacket(MACPacket):
|
def decode_remove_header(self):
|
||||||
|
header = []
|
||||||
|
for byte in self[:mac_header_len]:
|
||||||
|
header.append(self.pop(0))
|
||||||
|
for k, v in sorted(mac_header.items()):
|
||||||
|
setattr(self, k, get_field_data(v, header))
|
||||||
|
|
||||||
|
def decode(self):
|
||||||
|
self.preamble_error = self.check_remove_preamble()
|
||||||
|
self.crc_error = self.check_remove_crc()
|
||||||
|
if self.crc_error or self.preamble_error:
|
||||||
|
raise ValueError # XXX handle this properly
|
||||||
|
else:
|
||||||
|
self.decode_remove_header()
|
||||||
|
|
||||||
|
def encode_header(self):
|
||||||
|
header = 0
|
||||||
|
for k, v in sorted(mac_header.items()):
|
||||||
|
header |= (getattr(self, k) << (v.byte*8+v.offset))
|
||||||
|
for d in reversed(split_bytes(header, mac_header_len)):
|
||||||
|
self.insert(0, d)
|
||||||
|
|
||||||
def insert_crc(self):
|
def insert_crc(self):
|
||||||
for d in crc32(self):
|
for d in crc32(self):
|
||||||
self.append(d)
|
self.append(d)
|
||||||
|
@ -50,49 +83,62 @@ class MACTXPacket(MACPacket):
|
||||||
for d in reversed(preamble):
|
for d in reversed(preamble):
|
||||||
self.insert(0, d)
|
self.insert(0, d)
|
||||||
|
|
||||||
|
def encode(self):
|
||||||
|
self.encode_header()
|
||||||
|
self.insert_crc()
|
||||||
|
self.insert_preamble()
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
r = "--------\n"
|
||||||
|
for k in sorted(mac_header.keys()):
|
||||||
|
r += k + " : 0x%x" %getattr(self,k) + "\n"
|
||||||
|
r += "payload: "
|
||||||
|
for d in self:
|
||||||
|
r += "%02x" %d
|
||||||
|
return r
|
||||||
|
|
||||||
class MAC(Module):
|
class MAC(Module):
|
||||||
def __init__(self, phy, debug=False, loopback=False):
|
def __init__(self, phy, debug=False, loopback=False):
|
||||||
self.phy = phy
|
self.phy = phy
|
||||||
self.debug = debug
|
self.debug = debug
|
||||||
self.loopback = loopback
|
self.loopback = loopback
|
||||||
self.tx_packets = []
|
self.tx_packets = []
|
||||||
self.tx_packet = MACTXPacket()
|
self.tx_packet = MACPacket()
|
||||||
self.rx_packet = MACRXPacket()
|
self.rx_packet = MACPacket()
|
||||||
|
|
||||||
self.ip_callback = None
|
self.ip_callback = None
|
||||||
|
self.arp_callback = None
|
||||||
|
|
||||||
def set_ip_callback(self, callback):
|
def set_ip_callback(self, callback):
|
||||||
self.ip_callback = callback
|
self.ip_callback = callback
|
||||||
|
|
||||||
def send(self, datas):
|
def set_arp_callback(self, callback):
|
||||||
tx_packet = MACTXPacket(datas)
|
self.arp_callback = callback
|
||||||
|
|
||||||
|
def send(self, packet):
|
||||||
if self.debug:
|
if self.debug:
|
||||||
r = ">>>>>>>>\n"
|
print_mac(">>>>>>>>")
|
||||||
r += "length " + str(len(tx_packet)) + "\n"
|
print_mac(packet)
|
||||||
for d in tx_packet:
|
packet.encode()
|
||||||
r += "%02x" %d
|
self.tx_packets.append(packet)
|
||||||
print_mac(r)
|
|
||||||
tx_packet.insert_crc()
|
|
||||||
tx_packet.insert_preamble()
|
|
||||||
self.tx_packets.append(tx_packet)
|
|
||||||
|
|
||||||
def callback(self, datas):
|
def callback(self, datas):
|
||||||
rx_packet = MACRXPacket(datas)
|
packet = MACPacket(datas)
|
||||||
preamble_error = rx_packet.check_remove_preamble()
|
packet.decode()
|
||||||
crc_error = rx_packet.check_remove_crc()
|
|
||||||
if self.debug:
|
if self.debug:
|
||||||
r = "<<<<<<<<\n"
|
print_mac("<<<<<<<<")
|
||||||
r += "preamble_error " + str(preamble_error) + "\n"
|
print_mac(packet)
|
||||||
r += "crc_error " + str(crc_error) + "\n"
|
|
||||||
r += "length " + str(len(rx_packet)) + "\n"
|
|
||||||
for d in rx_packet:
|
|
||||||
r += "%02x" %d
|
|
||||||
print_mac(r)
|
|
||||||
if (not preamble_error) and (not crc_error):
|
|
||||||
if self.loopback:
|
if self.loopback:
|
||||||
self.send(rx_packet)
|
self.send(packet)
|
||||||
elif self.ip_callback is not None:
|
else:
|
||||||
self.ip_callback(rx_packet)
|
if self.ethernet_type == ethernet_type_ip:
|
||||||
|
if self.ip_callback is not None:
|
||||||
|
self.ip_callback(packet)
|
||||||
|
elif self.ethernet_type == ethernet_type_arp:
|
||||||
|
if self.arp_callback is not None:
|
||||||
|
self.arp_callback(packet)
|
||||||
|
else:
|
||||||
|
raise ValueError # XXX handle this properly
|
||||||
|
|
||||||
def gen_simulation(self, selfp):
|
def gen_simulation(self, selfp):
|
||||||
self.tx_packet.done = True
|
self.tx_packet.done = True
|
||||||
|
|
Loading…
Reference in a new issue