test: add mac simulation skeleton

This commit is contained in:
Florent Kermarrec 2015-01-28 19:07:59 +01:00
parent 8a42d74904
commit 33edf11ec9
8 changed files with 149 additions and 114 deletions

View File

@ -5,6 +5,7 @@ from migen.fhdl.std import *
from migen.genlib.resetsync import AsyncResetSynchronizer from migen.genlib.resetsync import AsyncResetSynchronizer
from migen.genlib.record import * from migen.genlib.record import *
from migen.genlib.fsm import FSM, NextState from migen.genlib.fsm import FSM, NextState
from migen.genlib.misc import chooser
from migen.flow.actor import EndpointDescription from migen.flow.actor import EndpointDescription
from migen.flow.actor import Sink, Source from migen.flow.actor import Sink, Source
from migen.actorlib.structuring import Converter, Pipeline from migen.actorlib.structuring import Converter, Pipeline

View File

@ -16,8 +16,8 @@ class LiteEthMACCore(Module, AutoCSR):
self.submodules += RenameClockDomains(preamble_checker, "eth_rx") self.submodules += RenameClockDomains(preamble_checker, "eth_rx")
# CRC insert/check # CRC insert/check
crc32_inserter = crc.LiteEthMACCRC32Inserter(eth_description(phy.dw)) crc32_inserter = crc.LiteEthMACCRC32Inserter(eth_phy_description(phy.dw))
crc32_checker = crc.LiteEthMACCRC32Checker(eth_description(phy.dw)) crc32_checker = crc.LiteEthMACCRC32Checker(eth_phy_description(phy.dw))
self.submodules += RenameClockDomains(crc32_inserter, "eth_tx") self.submodules += RenameClockDomains(crc32_inserter, "eth_tx")
self.submodules += RenameClockDomains(crc32_checker, "eth_rx") self.submodules += RenameClockDomains(crc32_checker, "eth_rx")

View File

@ -101,7 +101,7 @@ class LiteEthMACCRC32(Module):
### ###
self.submodules.engine = LiteEthCRCEngine(data_width, self.width, self.polynom) self.submodules.engine = LiteEthMACCRCEngine(data_width, self.width, self.polynom)
reg = Signal(self.width, reset=self.init) reg = Signal(self.width, reset=self.init)
self.sync += reg.eq(self.engine.next) self.sync += reg.eq(self.engine.next)
self.comb += [ self.comb += [
@ -255,14 +255,14 @@ class LiteEthMACCRCChecker(Module):
NextState("IDLE"), NextState("IDLE"),
) )
fsm.act("IDLE", fsm.act("IDLE",
crc.d.eq(sink.data), crc.data.eq(sink.data),
If(sink.stb & sink.sop & sink.ack, If(sink.stb & sink.sop & sink.ack,
crc.ce.eq(1), crc.ce.eq(1),
NextState("COPY") NextState("COPY")
) )
) )
fsm.act("COPY", fsm.act("COPY",
crc.d.eq(sink.data), crc.data.eq(sink.data),
If(sink.stb & sink.ack, If(sink.stb & sink.ack,
crc.ce.eq(1), crc.ce.eq(1),
If(sink.eop, If(sink.eop,

View File

@ -1,7 +1,7 @@
LEDIR = ../../ LEDIR = ../../
PYTHON = python3 PYTHON = python3
CMD = PYTHONPATH=$(MSCDIR) $(PYTHON) CMD = PYTHONPATH=$(LEDIR) $(PYTHON)
mac_core_tb: mac_core_tb:
$(CMD) mac_core_tb.py $(CMD) mac_core_tb.py

View File

@ -4,7 +4,7 @@ from migen.fhdl.std import *
from migen.flow.actor import Sink, Source from migen.flow.actor import Sink, Source
from migen.genlib.record import * from migen.genlib.record import *
from misoclib.ethmac.common import * from liteeth.common import *
def print_with_prefix(s, prefix=""): def print_with_prefix(s, prefix=""):
if not isinstance(s, str): if not isinstance(s, str):
@ -19,6 +19,13 @@ def seed_to_data(seed, random=True):
else: else:
return seed return seed
def comp(p1, p2):
r = True
for x, y in zip(p1, p2):
if x != y:
r = False
return r
def check(p1, p2): def check(p1, p2):
p1 = copy.deepcopy(p1) p1 = copy.deepcopy(p1)
p2 = copy.deepcopy(p2) p2 = copy.deepcopy(p2)
@ -51,16 +58,19 @@ class Packet(list):
self.append(data) self.append(data)
class PacketStreamer(Module): class PacketStreamer(Module):
def __init__(self, description): def __init__(self, description, last_be=None):
self.source = Source(description) self.source = Source(description)
self.last_be = last_be
### ###
self.packets = [] self.packets = []
self.packet = Packet() self.packet = Packet()
self.packet.done = 1 self.packet.done = True
def send(self, packet): def send(self, packet):
packet = copy.deepcopy(packet) packet = copy.deepcopy(packet)
self.packets.append(packet) self.packets.append(packet)
while not packet.done:
yield
def do_simulation(self, selfp): def do_simulation(self, selfp):
if len(self.packets) and self.packet.done: if len(self.packets) and self.packet.done:
@ -68,16 +78,22 @@ class PacketStreamer(Module):
if not self.packet.ongoing and not self.packet.done: if not self.packet.ongoing and not self.packet.done:
selfp.source.stb = 1 selfp.source.stb = 1
selfp.source.sop = 1 selfp.source.sop = 1
selfp.source.d = self.packet.pop(0) selfp.source.data = self.packet.pop(0)
self.packet.ongoing = True self.packet.ongoing = True
elif selfp.source.stb == 1 and selfp.source.ack == 1: elif selfp.source.stb == 1 and selfp.source.ack == 1:
selfp.source.sop = 0 selfp.source.sop = 0
selfp.source.eop = (len(self.packet) == 1) if len(self.packet) == 1:
selfp.source.eop = 1
if self.last_be is not None:
selfp.source.last_be = self.last_be
else:
selfp.source.eop = 0
selfp.source.last_be = 0
if len(self.packet) > 0: if len(self.packet) > 0:
selfp.source.stb = 1 selfp.source.stb = 1
selfp.source.d = self.packet.pop(0) selfp.source.data = self.packet.pop(0)
else: else:
self.packet.done = 1 self.packet.done = True
selfp.source.stb = 0 selfp.source.stb = 0
class PacketLogger(Module): class PacketLogger(Module):
@ -87,17 +103,17 @@ class PacketLogger(Module):
self.packet = Packet() self.packet = Packet()
def receive(self): def receive(self):
self.packet.done = 0 self.packet.done = False
while self.packet.done == 0: while not self.packet.done:
yield yield
def do_simulation(self, selfp): def do_simulation(self, selfp):
selfp.sink.ack = 1 selfp.sink.ack = 1
if selfp.sink.stb == 1 and selfp.sink.sop == 1: if selfp.sink.stb == 1 and selfp.sink.sop == 1:
self.packet = Packet() self.packet = Packet()
self.packet.append(selfp.sink.d) self.packet.append(selfp.sink.data)
elif selfp.sink.stb: elif selfp.sink.stb:
self.packet.append(selfp.sink.d) self.packet.append(selfp.sink.data)
if selfp.sink.stb == 1 and selfp.sink.eop == 1: if selfp.sink.stb == 1 and selfp.sink.eop == 1:
self.packet.done = True self.packet.done = True

View File

@ -3,69 +3,23 @@ from migen.bus import wishbone
from migen.bus.transactions import * from migen.bus.transactions import *
from migen.sim.generic import run_simulation from migen.sim.generic import run_simulation
from misoclib.ethmac import EthMAC from liteeth.common import *
from misoclib.ethmac.phy import loopback from liteeth.mac import LiteEthMAC
from misoclib.ethmac.test.common import * from liteeth.test.common import *
from liteeth.test.model import phy, mac
class WishboneMaster:
def __init__(self, obj):
self.obj = obj
self.dat = 0
def write(self, adr, dat):
self.obj.cyc = 1
self.obj.stb = 1
self.obj.adr = adr
self.obj.we = 1
self.obj.sel = 0xF
self.obj.dat_w = dat
while self.obj.ack == 0:
yield
self.obj.cyc = 0
self.obj.stb = 0
yield
def read(self, adr):
self.obj.cyc = 1
self.obj.stb = 1
self.obj.adr = adr
self.obj.we = 0
self.obj.sel = 0xF
self.obj.dat_w = 0
while self.obj.ack == 0:
yield
self.dat = self.obj.dat_r
self.obj.cyc = 0
self.obj.stb = 0
yield
class SRAMReaderDriver:
def __init__(self, obj):
self.obj = obj
def start(self, slot, length):
self.obj._slot.storage = slot
self.obj._length.storage = length
self.obj._start.re = 1
yield
self.obj._start.re = 0
yield
def wait_done(self):
while self.obj.ev.done.pending == 0:
yield
def clear_done(self):
self.obj.ev.done.clear = 1
yield
self.obj.ev.done.clear = 0
yield
class TB(Module): class TB(Module):
def __init__(self): def __init__(self):
self.submodules.ethphy = loopback.LoopbackPHY() self.submodules.hostphy = phy.PHY(8, debug=True)
self.submodules.ethmac = EthMAC(phy=self.ethphy, with_hw_preamble_crc=True) self.submodules.hostmac = mac.MAC(self.hostphy, debug=True, random_level=0)
self.submodules.ethmac = LiteEthMAC(phy=self.hostphy, dw=32, interface="core", with_hw_preamble_crc=True)
self.submodules.streamer = PacketStreamer(eth_mac_description(32), last_be=1)
self.submodules.streamer_randomizer = AckRandomizer(eth_mac_description(32), level=0)
self.submodules.logger_randomizer = AckRandomizer(eth_mac_description(32), level=0)
self.submodules.logger = PacketLogger(eth_mac_description(32))
# 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()
@ -77,6 +31,13 @@ class TB(Module):
self.cd_eth_tx.rst.eq(ResetSignal()), self.cd_eth_tx.rst.eq(ResetSignal()),
] ]
self.comb += [
Record.connect(self.streamer.source, self.streamer_randomizer.sink),
Record.connect(self.streamer_randomizer.source, self.ethmac.sink),
Record.connect(self.ethmac.source, self.logger_randomizer.sink),
Record.connect(self.logger_randomizer.source, self.logger.sink)
]
def gen_simulation(self, selfp): def gen_simulation(self, selfp):
selfp.cd_eth_rx.rst = 1 selfp.cd_eth_rx.rst = 1
selfp.cd_eth_tx.rst = 1 selfp.cd_eth_tx.rst = 1
@ -84,40 +45,10 @@ class TB(Module):
selfp.cd_eth_rx.rst = 0 selfp.cd_eth_rx.rst = 0
selfp.cd_eth_tx.rst = 0 selfp.cd_eth_tx.rst = 0
wishbone_master = WishboneMaster(selfp.ethmac.bus) for i in range(8):
sram_reader_driver = SRAMReaderDriver(selfp.ethmac.sram_reader) streamer_packet = Packet([i for i in range(64)])
print(streamer_packet)
sram_writer_slots_offset = [0x000, 0x200] yield from self.streamer.send(streamer_packet)
sram_reader_slots_offset = [0x400, 0x600]
length = 1500+2
tx_payload = [seed_to_data(i, True) % 0xFF for i in range(length)] + [0, 0, 0, 0]
errors = 0
for slot in range(2):
print("slot {}:".format(slot))
# fill tx memory
for i in range(length//4+1):
dat = int.from_bytes(tx_payload[4*i:4*(i+1)], "big")
yield from wishbone_master.write(sram_reader_slots_offset[slot]+i, dat)
# send tx payload & wait
yield from sram_reader_driver.start(slot, length)
yield from sram_reader_driver.wait_done()
yield from sram_reader_driver.clear_done()
# get rx payload (loopback on PHY Model)
rx_payload = []
for i in range(length//4+1):
yield from wishbone_master.read(sram_writer_slots_offset[slot]+i)
dat = wishbone_master.dat
rx_payload += list(dat.to_bytes(4, byteorder='big'))
# check results
s, l, e = check(tx_payload[:length], rx_payload[:min(length, len(rx_payload))])
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
if __name__ == "__main__": if __name__ == "__main__":
run_simulation(TB(), vcd_name="my.vcd") run_simulation(TB(), ncycles=1000, vcd_name="my.vcd", keep_files=True)

82
liteeth/test/model/mac.py Normal file
View File

@ -0,0 +1,82 @@
import binascii
from liteeth.common import *
from liteeth.mac.common import *
from liteeth.test.common import *
def crc32(l):
crc = []
crc_bytes = binascii.crc32(bytes(l)).to_bytes(4, byteorder="little")
for byte in crc_bytes:
crc.append(int(byte))
return crc
# MAC model
class MACPacket(list):
def __init__(self, init=[]):
self.ongoing = False
self.done = False
for byte in init:
self.append(byte)
class MACRXPacket(MACPacket):
def check_remove_preamble(self):
if comp(self[0:8], [0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0xD5]):
for i in range(8):
self.pop(0)
return False
else:
return True
def check_remove_crc(self):
if comp(self[-4:], crc32(self[:-4])):
for i in range(4):
self.pop()
return False
else:
return True
class MACTXPacket(MACPacket):
def insert_crc(self):
return self
def insert_preamble(self):
return self
class MAC(Module):
def __init__(self, phy, debug=False, random_level=0):
self.phy = phy
self.debug = debug
self.random_level = random_level
self.tx_packets = []
self.tx_packet = MACTXPacket()
self.rx_packet = MACRXPacket()
self.ip_callback = None
def set_ip_callback(self, callback):
self.ip_callback = callback
def send(self, datas):
tx_packet = MACTXPacket(datas)
tx_packet.insert_crc()
tx_packet.insert_preamble()
self.tx_packets.append(tx_packet)
def callback(self, datas):
rx_packet = MACRXPacket(datas)
preamble_error = rx_packet.check_remove_preamble()
crc_error = rx_packet.check_remove_crc()
if (not preamble_error) and (not crc_error):
if self.ip_callback is not None:
self.ip_callback(rx_packet)
def gen_simulation(self, selfp):
self.tx_packet.done = True
while True:
yield from self.phy.receive()
self.callback(self.phy.packet)
# XXX add full duplex
if len(self.tx_packets) != 0:
tx_packet = self.tx_packets.pop(0)
yield from self.phy.send(tx_packet)

View File

@ -16,13 +16,18 @@ class PHY(Module):
self.dw = dw self.dw = dw
self.debug = debug self.debug = debug
self.phy_source = PHYSource(dw) self.submodules.phy_source = PHYSource(dw)
self.phy_sink = PHYSink(dw) self.submodules.phy_sink = PHYSink(dw)
self.source = self.phy_source.source self.source = self.phy_source.source
self.sink = self.phy_sink.sink self.sink = self.phy_sink.sink
def send(self, datas, blocking=True): self.mac_callback = None
def set_mac_callback(self, callback):
self.mac_callback = callback
def send(self, datas):
packet = Packet(datas) packet = Packet(datas)
yield from self.phy_source.send(packet, blocking) yield from self.phy_source.send(packet, blocking)