modify addressing (in sectors) and improve hdd model debug
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 15 Dec 2014 12:26:53 +0000 (13:26 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Mon, 15 Dec 2014 12:26:53 +0000 (13:26 +0100)
lib/sata/command/__init__.py
lib/sata/common.py
lib/sata/test/command_tb.py
lib/sata/test/hdd.py
lib/sata/transport/__init__.py

index c2ad667e2f236fdd7f9173a3d1b1fd2b6ba61586..48072f9bbd65de42290fe2f108f7b947a320363d 100644 (file)
@@ -23,15 +23,12 @@ class SATACommandTX(Module):
 
                ###
 
-               sector_bits = log2_int(sector_size)
-               dwords_bits = 2
-
                self.comb += [
                        transport.sink.pm_port.eq(0),
                        transport.sink.features.eq(0),
-                       transport.sink.lba.eq(sink.address[sector_bits-dwords_bits:]),
+                       transport.sink.lba.eq(sink.sector),
                        transport.sink.device.eq(0xe0),
-                       transport.sink.count.eq(sink.length[sector_bits-dwords_bits:]),
+                       transport.sink.count.eq(sink.count),
                        transport.sink.icc.eq(0),
                        transport.sink.control.eq(0),
                ]
@@ -61,11 +58,10 @@ class SATACommandTX(Module):
                        transport.sink.type.eq(fis_types["REG_H2D"]),
                        transport.sink.c.eq(1),
                        transport.sink.command.eq(regs["WRITE_DMA_EXT"]),
-                       If(transport.sink.ack,
+                       If(sink.stb & transport.sink.ack,
                                NextState("WAIT_DMA_ACTIVATE")
                        )
                )
-               # XXX: split when length > 2048 dwords
                fsm.act("WAIT_DMA_ACTIVATE",
                        If(from_rx.dma_activate,
                                NextState("SEND_DATA")
@@ -116,7 +112,7 @@ class SATACommandTX(Module):
                ]
 
 class SATACommandRX(Module):
-       def __init__(self, transport, sector_size):
+       def __init__(self, transport, sector_size, max_count):
                self.source = source = Source(command_rx_description(32))
                self.to_tx = to_tx = Source(rx_to_tx)
                self.from_tx = from_tx = Sink(tx_to_rx)
@@ -167,7 +163,7 @@ class SATACommandRX(Module):
                        source.eop.eq(1),
                        source.write.eq(1),
                        source.success.eq(1),
-                       If(source.ack,
+                       If(source.stb & source.ack,
                                NextState("IDLE")
                        )
                )
@@ -207,7 +203,7 @@ class SATACommandRX(Module):
                        source.read.eq(~identify),
                        source.identify.eq(identify),
                        source.success.eq(1),
-                       If(source.ack,
+                       If(source.stb & source.ack,
                                NextState("IDLE")
                        )
                )
@@ -217,9 +213,11 @@ class SATACommandRX(Module):
                ]
 
 class SATACommand(Module):
-       def __init__(self, transport, sector_size=512):
+       def __init__(self, transport, sector_size=512, max_count=16):
+               if max_count*sector_size > 8192:
+                       raise ValueError("sector_size x max_count must be <= 2048")
                self.submodules.tx = SATACommandTX(transport, sector_size)
-               self.submodules.rx = SATACommandRX(transport, sector_size)
+               self.submodules.rx = SATACommandRX(transport, sector_size, max_count)
                self.comb += [
                        self.rx.to_tx.connect(self.tx.from_rx),
                        self.tx.to_rx.connect(self.rx.from_tx)
index c8e3ce3812472e88b562ac64ed919ba83cde6a4d..a4c1030d0e10c2cb148a0af9dae3ca706aeb66b9 100644 (file)
@@ -148,8 +148,8 @@ def command_tx_description(dw):
                ("write", 1),
                ("read", 1),
                ("identify", 1),
-               ("address", 32),
-               ("length", 32),
+               ("sector", 48),
+               ("count", 4),
                ("data", dw)
        ]
        return EndpointDescription(layout, packetized=True)
index afbe95ddbe5baaa37432b4723f161645a6131ef5..917bf214f4eb5d881914493c90447a6040ed4064 100644 (file)
@@ -13,14 +13,14 @@ from lib.sata.test.hdd import *
 from lib.sata.test.common import *
 
 class CommandTXPacket(list):
-       def __init__(self, write=0, read=0,  identify=0, address=0, length=0, data=[]):
+       def __init__(self, write=0, read=0,  identify=0, sector=0, count=0, data=[]):
                self.ongoing = False
                self.done = False
                self.write = write
                self.read = read
                self.identify = identify
-               self.address = address
-               self.length = length
+               self.sector = sector
+               self.count = count
                for d in data:
                        self.append(d)
 
@@ -47,8 +47,8 @@ class CommandStreamer(Module):
                selfp.source.write = self.packet.write
                selfp.source.read = self.packet.read
                selfp.source.identify = self.packet.identify
-               selfp.source.address = self.packet.address
-               selfp.source.length = self.packet.length
+               selfp.source.sector = self.packet.sector
+               selfp.source.count = self.packet.count
 
                if not self.packet.ongoing and not self.packet.done:
                        selfp.source.stb = 1
@@ -105,10 +105,8 @@ class CommandLogger(Module):
 class TB(Module):
        def __init__(self):
                self.submodules.hdd = HDD(
-                               phy_debug=False,
-                               link_random_level=50, link_debug=False,
+                               link_debug=False, link_random_level=50,
                                transport_debug=False, transport_loopback=False,
-                               command_debug=False,
                                hdd_debug=True)
                self.submodules.link = SATALink(self.hdd.phy)
                self.submodules.transport = SATATransport(self.link)
@@ -128,12 +126,14 @@ class TB(Module):
                ]
 
        def gen_simulation(self, selfp):
-               self.hdd.allocate_mem(0x00000000, 64*1024*1024)
-               write_data = [i for i in range(512//4)]
-               write_packet = CommandTXPacket(write=1, address=0, length=len(write_data), data=write_data)
+               hdd = self.hdd
+               hdd.malloc(0, 64)
+               write_data = [i for i in range(hdd.sectors2dwords(2))]
+               write_len = hdd.dwords2sectors(len(write_data))
+               write_packet = CommandTXPacket(write=1, sector=2, count=write_len, data=write_data)
                yield from self.streamer.send(write_packet)
                yield from self.logger.receive()
-               read_packet = CommandTXPacket(read=1, address=0, length=len(write_data))
+               read_packet = CommandTXPacket(read=1, sector=2, count=write_len)
                yield from self.streamer.send(read_packet)
                yield from self.logger.receive()
                read_data = self.logger.packet
@@ -144,4 +144,4 @@ class TB(Module):
                print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
 
 if __name__ == "__main__":
-       run_simulation(TB(), ncycles=1024, vcd_name="my.vcd", keep_files=True)
+       run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)
index 2d9d2f64c9948636fa099d534eec32aa180372ae..e459e7e2fb9b179c01b4eab5732564975871399b 100644 (file)
@@ -6,6 +6,13 @@ from migen.fhdl.std import *
 from lib.sata.common import *
 from lib.sata.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):
@@ -49,8 +56,7 @@ class PHYSink(Module):
                        self.dword.dat = selfp.sink.data
 
 class PHYLayer(Module):
-       def __init__(self, debug=False):
-               self.debug = debug
+       def __init__(self):
 
                self.submodules.rx = PHYSink()
                self.submodules.tx = PHYSource()
@@ -63,8 +69,6 @@ class PHYLayer(Module):
                self.tx.send(packet)
 
        def receive(self):
-               if self.debug:
-                               print(self)
                yield from self.rx.receive()
 
        def __repr__(self):
@@ -79,6 +83,9 @@ class PHYLayer(Module):
                return receiving + sending
 
 # Link Layer model
+def print_link(s):
+       print_with_prefix(s, "[LNK]: ")
+
 def import_scrambler_datas():
        with subprocess.Popen(["./scrambler"], stdin=subprocess.PIPE, stdout=subprocess.PIPE) as process:
                process.stdin.write("0x10000".encode("ASCII"))
@@ -249,6 +256,8 @@ class LinkLayer(Module):
                self.phy.send(primitives["SYNC"])
                while True:
                        yield from self.phy.receive()
+                       if self.debug:
+                               print_link(self.phy)
                        self.phy.send(primitives["SYNC"])
                        rx_dword = self.phy.rx.dword.dat
                        rx_dword = self.remove_cont(rx_dword)
@@ -264,6 +273,9 @@ class LinkLayer(Module):
                        self.insert_cont()
 
 # Transport Layer model
+def print_transport(s):
+       print_with_prefix(s, "[TRN]: ")
+
 def get_field_data(field, packet):
        return (packet[field.dword] >> field.offset) & (2**field.width-1)
 
@@ -365,7 +377,7 @@ class TransportLayer(Module):
                packet = LinkTXPacket(fis.packet)
                self.link.tx_packets.append(packet)
                if self.debug and not self.loopback:
-                       print(fis)
+                       print_transport(fis)
 
        def callback(self, packet):
                fis_type = packet[0] & 0xff
@@ -380,7 +392,7 @@ class TransportLayer(Module):
                else:
                        fis = FIS_UNKNOWN(packet, direction="H2D")
                if self.debug:
-                       print(fis)
+                       print_transport(fis)
                if self.loopback:
                        self.send(fis)
                else:
@@ -388,9 +400,8 @@ class TransportLayer(Module):
 
 # Command Layer model
 class CommandLayer(Module):
-       def __init__(self, transport, debug=False):
+       def __init__(self, transport):
                self.transport = transport
-               self.debug = debug
                self.transport.set_command_callback(self.callback)
 
                self.hdd = None
@@ -399,103 +410,100 @@ class CommandLayer(Module):
                self.hdd = hdd
 
        def callback(self, fis):
-               # XXX manage maximum of 2048 DWORDS per DMA
                resp = None
                if isinstance(fis, FIS_REG_H2D):
                        if fis.command == regs["WRITE_DMA_EXT"]:
-                               resp =  self.hdd.write_dma_cmd(fis)
+                               resp =  self.hdd.write_dma_callback(fis)
                        elif fis.command == regs["READ_DMA_EXT"]:
-                               resp = self.hdd.read_dma_cmd(fis)
+                               resp = self.hdd.read_dma_callback(fis)
                        elif fis.command == regs["IDENTIFY_DEVICE_DMA"]:
-                               resp = self.hdd.identify_device_dma_cmd(fis)
+                               resp = self.hdd.identify_device_dma_callback(fis)
                elif isinstance(fis, FIS_DATA):
-                       resp = self.hdd.data_cmd(fis)
+                       resp = self.hdd.data_callback(fis)
 
                if resp is not None:
                        for packet in resp:
                                self.transport.send(packet)
 
 # HDD model
+def print_hdd(s):
+       print_with_prefix(s, "[HDD]: ")
+
 class HDDMemRegion:
-       def __init__(self, base, length):
+       def __init__(self, base, count, sector_size):
                self.base = base
-               self.length = length
-               self.data = [0]*(length//4)
+               self.count = count
+               self.data = [0]*(count*sector_size//4)
 
 class HDD(Module):
        def __init__(self,
-                       phy_debug=False,
                        link_debug=False, link_random_level=0,
                        transport_debug=False, transport_loopback=False,
-                       command_debug=False,
                        hdd_debug=False, hdd_sector_size=512,
                        ):
                ###
-               self.submodules.phy = PHYLayer(phy_debug)
+               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, command_debug)
+               self.submodules.command = CommandLayer(self.transport)
 
                self.command.set_hdd(self)
 
-               self.hdd_debug = hdd_debug
-               self.hdd_sector_size = hdd_sector_size
+               self.debug = hdd_debug
+               self.sector_size = hdd_sector_size
                self.mem = None
-               self.wr_address = 0
-               self.wr_length = 0
-               self.wr_cnt = 0
-               self.rd_address = 0
-               self.rd_length = 0
-
-       def allocate_mem(self, base, length):
-               if self.hdd_debug:
-                       print("[HDD] : Allocating {n} bytes at 0x{a}".format(n=length, a=base))
-               self.mem = HDDMemRegion(base, length)
-
-       def write_mem(self, adr, data):
-               if self.hdd_debug:
-                       print("[HDD] : Writing {n} bytes at 0x{a}".format(n=len(data)*4, a=adr))
-               current_adr = (adr-self.mem.base)//4
+               self.wr_sector = 0
+               self.wr_end_sector = 0
+
+       def dwords2sectors(self, n):
+               return math.ceil(n*4/self.sector_size)
+
+       def sectors2dwords(self, n):
+               return n*self.sector_size//4
+
+       def malloc(self, sector, count):
+               if self.debug:
+                       s = "Allocating {n} sectors: {s} to {e}".format(n=count, s=sector, e=sector+count)
+                       s += " ({} KB)".format(count*self.sector_size//1024)
+                       print_hdd(s)
+               self.mem = HDDMemRegion(sector, count, self.sector_size)
+
+       def write(self, sector, data):
+               n = math.ceil(self.dwords2sectors(len(data)))
+               if self.debug:
+                       print_hdd("Writing sector {s} to {e}".format(s=sector, e=sector+n-1))
                for i in range(len(data)):
-                       self.mem.data[current_adr+i] = data[i]
+                       offset = self.sectors2dwords(sector)
+                       self.mem.data[offset+i] = data[i]
 
-       def read_mem(self, adr, length=1):
-               if self.hdd_debug:
-                       print("[HDD] : Reading {n} bytes at 0x{a}".format(n=length, a=adr))
-               current_adr = (adr-self.mem.base)//4
+       def read(self, sector, count):
+               if self.debug:
+                       print_hdd("Reading sector {s} to {e}".format(s=sector, e=sector+count-1))
                data = []
-               for i in range(length//4):
-                       data.append(self.mem.data[current_adr+i])
+               for i in range(self.sectors2dwords(count)):
+                       data.append(self.mem.data[self.sectors2dwords(sector)+i])
                return data
 
-       def write_dma_cmd(self, fis):
-               self.wr_address = fis.lba_lsb
-               self.wr_length = fis.count*self.hdd_sector_size
-               self.wr_cnt = 0
+       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_cmd(self, fis):
-               self.rd_address = fis.lba_lsb
-               self.rd_length = fis.count*self.hdd_sector_size
-               self.rd_cnt = 0
-               n = math.ceil(self.rd_length/(2048*4))
-               packets = [FIS_REG_D2H()]
-               for i in range(n):
-                       length = min(self.rd_length-self.rd_cnt, 2048)
-                       packet = self.read_mem(self.rd_address, length)
-                       packet.insert(0, 0)
-                       packets.insert(0, FIS_DATA(packet, direction="D2H"))
-               return packets
-
-       def identify_dma_cmd(self, fis):
+       def read_dma_callback(self, fis):
+               sector = fis.lba_lsb + (fis.lba_msb << 32)
+               packet = self.read(sector, fis.count)
+               packet.insert(0, 0)
+               return [FIS_DATA(packet, direction="D2H"), FIS_REG_D2H()]
+
+       def identify_dma_callback(self, fis):
                packet = [i for i in range(256)]
                packet.insert(0, 0)
                return [FIS_DATA(packet, direction="D2H"), FIS_REG_D2H()]
 
-       def data_cmd(self, fis):
-               self.write_mem(self.wr_address, fis.packet[1:])
-               self.wr_cnt += len(fis.packet[1:])*4
-               if self.wr_length == self.wr_cnt:
+       def data_callback(self, fis):
+               self.write(self.wr_sector, fis.packet[1:])
+               self.wr_sector += self.dwords2sectors(len(fis.packet[1:]))
+               if self.wr_sector == self.wr_end_sector:
                        return [FIS_REG_D2H()]
                else:
                        return [FIS_DMA_ACTIVATE_D2H()]
index 92828d1e08397e16fb950dbd4b7c945fbd047aeb..30baa0526ba6fbba532f95b36d1398c744e4edca 100644 (file)
@@ -54,7 +54,7 @@ class SATATransportTX(Module):
                                        sink.ack.eq(1)
                                )
                        ).Else(
-                               sink.ack.eq(sink.stb)
+                               sink.ack.eq(1)
                        )
                )
                fsm.act("SEND_REG_H2D_CMD",
@@ -161,7 +161,6 @@ class SATATransportRX(Module):
                                ).Elif(test_type("DATA"),
                                        NextState("RECEIVE_DATA_CMD"),
                                ).Else(
-                                       # XXX: Better to ack?
                                        link.source.ack.eq(1)
                                )
                        ).Else(
@@ -180,7 +179,7 @@ class SATATransportRX(Module):
                        source.sop.eq(1),
                        source.eop.eq(1),
                        _decode_cmd(encoded_cmd, fis_reg_d2h_layout, source),
-                       If(source.ack,
+                       If(source.stb & source.ack,
                                NextState("IDLE")
                        )
                )
@@ -196,7 +195,7 @@ class SATATransportRX(Module):
                        source.sop.eq(1),
                        source.eop.eq(1),
                        _decode_cmd(encoded_cmd, fis_dma_activate_d2h_layout, source),
-                       If(source.ack,
+                       If(source.stb & source.ack,
                                NextState("IDLE")
                        )
                )