improve BIST and clean up (remove support of identify command and debug code)

This commit is contained in:
Florent Kermarrec 2014-12-23 18:26:07 +01:00
parent 38d3f3697b
commit 678ee33af4
14 changed files with 176 additions and 448 deletions

View file

@ -5,6 +5,11 @@ from lib.sata.command import SATACommand
class SATACON(Module):
def __init__(self, phy, sector_size=512, max_count=8):
self.sector_size = sector_size
self.max_count = max_count
###
self.link = SATALink(phy)
self.transport = SATATransport(self.link)
self.command = SATACommand(self.transport, sector_size=sector_size, max_count=max_count)

View file

@ -1,10 +1,11 @@
from lib.sata.common import *
from lib.sata.link.scrambler import Scrambler
from migen.bank.description import *
class SATABIST(Module):
def __init__(self, sector_size=512):
self.sink = sink = Sink(command_rx_description(32))
self.source = source = Source(command_tx_description(32))
class SATABISTUnit(Module):
def __init__(self, sata_con):
sink = sata_con.source
source = sata_con.sink
self.start = Signal()
self.sector = Signal(48)
@ -36,7 +37,7 @@ class SATABIST(Module):
fsm.act("SEND_WRITE_CMD_AND_DATA",
source.stb.eq(1),
source.sop.eq((counter.value == 0)),
source.eop.eq((counter.value == (sector_size//4*self.count)-1)),
source.eop.eq((counter.value == (sata_con.sector_size//4*self.count)-1)),
source.write.eq(1),
source.sector.eq(self.sector),
source.count.eq(self.count),
@ -87,3 +88,65 @@ class SATABIST(Module):
)
)
)
class SATABIST(Module, AutoCSR):
def __init__(self, sata_con):
self._start = CSR()
self._start_sector = CSRStorage(48)
self._count = CSRStorage(4)
self._stop = CSRStorage()
self._sector = CSRStatus(48)
self._errors = CSRStatus(32)
start = self._start.r & self._start.re
start_sector = self._start_sector.storage
count = self._count.storage
stop = self._stop.storage
update = Signal()
sector = self._sector.status
errors = self._errors.status
###
self.unit = SATABISTUnit(sata_con)
self.comb += [
self.unit.sector.eq(sector),
self.unit.count.eq(count)
]
self.fsm = fsm = FSM(reset_state="IDLE")
# FSM
fsm.act("IDLE",
If(start,
NextState("START")
)
)
fsm.act("START",
self.unit.start.eq(1),
NextState("WAIT_DONE")
)
fsm.act("WAIT_DONE",
If(self.unit.done,
NextState("CHECK_PREPARE")
).Elif(stop,
NextState("IDLE")
)
)
fsm.act("CHECK_PREPARE",
update.eq(1),
NextState("START")
)
self.sync += [
If(start,
errors.eq(0),
sector.eq(start_sector)
).Elif(update,
errors.eq(errors + self.unit.data_errors),
sector.eq(sector + count)
)
]

View file

@ -3,7 +3,6 @@ from lib.sata.common import *
tx_to_rx = [
("write", 1),
("read", 1),
("identify", 1),
("count", 4)
]
@ -39,8 +38,6 @@ class SATACommandTX(Module):
NextState("SEND_WRITE_DMA_CMD")
).Elif(sink.read,
NextState("SEND_READ_DMA_CMD")
).Elif(sink.identify,
NextState("SEND_IDENTIFY_CMD")
).Else(
sink.ack.eq(1)
)
@ -87,24 +84,11 @@ class SATACommandTX(Module):
NextState("IDLE")
)
)
fsm.act("SEND_IDENTIFY_CMD",
transport.sink.stb.eq(sink.stb),
transport.sink.sop.eq(1),
transport.sink.eop.eq(1),
transport.sink.type.eq(fis_types["REG_H2D"]),
transport.sink.c.eq(1),
transport.sink.command.eq(regs["IDENTIFY_DEVICE_DMA"]),
sink.ack.eq(transport.sink.ack),
If(sink.stb & sink.ack,
NextState("IDLE")
)
)
self.comb += [
If(sink.stb,
to_rx.write.eq(sink.write),
to_rx.read.eq(sink.read),
to_rx.identify.eq(sink.identify),
to_rx.count.eq(sink.count)
)
]
@ -131,15 +115,10 @@ class SATACommandRX(Module):
transport.source.ack.eq(1),
If(from_tx.write,
NextState("WAIT_WRITE_ACTIVATE")
).Elif(from_tx.read | from_tx.identify,
).Elif(from_tx.read,
NextState("WAIT_READ_DATA")
)
)
identify = Signal()
self.sync += \
If(fsm.ongoing("IDLE"),
identify.eq(from_tx.identify)
)
fsm.act("WAIT_WRITE_ACTIVATE",
transport.source.ack.eq(1),
If(transport.source.stb,
@ -202,11 +181,10 @@ class SATACommandRX(Module):
)
fsm.act("PRESENT_READ_RESPONSE",
cmd_fifo.sink.stb.eq(1),
cmd_fifo.sink.read.eq(~identify),
cmd_fifo.sink.identify.eq(identify),
cmd_fifo.sink.read.eq(1),
cmd_fifo.sink.success.eq(1),
cmd_fifo.sink.failed.eq(0),
If(~cmd_fifo.fifo.readable, # Note: simulate a depth=1 fifo
If(~cmd_fifo.fifo.readable, # Note: simulate a fifo with depth=1
If(cmd_fifo.sink.stb & cmd_fifo.sink.ack,
If(cmd_fifo.sink.failed,
data_fifo.reset.eq(1)
@ -220,7 +198,7 @@ class SATACommandRX(Module):
out_fsm.act("IDLE",
If(cmd_fifo.source.stb & cmd_fifo.source.write,
NextState("PRESENT_WRITE_RESPONSE"),
).Elif(cmd_fifo.source.stb & (cmd_fifo.source.read | cmd_fifo.source.identify),
).Elif(cmd_fifo.source.stb & (cmd_fifo.source.read),
If(cmd_fifo.source.success,
NextState("PRESENT_READ_RESPONSE_SUCCESS"),
).Else(
@ -242,7 +220,6 @@ class SATACommandRX(Module):
out_fsm.act("PRESENT_READ_RESPONSE_SUCCESS",
source.stb.eq(data_fifo.source.stb),
source.read.eq(cmd_fifo.source.read),
source.identify.eq(cmd_fifo.source.identify),
source.success.eq(1),
source.sop.eq(data_fifo.source.sop),
source.eop.eq(data_fifo.source.eop),
@ -258,7 +235,6 @@ class SATACommandRX(Module):
source.sop.eq(1),
source.eop.eq(1),
source.read.eq(cmd_fifo.source.read),
source.identify.eq(cmd_fifo.source.identify),
source.failed.eq(1),
If(source.stb & source.ack,
cmd_fifo.source.ack.eq(1),

View file

@ -143,15 +143,13 @@ def transport_rx_description(dw):
# Command Layer
regs = {
"WRITE_DMA_EXT" : 0x35,
"READ_DMA_EXT" : 0x25,
"IDENTIFY_DEVICE_DMA" : 0xEE
"READ_DMA_EXT" : 0x25
}
def command_tx_description(dw):
layout = [
("write", 1),
("read", 1),
("identify", 1),
("sector", 48),
("count", 4),
("data", dw)
@ -162,7 +160,6 @@ def command_rx_description(dw):
layout = [
("write", 1),
("read", 1),
("identify", 1),
("success", 1),
("failed", 1),
("data", dw)
@ -173,7 +170,6 @@ def command_rx_cmd_description(dw):
layout = [
("write", 1),
("read", 1),
("identify", 1),
("success", 1),
("failed", 1)
]

View file

@ -10,7 +10,7 @@ from_rx = [
]
class SATALinkTX(Module):
def __init__(self, phy, disable_cont=False):
def __init__(self, phy):
self.sink = Sink(link_description(32))
self.from_rx = Sink(from_rx)
@ -34,7 +34,7 @@ class SATALinkTX(Module):
# inserter CONT and scrambled data between
# CONT and next primitive
self.cont = cont = SATACONTInserter(phy_description(32), disable=False)
self.cont = cont = SATACONTInserter(phy_description(32))
# datas / primitives mux
insert = Signal(32)
@ -200,7 +200,7 @@ class SATALinkRX(Module):
)
)
fsm.act("WTRM",
# XXX: check CRC resutlt to return R_ERR or R_OK
# XXX: check CRC result to return R_ERR or R_OK
insert.eq(primitives["R_OK"]),
If(det == primitives["SYNC"],
NextState("IDLE")
@ -215,8 +215,8 @@ class SATALinkRX(Module):
]
class SATALink(Module):
def __init__(self, phy, disable_tx_cont=False):
self.tx = SATALinkTX(phy, disable_tx_cont)
def __init__(self, phy):
self.tx = SATALinkTX(phy)
self.rx = SATALinkRX(phy)
self.comb += Record.connect(self.rx.to_tx, self.tx.from_rx)
self.sink, self.source = self.tx.sink, self.rx.source

View file

@ -4,15 +4,12 @@ from lib.sata.link.scrambler import Scrambler
from migen.genlib.misc import optree
class SATACONTInserter(Module):
def __init__(self, description, disable=False):
def __init__(self, description):
self.sink = sink = Sink(description)
self.source = source = Source(description)
###
if disable:
self.comb += Record.connect(self.sink, self.source)
else:
self.counter = counter = Counter(max=4)
is_data = Signal()

View file

@ -7,12 +7,11 @@ from lib.sata.test.hdd import *
from lib.sata.test.common import *
class CommandTXPacket(list):
def __init__(self, write=0, read=0, identify=0, sector=0, count=0, data=[]):
def __init__(self, write=0, read=0, sector=0, count=0, data=[]):
self.ongoing = False
self.done = False
self.write = write
self.read = read
self.identify = identify
self.sector = sector
self.count = count
for d in data:
@ -26,7 +25,6 @@ class CommandStreamer(PacketStreamer):
PacketStreamer.do_simulation(self, selfp)
selfp.source.write = self.packet.write
selfp.source.read = self.packet.read
selfp.source.identify = self.packet.identify
selfp.source.sector = self.packet.sector
selfp.source.count = self.packet.count
@ -36,7 +34,6 @@ class CommandRXPacket(list):
self.done = False
self.write = 0
self.read = 0
self.identify = 0
self.success = 0
self.failed = 0
@ -50,7 +47,6 @@ class CommandLogger(PacketLogger):
self.packet = CommandRXPacket()
self.packet.write = selfp.sink.write
self.packet.read = selfp.sink.read
self.packet.identify = selfp.sink.identify
self.packet.sucess = selfp.sink.success
self.packet.failed = selfp.sink.failed
self.packet.append(selfp.sink.data)
@ -100,8 +96,5 @@ class TB(Module):
s, l, e = check(write_data, read_data)
print("shift "+ str(s) + " / length " + str(l) + " / errors " + str(e))
identify_packet = CommandTXPacket(identify=1)
yield from self.streamer.send(identify_packet)
if __name__ == "__main__":
run_simulation(TB(), ncycles=2048, vcd_name="my.vcd", keep_files=True)

View file

@ -421,8 +421,6 @@ class CommandLayer(Module):
resp = self.hdd.write_dma_callback(fis)
elif fis.command == regs["READ_DMA_EXT"]:
resp = self.hdd.read_dma_callback(fis)
elif fis.command == regs["IDENTIFY_DEVICE_DMA"]:
resp = self.hdd.identify_device_dma_callback(fis)
elif isinstance(fis, FIS_DATA):
resp = self.hdd.data_callback(fis)
@ -508,12 +506,6 @@ class HDD(Module):
packet.insert(0, 0)
return [FIS_DATA(packet, direction="D2H"), FIS_REG_D2H()]
def identify_device_dma_callback(self, fis):
print_hdd("Identify device request")
packet = [i for i in range(256)]
packet.insert(0, 0)
return [FIS_DATA(packet, direction="D2H"), FIS_REG_D2H()]
def data_callback(self, fis):
self.write(self.wr_sector, fis.packet[1:])
self.wr_sector += self.dwords2sectors(len(fis.packet[1:]))

View file

@ -152,179 +152,6 @@ class ClockLeds(Module):
sata_tx_cnt.eq(sata_tx_cnt-1)
)
class CommandGenerator(Module, AutoCSR):
def __init__(self, sata_con, sector_size):
self._write = CSR()
self._read = CSR()
self._identify = CSR()
self._sector = CSRStorage(48)
self._count = CSRStorage(4)
self._data = CSRStorage(32) # Note: fixed data, add a fifo later
self._sucess = CSRStatus()
self._failed = CSRStatus()
self.fsm = fsm = FSM(reset_state="IDLE")
def new_command(csr):
return csr.r & csr.re
cnt = Signal(16)
sector = self._sector.storage
count = self._count.storage
data = self._data.storage
success = self._sucess.status
failed = self._failed.status
clr_status = Signal()
set_success = Signal()
set_failed = Signal()
self.sync += [
If(clr_status,
success.eq(0),
failed.eq(0),
).Elif(set_success,
success.eq(1)
).Elif(set_failed,
failed.eq(1)
)
]
self.comb += sata_con.source.ack.eq(1)
# FSM
fsm.act("IDLE",
clr_status.eq(1),
If(new_command(self._write),
NextState("SEND_WRITE_CMD")
).Elif(new_command(self._read),
NextState("SEND_READ_CMD")
).Elif(new_command(self._identify),
NextState("SEND_IDENTIFY_CMD")
)
)
fsm.act("SEND_WRITE_CMD",
sata_con.sink.stb.eq(1),
sata_con.sink.sop.eq(cnt == 0),
sata_con.sink.eop.eq(cnt == (count*sector_size-1)),
sata_con.sink.write.eq(1),
sata_con.sink.sector.eq(sector),
sata_con.sink.count.eq(count),
sata_con.sink.data.eq(data),
If(sata_con.sink.eop & sata_con.sink.ack,
NextState("WAIT_WRITE_ACK")
)
)
self.sync += [
If(fsm.ongoing("IDLE"),
cnt.eq(0)
).Elif(sata_con.sink.stb & sata_con.sink.stb,
cnt.eq(cnt+1)
)
]
fsm.act("WAIT_WRITE_ACK",
# XXX: add check of success / failed
If(sata_con.source.stb & sata_con.source.eop,
set_success.eq(1),
NextState("IDLE")
)
)
fsm.act("SEND_READ_CMD",
sata_con.sink.stb.eq(1),
sata_con.sink.sop.eq(1),
sata_con.sink.eop.eq(1),
sata_con.sink.read.eq(1),
sata_con.sink.sector.eq(sector),
sata_con.sink.count.eq(count),
If(sata_con.sink.ack,
NextState("WAIT_READ_ACK_AND_DATA")
)
)
fsm.act("WAIT_READ_ACK_AND_DATA",
# XXX: add check of success / failed and receive data
If(sata_con.source.stb & sata_con.source.eop,
set_success.eq(1),
NextState("IDLE")
)
)
fsm.act("SEND_IDENTIFY_CMD",
sata_con.sink.stb.eq(1),
sata_con.sink.sop.eq(1),
sata_con.sink.eop.eq(1),
sata_con.sink.identify.eq(1),
If(sata_con.sink.ack,
NextState("WAIT_IDENTIFY_ACK_AND_DATA")
)
)
fsm.act("WAIT_IDENTIFY_ACK_AND_DATA",
# XXX: add check of success / failed and receive data
If(sata_con.source.stb & sata_con.source.eop,
set_success.eq(1),
NextState("IDLE")
)
)
class BIST(Module, AutoCSR):
def __init__(self, sata_con, sector_size):
self._start = CSR()
self._stop = CSR()
self._sector = CSRStatus(48)
self._ctrl_errors = CSRStatus(32)
self._data_errors = CSRStatus(32)
check_prepare = Signal()
sector = self._sector.status
ctrl_errors = self._ctrl_errors.status
data_errors = self._data_errors.status
###
self.sata_bist = SATABIST(sector_size)
self.comb += [
Record.connect(sata_con.source, self.sata_bist.sink),
Record.connect(self.sata_bist.source, sata_con.sink)
]
self.fsm = fsm = FSM(reset_state="IDLE")
self.comb += [
self.sata_bist.sector.eq(sector),
self.sata_bist.count.eq(4)
]
# FSM
fsm.act("IDLE",
If(self._start.r & self._start.re,
NextState("START")
)
)
fsm.act("START",
self.sata_bist.start.eq(1),
NextState("WAIT_DONE")
)
fsm.act("WAIT_DONE",
If(self.sata_bist.done,
NextState("CHECK_PREPARE")
).Elif(self._stop.r & self._stop.re,
NextState("IDLE")
)
)
fsm.act("CHECK_PREPARE",
check_prepare.eq(1),
NextState("START")
)
self.sync += [
If(check_prepare,
ctrl_errors.eq(ctrl_errors + self.sata_bist.ctrl_errors),
data_errors.eq(data_errors + self.sata_bist.data_errors),
sector.eq(sector+4)
)
]
class TestDesign(UART2WB, AutoCSR):
default_platform = "kc705"
csr_map = {
@ -342,8 +169,7 @@ class TestDesign(UART2WB, AutoCSR):
self.sata_phy = SATAPHY(platform.request("sata_host"), clk_freq, host=True, speed="SATA2")
self.sata_con = SATACON(self.sata_phy, sector_size=512, max_count=8)
#self.command_generator = CommandGenerator(self.sata_con, sector_size=512)
self.bist = BIST(self.sata_con, sector_size=512)
self.bist = SATABIST(self.sata_con)
self.clock_leds = ClockLeds(platform)
@ -380,7 +206,6 @@ class TestDesign(UART2WB, AutoCSR):
self.sata_con.sink.ack,
self.sata_con.sink.write,
self.sata_con.sink.read,
self.sata_con.sink.identify,
self.sata_con.source.stb,
self.sata_con.source.sop,
@ -388,7 +213,6 @@ class TestDesign(UART2WB, AutoCSR):
self.sata_con.source.ack,
self.sata_con.source.write,
self.sata_con.source.read,
self.sata_con.source.identify,
self.sata_con.source.success,
self.sata_con.source.failed,
self.sata_con.source.data

View file

@ -5,18 +5,44 @@ from tools import *
sector_size = 512
wb.open()
regs = wb.regs
###
regs.bist_start.write(1)
last_sector = 0
class SATABISTDriver:
def __init__(self, regs):
self.regs = regs
self.last_sector = 0
self.last_time = time.time()
self.last_errors = 0
def start_loopback(self, sector, count):
self.regs.bist_start_sector.write(sector)
self.regs.bist_count.write(count)
self.regs.bist_stop.write(0)
self.regs.bist_start.write(1)
def stop(self):
self.regs.bist_stop.write(1)
def show_status(self):
errors = self.regs.bist_errors.read() - self.last_errors
self.last_errors += errors
sector = self.regs.bist_sector.read()
n = sector - self.last_sector
self.last_sector = sector
t = self.last_time - time.time()
self.last_time = time.time()
print("%4.2f Mb/sec errors=%d sector=%d" %(n*512*8*2/(1024*1024), errors, sector))
bist = SATABISTDriver(wb.regs)
try:
bist.start_loopback(0, 4)
while True:
bist.show_status()
time.sleep(1)
sector = regs.bist_sector.read()
n_sectors = sector - last_sector
last_sector = sector
n_bytes = n_sectors*sector_size*4*2
ctrl_errors = regs.bist_ctrl_errors.read()
data_errors = regs.bist_data_errors.read()
print("%04d MB/s / data_errors %08d / ctrl_errors %08d " %(n_bytes/(1024*1024), data_errors, ctrl_errors))
except KeyboardInterrupt:
pass
bist.stop()
###
wb.close()

View file

@ -1,38 +0,0 @@
import time
from config import *
from tools import *
from miscope.host.drivers import MiLaDriver
mila = MiLaDriver(wb.regs, "mila")
wb.open()
regs = wb.regs
###
cond = {
#"sata_phy_source_source_payload_data" : primitives["R_RDY"],
#"sata_phy_source_source_payload_data" : primitives["R_OK"],
"sata_phy_source_source_payload_data" : primitives["X_RDY"],
}
trigger = 0
mask = 0
for k, v in cond.items():
trigger |= getattr(mila, k+"_o")*v
mask |= getattr(mila, k+"_m")
mila.prog_term(port=0, trigger=trigger, mask=mask)
mila.prog_sum("term")
# Trigger / wait / receive
mila.trigger(offset=32, length=512)
regs.command_generator_identify.write(1)
mila.wait_done()
mila.read()
mila.export("dump.vcd")
###
wb.close()
print_link_trace(mila,
tx_data_name="sata_phy_sink_sink_payload_data",
rx_data_name="sata_phy_source_source_payload_data"
)

View file

@ -1,23 +0,0 @@
from config import *
from miscope.host.drivers import MiLaDriver
mila = MiLaDriver(wb.regs, "mila", use_rle=False)
wb.open()
###
trigger0 = mila.cont_remover_source_stb_o*1
mask0 = mila.cont_remover_source_stb_m
trigger0 = 0
mask0 = 0
mila.prog_term(port=0, trigger=trigger0, mask=mask0)
mila.prog_sum("term")
# Trigger / wait / receive
mila.trigger(offset=32, length=1024)
mila.wait_done()
mila.read()
mila.export("dump.vcd")
mila.export("dump.csv")
###
wb.close()

View file

@ -1,41 +0,0 @@
import time
from config import *
from tools import *
from miscope.host.drivers import MiLaDriver
mila = MiLaDriver(wb.regs, "mila")
wb.open()
regs = wb.regs
###
cond = {
#"sata_phy_source_source_payload_data" : primitives["R_RDY"],
#"sata_phy_source_source_payload_data" : primitives["R_OK"],
#"sata_phy_source_source_payload_data" : primitives["X_RDY"],
"sata_con_source_source_stb" : 1,
}
trigger = 0
mask = 0
for k, v in cond.items():
trigger |= getattr(mila, k+"_o")*v
mask |= getattr(mila, k+"_m")
mila.prog_term(port=0, trigger=trigger, mask=mask)
mila.prog_sum("term")
# Trigger / wait / receive
mila.trigger(offset=32, length=512)
regs.command_generator_sector.write(0)
regs.command_generator_count.write(1)
regs.command_generator_read.write(1)
mila.wait_done()
mila.read()
mila.export("dump.vcd")
###
wb.close()
print_link_trace(mila,
tx_data_name="sata_phy_sink_sink_payload_data",
rx_data_name="sata_phy_source_source_payload_data"
)

View file

@ -1,42 +0,0 @@
import time
from config import *
from tools import *
from miscope.host.drivers import MiLaDriver
mila = MiLaDriver(wb.regs, "mila")
wb.open()
regs = wb.regs
###
cond = {
#"sata_phy_source_source_payload_data" : primitives["R_RDY"],
#"sata_phy_source_source_payload_data" : primitives["R_OK"],
#"sata_phy_source_source_payload_data" : primitives["X_RDY"],
"sata_con_source_source_stb" : 1,
}
trigger = 0
mask = 0
for k, v in cond.items():
trigger |= getattr(mila, k+"_o")*v
mask |= getattr(mila, k+"_m")
mila.prog_term(port=0, trigger=trigger, mask=mask)
mila.prog_sum("term")
# Trigger / wait / receive
mila.trigger(offset=32, length=512)
regs.command_generator_sector.write(0)
regs.command_generator_count.write(1)
regs.command_generator_data.write(0x12345678)
regs.command_generator_write.write(1)
mila.wait_done()
mila.read()
mila.export("dump.vcd")
###
wb.close()
print_link_trace(mila,
tx_data_name="sata_phy_sink_sink_payload_data",
rx_data_name="sata_phy_source_source_payload_data"
)