From 1ef81c4d24bf90daf3fed2facb30eff3ad7e0f68 Mon Sep 17 00:00:00 2001 From: Florent Kermarrec Date: Mon, 27 Apr 2015 14:50:43 +0200 Subject: [PATCH] litesata: split hdd model (phy, link, transport, command & hdd) and update simulations --- misoclib/mem/litesata/test/__init__.py | 0 misoclib/mem/litesata/test/bist_tb.py | 2 +- misoclib/mem/litesata/test/command_tb.py | 2 +- misoclib/mem/litesata/test/common.py | 7 + misoclib/mem/litesata/test/link_tb.py | 2 +- misoclib/mem/litesata/test/model/__init__.py | 0 misoclib/mem/litesata/test/model/command.py | 28 ++++ misoclib/mem/litesata/test/model/hdd.py | 97 +++++++++++++ .../litesata/test/{hdd.py => model/link.py} | 109 ++------------ misoclib/mem/litesata/test/model/phy.py | 77 ++++++++++ misoclib/mem/litesata/test/model/transport.py | 137 ++++++++++++++++++ 11 files changed, 360 insertions(+), 101 deletions(-) create mode 100644 misoclib/mem/litesata/test/__init__.py create mode 100644 misoclib/mem/litesata/test/model/__init__.py create mode 100644 misoclib/mem/litesata/test/model/command.py create mode 100644 misoclib/mem/litesata/test/model/hdd.py rename misoclib/mem/litesata/test/{hdd.py => model/link.py} (84%) create mode 100644 misoclib/mem/litesata/test/model/phy.py create mode 100644 misoclib/mem/litesata/test/model/transport.py diff --git a/misoclib/mem/litesata/test/__init__.py b/misoclib/mem/litesata/test/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/misoclib/mem/litesata/test/bist_tb.py b/misoclib/mem/litesata/test/bist_tb.py index 46042713..2b89c5fa 100644 --- a/misoclib/mem/litesata/test/bist_tb.py +++ b/misoclib/mem/litesata/test/bist_tb.py @@ -2,8 +2,8 @@ from misoclib.mem.litesata.common import * from misoclib.mem.litesata import LiteSATA from misoclib.mem.litesata.frontend.bist import LiteSATABISTGenerator, LiteSATABISTChecker -from misoclib.mem.litesata.test.hdd import * from misoclib.mem.litesata.test.common import * +from misoclib.mem.litesata.test.model.hdd import * class TB(Module): diff --git a/misoclib/mem/litesata/test/command_tb.py b/misoclib/mem/litesata/test/command_tb.py index 4dd67709..6020dc96 100644 --- a/misoclib/mem/litesata/test/command_tb.py +++ b/misoclib/mem/litesata/test/command_tb.py @@ -1,8 +1,8 @@ from misoclib.mem.litesata.common import * from misoclib.mem.litesata.core import LiteSATACore -from misoclib.mem.litesata.test.hdd import * from misoclib.mem.litesata.test.common import * +from misoclib.mem.litesata.test.model.hdd import * class CommandTXPacket(list): diff --git a/misoclib/mem/litesata/test/common.py b/misoclib/mem/litesata/test/common.py index 6ecbba82..4d98b4ee 100644 --- a/misoclib/mem/litesata/test/common.py +++ b/misoclib/mem/litesata/test/common.py @@ -5,6 +5,13 @@ from migen.sim.generic import run_simulation from misoclib.mem.litesata.common import * +def print_with_prefix(s, prefix=""): + if not isinstance(s, str): + s = s.__repr__() + s = s.split("\n") + for l in s: + print(prefix + l) + def seed_to_data(seed, random=True): if random: diff --git a/misoclib/mem/litesata/test/link_tb.py b/misoclib/mem/litesata/test/link_tb.py index 0790a0f4..dbaffa2c 100644 --- a/misoclib/mem/litesata/test/link_tb.py +++ b/misoclib/mem/litesata/test/link_tb.py @@ -1,8 +1,8 @@ from misoclib.mem.litesata.common import * from misoclib.mem.litesata.core.link import LiteSATALink +from misoclib.mem.litesata.test.model.hdd import * from misoclib.mem.litesata.test.common import * -from misoclib.mem.litesata.test.hdd import * class LinkStreamer(PacketStreamer): diff --git a/misoclib/mem/litesata/test/model/__init__.py b/misoclib/mem/litesata/test/model/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/misoclib/mem/litesata/test/model/command.py b/misoclib/mem/litesata/test/model/command.py new file mode 100644 index 00000000..e718c12c --- /dev/null +++ b/misoclib/mem/litesata/test/model/command.py @@ -0,0 +1,28 @@ +from misoclib.mem.litesata.common import * +from misoclib.mem.litesata.test.common import * + +from misoclib.mem.litesata.test.model.transport import FIS_REG_H2D, FIS_DATA + +class CommandLayer(Module): + def __init__(self, transport): + self.transport = transport + self.transport.set_command_callback(self.callback) + + self.hdd = None + + def set_hdd(self, hdd): + self.hdd = hdd + + def callback(self, fis): + resp = None + if isinstance(fis, FIS_REG_H2D): + if fis.command == regs["WRITE_DMA_EXT"]: + resp = self.hdd.write_dma_callback(fis) + elif fis.command == regs["READ_DMA_EXT"]: + resp = self.hdd.read_dma_callback(fis) + elif isinstance(fis, FIS_DATA): + resp = self.hdd.data_callback(fis) + + if resp is not None: + for packet in resp: + self.transport.send(packet) diff --git a/misoclib/mem/litesata/test/model/hdd.py b/misoclib/mem/litesata/test/model/hdd.py new file mode 100644 index 00000000..2f884f5d --- /dev/null +++ b/misoclib/mem/litesata/test/model/hdd.py @@ -0,0 +1,97 @@ +import math + +from misoclib.mem.litesata.common import * +from misoclib.mem.litesata.test.common import * + +from misoclib.mem.litesata.test.model.phy import * +from misoclib.mem.litesata.test.model.link import * +from misoclib.mem.litesata.test.model.transport import * +from misoclib.mem.litesata.test.model.command import * + +def print_hdd(s): + print_with_prefix(s, "[HDD]: ") + + +class HDDMemRegion: + def __init__(self, base, count, sector_size): + self.base = base + self.count = count + self.data = [0]*(count*sector_size//4) + + +class HDD(Module): + def __init__(self, + link_debug=False, link_random_level=0, + transport_debug=False, transport_loopback=False, + hdd_debug=False, + ): + self.submodules.phy = PHYLayer() + self.submodules.link = LinkLayer(self.phy, link_debug, link_random_level) + self.submodules.transport = TransportLayer(self.link, transport_debug, transport_loopback) + self.submodules.command = CommandLayer(self.transport) + + self.command.set_hdd(self) + + self.debug = hdd_debug + self.mem = None + self.wr_sector = 0 + self.wr_end_sector = 0 + self.rd_sector = 0 + self.rx_end_sector = 0 + + def malloc(self, sector, count): + if self.debug: + s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count-1) + s += " ({} KB)".format(count*logical_sector_size//1024) + print_hdd(s) + self.mem = HDDMemRegion(sector, count, logical_sector_size) + + def write(self, sector, data): + n = math.ceil(dwords2sectors(len(data))) + if self.debug: + if n == 1: + s = "{}".format(sector) + else: + s = "{s} to {e}".format(s=sector, e=sector+n-1) + print_hdd("Writing sector " + s) + for i in range(len(data)): + offset = sectors2dwords(sector) + self.mem.data[offset+i] = data[i] + + def read(self, sector, count): + if self.debug: + if count == 1: + s = "{}".format(sector) + else: + s = "{s} to {e}".format(s=sector, e=sector+count-1) + print_hdd("Reading sector " + s) + data = [] + for i in range(sectors2dwords(count)): + data.append(self.mem.data[sectors2dwords(sector)+i]) + return data + + def write_dma_callback(self, fis): + self.wr_sector = fis.lba_lsb + (fis.lba_msb << 32) + self.wr_end_sector = self.wr_sector + fis.count + return [FIS_DMA_ACTIVATE_D2H()] + + def read_dma_callback(self, fis): + self.rd_sector = fis.lba_lsb + (fis.lba_msb << 32) + self.rd_end_sector = self.rd_sector + fis.count + packets = [] + while self.rd_sector != self.rd_end_sector: + count = min(self.rd_end_sector-self.rd_sector, (fis_max_dwords*4)//logical_sector_size) + packet = self.read(self.rd_sector, count) + packet.insert(0, 0) + packets.append(FIS_DATA(packet, direction="D2H")) + self.rd_sector += count + packets.append(FIS_REG_D2H()) + return packets + + def data_callback(self, fis): + self.write(self.wr_sector, fis.packet[1:]) + self.wr_sector += dwords2sectors(len(fis.packet[1:])) + if self.wr_sector == self.wr_end_sector: + return [FIS_REG_D2H()] + else: + return [FIS_DMA_ACTIVATE_D2H()] diff --git a/misoclib/mem/litesata/test/hdd.py b/misoclib/mem/litesata/test/model/link.py similarity index 84% rename from misoclib/mem/litesata/test/hdd.py rename to misoclib/mem/litesata/test/model/link.py index a9f66bfa..f3dd40be 100644 --- a/misoclib/mem/litesata/test/hdd.py +++ b/misoclib/mem/litesata/test/model/link.py @@ -4,93 +4,6 @@ import math from misoclib.mem.litesata.common import * from misoclib.mem.litesata.test.common import * - -def print_with_prefix(s, prefix=""): - if not isinstance(s, str): - s = s.__repr__() - s = s.split("\n") - for l in s: - print(prefix + l) - - -# PHY Layer model -class PHYDword: - def __init__(self, dat=0): - self.dat = dat - self.start = 1 - self.done = 0 - - -class PHYSource(Module): - def __init__(self): - self.source = Source(phy_description(32)) - - # # # - - self.dword = PHYDword() - - def send(self, dword): - self.dword = dword - - def do_simulation(self, selfp): - selfp.source.stb = 1 - selfp.source.charisk = 0b0000 - for k, v in primitives.items(): - if v == self.dword.dat: - selfp.source.charisk = 0b0001 - selfp.source.data = self.dword.dat - - -class PHYSink(Module): - def __init__(self): - self.sink = Sink(phy_description(32)) - - # # # - - self.dword = PHYDword() - - def receive(self): - self.dword.done = 0 - while self.dword.done == 0: - yield - - def do_simulation(self, selfp): - self.dword.done = 0 - selfp.sink.ack = 1 - if selfp.sink.stb == 1: - self.dword.done = 1 - self.dword.dat = selfp.sink.data - - -class PHYLayer(Module): - def __init__(self): - - self.submodules.rx = PHYSink() - self.submodules.tx = PHYSource() - - self.source = self.tx.source - self.sink = self.rx.sink - - def send(self, dword): - packet = PHYDword(dword) - self.tx.send(packet) - - def receive(self): - yield from self.rx.receive() - - def __repr__(self): - receiving = "{:08x} ".format(self.rx.dword.dat) - receiving += decode_primitive(self.rx.dword.dat) - receiving += " "*(16-len(receiving)) - - sending = "{:08x} ".format(self.tx.dword.dat) - sending += decode_primitive(self.tx.dword.dat) - sending += " "*(16-len(sending)) - - return receiving + sending - - -# Link Layer model def print_link(s): print_with_prefix(s, "[LNK]: ") @@ -142,7 +55,7 @@ class LinkTXPacket(LinkPacket): def insert_crc(self): stdin = "" for v in self: - stdin += "0x{:08x} ".foramt(v) + stdin += "0x{:08x} ".format(v) stdin += "exit" with subprocess.Popen("./crc", stdin=subprocess.PIPE, @@ -299,7 +212,7 @@ def print_transport(s): def get_field_data(field, packet): - return (packet[field.dword] >> field.offset) & (2**field.width-1) + return (packet[field.byte//4] >> field.offset) & (2**field.width-1) class FIS: @@ -315,7 +228,7 @@ class FIS: def encode(self): for k, v in self.description.items(): - self.packet[v.dword] |= (getattr(self, k) << v.offset) + self.packet[v.byte//4] |= (getattr(self, k) << v.offset) def __repr__(self): if self.direction == "H2D": @@ -328,8 +241,8 @@ class FIS: class FIS_REG_H2D(FIS): - def __init__(self, packet=[0]*fis_reg_h2d_cmd_len): - FIS.__init__(self, packet, fis_reg_h2d_layout) + def __init__(self, packet=[0]*fis_reg_h2d_header.length): + FIS.__init__(self, packet, fis_reg_h2d_header.fields) self.type = fis_types["REG_H2D"] self.direction = "H2D" @@ -340,8 +253,8 @@ class FIS_REG_H2D(FIS): class FIS_REG_D2H(FIS): - def __init__(self, packet=[0]*fis_reg_d2h_cmd_len): - FIS.__init__(self, packet, fis_reg_d2h_layout) + def __init__(self, packet=[0]*fis_reg_d2h_header.length): + FIS.__init__(self, packet, fis_reg_d2h_header.fields) self.type = fis_types["REG_D2H"] self.direction = "D2H" @@ -352,8 +265,8 @@ class FIS_REG_D2H(FIS): class FIS_DMA_ACTIVATE_D2H(FIS): - def __init__(self, packet=[0]*fis_dma_activate_d2h_cmd_len): - FIS.__init__(self, packet, fis_dma_activate_d2h_layout) + def __init__(self, packet=[0]*fis_dma_activate_d2h_header.length): + FIS.__init__(self, packet, fis_dma_activate_d2h_header.fields) self.type = fis_types["DMA_ACTIVATE_D2H"] self.direction = "D2H" @@ -365,7 +278,7 @@ class FIS_DMA_ACTIVATE_D2H(FIS): class FIS_DATA(FIS): def __init__(self, packet=[0], direction="H2D"): - FIS.__init__(self, packet, fis_data_layout, direction) + FIS.__init__(self, packet, fis_data_header.fields, direction) self.type = fis_types["DATA"] def __repr__(self): @@ -488,7 +401,7 @@ class HDD(Module): def malloc(self, sector, count): if self.debug: - s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count) + s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count-1) s += " ({} KB)".format(count*logical_sector_size//1024) print_hdd(s) self.mem = HDDMemRegion(sector, count, logical_sector_size) diff --git a/misoclib/mem/litesata/test/model/phy.py b/misoclib/mem/litesata/test/model/phy.py new file mode 100644 index 00000000..27f15edf --- /dev/null +++ b/misoclib/mem/litesata/test/model/phy.py @@ -0,0 +1,77 @@ +from misoclib.mem.litesata.common import * +from misoclib.mem.litesata.test.common import * + +class PHYDword: + def __init__(self, dat=0): + self.dat = dat + self.start = 1 + self.done = 0 + + +class PHYSource(Module): + def __init__(self): + self.source = Source(phy_description(32)) + + # # # + + self.dword = PHYDword() + + def send(self, dword): + self.dword = dword + + def do_simulation(self, selfp): + selfp.source.stb = 1 + selfp.source.charisk = 0b0000 + for k, v in primitives.items(): + if v == self.dword.dat: + selfp.source.charisk = 0b0001 + selfp.source.data = self.dword.dat + + +class PHYSink(Module): + def __init__(self): + self.sink = Sink(phy_description(32)) + + # # # + + self.dword = PHYDword() + + def receive(self): + self.dword.done = 0 + while self.dword.done == 0: + yield + + def do_simulation(self, selfp): + self.dword.done = 0 + selfp.sink.ack = 1 + if selfp.sink.stb == 1: + self.dword.done = 1 + self.dword.dat = selfp.sink.data + + +class PHYLayer(Module): + def __init__(self): + + self.submodules.rx = PHYSink() + self.submodules.tx = PHYSource() + + self.source = self.tx.source + self.sink = self.rx.sink + + def send(self, dword): + packet = PHYDword(dword) + self.tx.send(packet) + + def receive(self): + yield from self.rx.receive() + + def __repr__(self): + receiving = "{:08x} ".format(self.rx.dword.dat) + receiving += decode_primitive(self.rx.dword.dat) + receiving += " "*(16-len(receiving)) + + sending = "{:08x} ".format(self.tx.dword.dat) + sending += decode_primitive(self.tx.dword.dat) + sending += " "*(16-len(sending)) + + return receiving + sending diff --git a/misoclib/mem/litesata/test/model/transport.py b/misoclib/mem/litesata/test/model/transport.py new file mode 100644 index 00000000..830c2f72 --- /dev/null +++ b/misoclib/mem/litesata/test/model/transport.py @@ -0,0 +1,137 @@ +from misoclib.mem.litesata.common import * +from misoclib.mem.litesata.test.common import * + +from misoclib.mem.litesata.test.model.link import LinkTXPacket + +def print_transport(s): + print_with_prefix(s, "[TRN]: ") + + +def get_field_data(field, packet): + return (packet[field.byte//4] >> field.offset) & (2**field.width-1) + + +class FIS: + def __init__(self, packet, description, direction="H2D"): + self.packet = packet + self.description = description + self.direction = direction + self.decode() + + def decode(self): + for k, v in self.description.items(): + setattr(self, k, get_field_data(v, self.packet)) + + def encode(self): + for k, v in self.description.items(): + self.packet[v.byte//4] |= (getattr(self, k) << v.offset) + + def __repr__(self): + if self.direction == "H2D": + r = ">>>>>>>>\n" + else: + r = "<<<<<<<<\n" + for k in sorted(self.description.keys()): + r += k + " : 0x{:x}".format(getattr(self, k)) + "\n" + return r + + +class FIS_REG_H2D(FIS): + def __init__(self, packet=[0]*fis_reg_h2d_header.length): + FIS.__init__(self, packet, fis_reg_h2d_header.fields) + self.type = fis_types["REG_H2D"] + self.direction = "H2D" + + def __repr__(self): + r = "FIS_REG_H2D\n" + r += FIS.__repr__(self) + return r + + +class FIS_REG_D2H(FIS): + def __init__(self, packet=[0]*fis_reg_d2h_header.length): + FIS.__init__(self, packet, fis_reg_d2h_header.fields) + self.type = fis_types["REG_D2H"] + self.direction = "D2H" + + def __repr__(self): + r = "FIS_REG_D2H\n" + r += FIS.__repr__(self) + return r + + +class FIS_DMA_ACTIVATE_D2H(FIS): + def __init__(self, packet=[0]*fis_dma_activate_d2h_header.length): + FIS.__init__(self, packet, fis_dma_activate_d2h_header.fields) + self.type = fis_types["DMA_ACTIVATE_D2H"] + self.direction = "D2H" + + def __repr__(self): + r = "FIS_DMA_ACTIVATE_D2H\n" + r += FIS.__repr__(self) + return r + + +class FIS_DATA(FIS): + def __init__(self, packet=[0], direction="H2D"): + FIS.__init__(self, packet, fis_data_header.fields, direction) + self.type = fis_types["DATA"] + + def __repr__(self): + r = "FIS_DATA\n" + r += FIS.__repr__(self) + for data in self.packet[1:]: + r += "{:08x}\n".format(data) + return r + + +class FIS_UNKNOWN(FIS): + def __init__(self, packet=[0], direction="H2D"): + FIS.__init__(self, packet, {}, direction) + + def __repr__(self): + r = "UNKNOWN\n" + if self.direction == "H2D": + r += ">>>>>>>>\n" + else: + r += "<<<<<<<<\n" + for dword in self.packet: + r += "{:08x}\n".format(dword) + return r + + +class TransportLayer(Module): + def __init__(self, link, debug=False, loopback=False): + self.link = link + self.debug = debug + self.loopback = loopback + self.link.set_transport_callback(self.callback) + + def set_command_callback(self, callback): + self.command_callback = callback + + def send(self, fis): + fis.encode() + packet = LinkTXPacket(fis.packet) + self.link.tx_packets.append(packet) + if self.debug and not self.loopback: + print_transport(fis) + + def callback(self, packet): + fis_type = packet[0] & 0xff + if fis_type == fis_types["REG_H2D"]: + fis = FIS_REG_H2D(packet) + elif fis_type == fis_types["REG_D2H"]: + fis = FIS_REG_D2H(packet) + elif fis_type == fis_types["DMA_ACTIVATE_D2H"]: + fis = FIS_DMA_ACTIVATE_D2H(packet) + elif fis_type == fis_types["DATA"]: + fis = FIS_DATA(packet, direction="H2D") + else: + fis = FIS_UNKNOWN(packet, direction="H2D") + if self.debug: + print_transport(fis) + if self.loopback: + self.send(fis) + else: + self.command_callback(fis) -- 2.30.2