"IDENTIFY_DEVICE" : 0xEC
}
+reg_d2h_status = {
+ "bsy" : 7,
+ "drdy" : 6,
+ "df" : 5,
+ "se" : 5,
+ "dwe" : 4,
+ "drq" : 3,
+ "ae" : 2,
+ "sns" : 1,
+ "cc" : 0,
+ "err" : 0
+}
+
def command_tx_description(dw):
layout = [
("write", 1),
]
rx_to_tx = [
- ("dma_activate", 1)
+ ("dma_activate", 1),
+ ("d2h_error", 1)
]
class LiteSATACommandTX(Module):
dwords_counter.reset.eq(1),
If(from_rx.dma_activate,
NextState("SEND_DATA")
+ ).Elif(from_rx.d2h_error,
+ sink.ack.eq(1),
+ NextState("IDLE")
)
)
fsm.act("SEND_DATA",
)
self.comb += read_done.eq(self.dwords_counter.value == read_ndwords)
+ d2h_error = Signal()
+ clr_d2h_error = Signal()
+ set_d2h_error = Signal()
+ self.sync += \
+ If(clr_d2h_error,
+ d2h_error.eq(0)
+ ).Elif(set_d2h_error,
+ d2h_error.eq(1)
+ )
+
self.fsm = fsm = FSM(reset_state="IDLE")
fsm.act("IDLE",
self.dwords_counter.reset.eq(1),
transport.source.ack.eq(1),
+ clr_d2h_error.eq(1),
If(from_tx.write,
NextState("WAIT_WRITE_ACTIVATE_OR_REG_D2H")
).Elif(from_tx.read,
If(test_type("DMA_ACTIVATE_D2H"),
dma_activate.eq(1),
).Elif(test_type("REG_D2H"),
- # XXX: use status and error fields of REG_D2H
+ set_d2h_error.eq(transport.source.status[reg_d2h_status["err"]]),
NextState("PRESENT_WRITE_RESPONSE")
)
)
cmd_buffer.sink.stb.eq(1),
cmd_buffer.sink.write.eq(1),
cmd_buffer.sink.last.eq(1),
- cmd_buffer.sink.success.eq(~transport.source.error),
- cmd_buffer.sink.failed.eq(transport.source.error),
+ cmd_buffer.sink.success.eq(~transport.source.error & ~d2h_error),
+ cmd_buffer.sink.failed.eq(transport.source.error | d2h_error),
If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
NextState("IDLE")
)
If(test_type("DATA"),
NextState("PRESENT_READ_DATA")
).Elif(test_type("REG_D2H"),
- # XXX: use status and error fields of REG_D2H
+ set_d2h_error.eq(transport.source.status[reg_d2h_status["err"]]),
NextState("PRESENT_READ_RESPONSE")
)
)
)
fsm.act("PRESENT_PIO_SETUP_D2H",
transport.source.ack.eq(1),
- # XXX : Check error/ status
If(transport.source.stb & transport.source.eop,
NextState("WAIT_READ_DATA_OR_REG_D2H")
)
cmd_buffer.sink.read.eq(~identify),
cmd_buffer.sink.identify.eq(identify),
cmd_buffer.sink.last.eq(read_done | identify),
- cmd_buffer.sink.success.eq(~read_error),
- cmd_buffer.sink.failed.eq(read_error),
+ cmd_buffer.sink.success.eq(~read_error & ~d2h_error),
+ cmd_buffer.sink.failed.eq(read_error | d2h_error),
If(cmd_buffer.sink.stb & cmd_buffer.sink.ack,
If(cmd_buffer.sink.failed,
data_buffer.reset.eq(1)
self.comb += [
to_tx.dma_activate.eq(dma_activate),
+ to_tx.d2h_error.eq(d2h_error)
]
class LiteSATACommand(Module):
self.random = Signal()
self.done = Signal()
+ self.aborted = Signal()
self.errors = Signal(32) # Note: Not used for writes
###
NextState("IDLE")
)
)
+ self.sync += If(sink.stb & sink.ack, self.aborted.eq(sink.failed))
class LiteSATABISTChecker(Module):
def __init__(self, sata_master_port):
self.random = Signal()
self.done = Signal()
+ self.aborted = Signal()
self.errors = Signal(32)
###
)
)
)
+ self.sync += If(sink.stb & sink.ack, self.aborted.eq(sink.failed))
class LiteSATABISTUnitCSR(Module, AutoCSR):
def __init__(self, bist_unit):
self._count = CSRStorage(16)
self._random = CSRStorage()
self._done = CSRStatus()
+ self._aborted = CSRStatus()
self._errors = CSRStatus(32)
self._cycles = CSRStatus(32)
bist_unit.random.eq(self._random.storage),
self._done.status.eq(bist_unit.done),
+ self._aborted.status.eq(bist_unit.aborted),
self._errors.status.eq(bist_unit.errors)
]
self.name = name
self.frequency = regs.identifier_frequency.read()
self.time = 0
- for s in ["start", "sector", "count", "random", "done", "errors", "cycles"]:
+ for s in ["start", "sector", "count", "random", "done", "aborted", "errors", "cycles"]:
setattr(self, s, getattr(regs, name + "_"+ s))
- def run(self, sector, count, random):
+ def run(self, sector, count, random, blocking=True):
self.sector.write(sector)
self.count.write(count)
self.random.write(random)
self.start.write(1)
- while (self.done.read() == 0):
- pass
- self.time = self.cycles.read()/self.frequency
- speed = (count*logical_sector_size)/self.time
- errors = self.errors.read()
- return (speed, errors)
+ if blocking:
+ while (self.done.read() == 0):
+ pass
+ aborted = self.aborted.read()
+ if not aborted:
+ self.time = self.cycles.read()/self.frequency
+ speed = (count*logical_sector_size)/self.time
+ errors = self.errors.read()
+ else:
+ speed = 0
+ errors = -1
+ return (aborted, errors, speed)
class LiteSATABISTGeneratorDriver(LiteSATABISTUnitDriver):
def __init__(self, regs, name):
self.data += [word_lsb, word_msb]
self.source_ack.write(1)
- def run(self):
+ def run(self, blocking=True):
self.read_fifo() # flush the fifo before we start
self.start.write(1)
- while (self.done.read() == 0):
- pass
- self.read_fifo()
- self.decode()
+ if blocking:
+ while (self.done.read() == 0):
+ pass
+ self.read_fifo()
+ self.decode()
def decode(self):
self.serial_number = ""
description="""\
SATA BIST utility.
""")
- parser.add_argument("-s", "--transfer_size", default=4, help="transfer sizes (in MB, up to 16MB)")
+ parser.add_argument("-s", "--transfer_size", default=1024, help="transfer sizes (in KB, up to 16MB)")
parser.add_argument("-l", "--total_length", default=256, help="total transfer length (in MB, up to HDD capacity)")
parser.add_argument("-r", "--random", action="store_true", help="use random data")
parser.add_argument("-c", "--continuous", action="store_true", help="continuous mode (Escape to exit)")
if not int(args.identify):
sector = 0
- count = int(args.transfer_size)*MB//logical_sector_size
+ count = int(args.transfer_size)*KB//logical_sector_size
length = int(args.total_length)*MB
random = int(args.random)
continuous = int(args.continuous)
try:
while ((sector*logical_sector_size < length) or continuous) and (sector < identify.total_sectors):
+ retry = 0
# generator (write data to HDD)
- write_speed, write_errors = generator.run(sector, count, random)
+ write_done = False
+ while not write_done:
+ write_aborted, write_errors, write_speed = generator.run(sector, count, random)
+ write_done = not write_aborted
+ if not write_done:
+ retry += 1
# checker (read and check data from HDD)
- read_speed, read_errors = checker.run(sector, count, random)
-
- print("sector=%d(%dMB) wr_speed=%4.2fMB/sec rd_speed=%4.2fMB/sec errors=%d" %(
+ read_done = False
+ while not read_done:
+ read_aborted, read_errors, read_speed = checker.run(sector, count, random)
+ read_done = not read_aborted
+ if not read_done:
+ retry += 1
+
+ print("sector=%d(%dMB) wr_speed=%4.2fMB/s rd_speed=%4.2fMB/s errors=%d retry=%d" %(
sector,
sector*logical_sector_size/MB,
write_speed/MB,
read_speed/MB,
- write_errors + read_errors))
+ write_errors + read_errors,
+ retry))
sector += count
except KeyboardInterrupt:
return k
return ""
-def print_link_trace(mila, tx_data_name, rx_data_name):
+def link_trace(mila, tx_data_name, rx_data_name):
+ r = ""
dump = Dump()
dump.add_from_layout(mila.layout, mila.dat)
if var.name == rx_data_name:
rx_data = var.values
- print("")
for i in range(len(tx_data)):
tx = "%08x " %tx_data[i]
tx += decode_primitive(tx_data[i])
rx += decode_primitive(rx_data[i])
rx += " "*(16-len(rx))
- print(tx + rx)
+ r += tx + rx + "\n"
+
+ return r