###
- 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),
]
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")
]
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)
source.eop.eq(1),
source.write.eq(1),
source.success.eq(1),
- If(source.ack,
+ If(source.stb & source.ack,
NextState("IDLE")
)
)
source.read.eq(~identify),
source.identify.eq(identify),
source.success.eq(1),
- If(source.ack,
+ If(source.stb & source.ack,
NextState("IDLE")
)
)
]
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)
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)
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
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)
]
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
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)
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):
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()
self.tx.send(packet)
def receive(self):
- if self.debug:
- print(self)
yield from self.rx.receive()
def __repr__(self):
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"))
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)
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)
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
else:
fis = FIS_UNKNOWN(packet, direction="H2D")
if self.debug:
- print(fis)
+ print_transport(fis)
if self.loopback:
self.send(fis)
else:
# 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
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()]