mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
simplify bist
This commit is contained in:
parent
1c03f72252
commit
4deda89dcb
5 changed files with 113 additions and 151 deletions
145
lib/sata/bist.py
145
lib/sata/bist.py
|
@ -2,23 +2,25 @@ from lib.sata.common import *
|
||||||
from lib.sata.link.scrambler import Scrambler
|
from lib.sata.link.scrambler import Scrambler
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
|
|
||||||
class SATABISTUnit(Module):
|
class SATABIST(Module):
|
||||||
def __init__(self, sata_con):
|
def __init__(self, sata_con):
|
||||||
|
self.write = Signal()
|
||||||
|
self.read = Signal()
|
||||||
|
self.sector = Signal(48)
|
||||||
|
self.count = Signal(16)
|
||||||
|
self.loops = Signal(8)
|
||||||
|
|
||||||
|
self.done = Signal()
|
||||||
|
self.errors = Signal(32)
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
sink = sata_con.source
|
sink = sata_con.source
|
||||||
source = sata_con.sink
|
source = sata_con.sink
|
||||||
|
|
||||||
self.start = Signal()
|
|
||||||
self.write_only = Signal()
|
|
||||||
self.read_only = Signal()
|
|
||||||
self.sector = Signal(48)
|
|
||||||
self.count = Signal(16)
|
|
||||||
self.done = Signal()
|
|
||||||
self.ctrl_errors = Signal(32)
|
|
||||||
self.data_errors = Signal(32)
|
|
||||||
|
|
||||||
self.counter = counter = Counter(bits_sign=32)
|
self.counter = counter = Counter(bits_sign=32)
|
||||||
self.ctrl_error_counter = Counter(self.ctrl_errors, bits_sign=32)
|
self.loops_counter = loops_counter = Counter(bits_sign=8)
|
||||||
self.data_error_counter = Counter(self.data_errors, bits_sign=32)
|
self.error_counter = Counter(self.errors, bits_sign=32)
|
||||||
|
|
||||||
self.scrambler = scrambler = InsertReset(Scrambler())
|
self.scrambler = scrambler = InsertReset(Scrambler())
|
||||||
self.comb += [
|
self.comb += [
|
||||||
|
@ -30,39 +32,39 @@ class SATABISTUnit(Module):
|
||||||
fsm.act("IDLE",
|
fsm.act("IDLE",
|
||||||
self.done.eq(1),
|
self.done.eq(1),
|
||||||
counter.reset.eq(1),
|
counter.reset.eq(1),
|
||||||
If(self.start,
|
loops_counter.reset.eq(1),
|
||||||
self.ctrl_error_counter.reset.eq(1),
|
If(self.write,
|
||||||
self.data_error_counter.reset.eq(1),
|
self.error_counter.reset.eq(1),
|
||||||
If(self.read_only,
|
|
||||||
NextState("SEND_READ_CMD")
|
|
||||||
).Else(
|
|
||||||
NextState("SEND_WRITE_CMD_AND_DATA")
|
NextState("SEND_WRITE_CMD_AND_DATA")
|
||||||
)
|
).Elif(self.read,
|
||||||
|
self.error_counter.reset.eq(1),
|
||||||
|
NextState("SEND_READ_CMD")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("SEND_WRITE_CMD_AND_DATA",
|
fsm.act("SEND_WRITE_CMD_AND_DATA",
|
||||||
source.stb.eq(1),
|
source.stb.eq(1),
|
||||||
source.sop.eq((counter.value == 0)),
|
source.sop.eq(counter.value == 0),
|
||||||
source.eop.eq((counter.value == (logical_sector_size//4*self.count)-1)),
|
source.eop.eq(counter.value == (logical_sector_size//4*self.count)-1),
|
||||||
source.write.eq(1),
|
source.write.eq(1),
|
||||||
source.sector.eq(self.sector),
|
source.sector.eq(self.sector),
|
||||||
source.count.eq(self.count),
|
source.count.eq(self.count),
|
||||||
source.data.eq(scrambler.value),
|
source.data.eq(scrambler.value),
|
||||||
counter.ce.eq(source.ack),
|
If(source.stb & source.ack,
|
||||||
If(source.stb & source.eop & source.ack,
|
counter.ce.eq(1),
|
||||||
|
If(source.eop,
|
||||||
NextState("WAIT_WRITE_ACK")
|
NextState("WAIT_WRITE_ACK")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
)
|
||||||
fsm.act("WAIT_WRITE_ACK",
|
fsm.act("WAIT_WRITE_ACK",
|
||||||
sink.ack.eq(1),
|
sink.ack.eq(1),
|
||||||
If(sink.stb,
|
If(sink.stb,
|
||||||
If(~sink.write | ~sink.success | sink.failed,
|
loops_counter.ce.eq(1),
|
||||||
self.ctrl_error_counter.ce.eq(1)
|
If(loops_counter.value == (self.loops-1),
|
||||||
),
|
|
||||||
If(self.write_only,
|
|
||||||
NextState("IDLE")
|
NextState("IDLE")
|
||||||
).Else(
|
).Else(
|
||||||
NextState("SEND_READ_CMD")
|
counter.reset.eq(1),
|
||||||
|
NextState("SEND_WRITE_CMD_AND_DATA")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -80,9 +82,6 @@ class SATABISTUnit(Module):
|
||||||
)
|
)
|
||||||
fsm.act("WAIT_READ_ACK",
|
fsm.act("WAIT_READ_ACK",
|
||||||
If(sink.stb & sink.read,
|
If(sink.stb & sink.read,
|
||||||
If(~sink.read | ~sink.success | sink.failed,
|
|
||||||
self.ctrl_error_counter.ce.eq(1)
|
|
||||||
),
|
|
||||||
NextState("RECEIVE_READ_DATA")
|
NextState("RECEIVE_READ_DATA")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
@ -91,11 +90,16 @@ class SATABISTUnit(Module):
|
||||||
If(sink.stb,
|
If(sink.stb,
|
||||||
counter.ce.eq(1),
|
counter.ce.eq(1),
|
||||||
If(sink.data != scrambler.value,
|
If(sink.data != scrambler.value,
|
||||||
self.data_error_counter.ce.eq(1)
|
self.error_counter.ce.eq(1)
|
||||||
),
|
),
|
||||||
If(sink.eop,
|
If(sink.eop,
|
||||||
If(sink.last,
|
If(sink.last,
|
||||||
|
loops_counter.ce.eq(1),
|
||||||
|
If(loops_counter.value == (self.loops-1),
|
||||||
NextState("IDLE")
|
NextState("IDLE")
|
||||||
|
).Else(
|
||||||
|
NextState("SEND_READ_CMD")
|
||||||
|
)
|
||||||
).Else(
|
).Else(
|
||||||
NextState("WAIT_READ_ACK")
|
NextState("WAIT_READ_ACK")
|
||||||
)
|
)
|
||||||
|
@ -103,71 +107,24 @@ class SATABISTUnit(Module):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
class SATABIST(Module, AutoCSR):
|
class SATABISTControl(Module, AutoCSR):
|
||||||
def __init__(self, sata_con):
|
def __init__(self, sata_bist):
|
||||||
self._start = CSR()
|
self._write = CSR()
|
||||||
self._start_sector = CSRStorage(48)
|
self._read = CSR()
|
||||||
|
self._sector = CSRStorage(48)
|
||||||
self._count = CSRStorage(16)
|
self._count = CSRStorage(16)
|
||||||
self._write_only = CSRStorage()
|
self._loops = CSRStorage(8)
|
||||||
self._read_only = CSRStorage()
|
|
||||||
|
|
||||||
self._stop = CSRStorage()
|
self._done = CSRStatus()
|
||||||
|
|
||||||
self._sector = CSRStatus(48)
|
|
||||||
self._errors = CSRStatus(32)
|
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
|
|
||||||
|
|
||||||
compute = Signal()
|
|
||||||
|
|
||||||
write_only = self._write_only.storage
|
|
||||||
read_only = self._read_only.storage
|
|
||||||
sector = self._sector.status
|
|
||||||
errors = self._errors.status
|
|
||||||
|
|
||||||
###
|
|
||||||
|
|
||||||
self.unit = SATABISTUnit(sata_con)
|
|
||||||
self.comb += [
|
self.comb += [
|
||||||
self.unit.write_only.eq(write_only),
|
sata_bist.write.eq(self._write.r & self._write.re),
|
||||||
self.unit.read_only.eq(read_only),
|
sata_bist.read.eq(self._read.r & self._read.re),
|
||||||
self.unit.sector.eq(sector),
|
sata_bist.sector.eq(self._sector.storage),
|
||||||
self.unit.count.eq(count)
|
sata_bist.count.eq(self._count.storage),
|
||||||
]
|
sata_bist.loops.eq(self._loops.storage),
|
||||||
|
|
||||||
self.fsm = fsm = FSM(reset_state="IDLE")
|
self._done.status.eq(sata_bist.done),
|
||||||
|
self._errors.status.eq(sata_bist.errors)
|
||||||
# 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("COMPUTE")
|
|
||||||
).Elif(stop,
|
|
||||||
NextState("IDLE")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
fsm.act("COMPUTE",
|
|
||||||
compute.eq(1),
|
|
||||||
NextState("START")
|
|
||||||
)
|
|
||||||
|
|
||||||
self.sync += [
|
|
||||||
If(start,
|
|
||||||
errors.eq(0),
|
|
||||||
sector.eq(start_sector)
|
|
||||||
).Elif(compute,
|
|
||||||
errors.eq(errors + self.unit.data_errors),
|
|
||||||
sector.eq(sector + count)
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from lib.sata.common import *
|
from lib.sata.common import *
|
||||||
from lib.sata import SATACON
|
from lib.sata import SATACON
|
||||||
from lib.sata.bist import SATABISTUnit
|
from lib.sata.bist import SATABIST
|
||||||
|
|
||||||
from lib.sata.test.hdd import *
|
from lib.sata.test.hdd import *
|
||||||
from lib.sata.test.common import *
|
from lib.sata.test.common import *
|
||||||
|
@ -12,21 +12,28 @@ class TB(Module):
|
||||||
transport_debug=False, transport_loopback=False,
|
transport_debug=False, transport_loopback=False,
|
||||||
hdd_debug=True)
|
hdd_debug=True)
|
||||||
self.con = SATACON(self.hdd.phy)
|
self.con = SATACON(self.hdd.phy)
|
||||||
self.bist = SATABISTUnit(self.con)
|
self.bist = SATABIST(self.con)
|
||||||
|
|
||||||
def gen_simulation(self, selfp):
|
def gen_simulation(self, selfp):
|
||||||
hdd = self.hdd
|
hdd = self.hdd
|
||||||
hdd.malloc(0, 64)
|
hdd.malloc(0, 64)
|
||||||
selfp.bist.sector = 0
|
selfp.bist.sector = 0
|
||||||
selfp.bist.count = 17
|
selfp.bist.count = 17
|
||||||
|
selfp.bist.loops = 1
|
||||||
while True:
|
while True:
|
||||||
selfp.bist.start = 1
|
selfp.bist.write = 1
|
||||||
yield
|
yield
|
||||||
selfp.bist.start = 0
|
selfp.bist.write = 0
|
||||||
yield
|
yield
|
||||||
while selfp.bist.done == 0:
|
while selfp.bist.done == 0:
|
||||||
yield
|
yield
|
||||||
print("ctrl_errors: {} / data_errors {}".format(selfp.bist.ctrl_errors, selfp.bist.data_errors))
|
selfp.bist.read = 1
|
||||||
|
yield
|
||||||
|
selfp.bist.read = 0
|
||||||
|
yield
|
||||||
|
while selfp.bist.done == 0:
|
||||||
|
yield
|
||||||
|
print("errors {}".format(selfp.bist.errors))
|
||||||
selfp.bist.sector += 1
|
selfp.bist.sector += 1
|
||||||
selfp.bist.count = max((selfp.bist.count + 1)%8, 1)
|
selfp.bist.count = max((selfp.bist.count + 1)%8, 1)
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ from misoclib import identifier
|
||||||
from lib.sata.common import *
|
from lib.sata.common import *
|
||||||
from lib.sata.phy import SATAPHY
|
from lib.sata.phy import SATAPHY
|
||||||
from lib.sata import SATACON
|
from lib.sata import SATACON
|
||||||
from lib.sata.bist import SATABIST
|
from lib.sata.bist import SATABIST, SATABISTControl
|
||||||
|
|
||||||
from migen.genlib.cdc import *
|
from migen.genlib.cdc import *
|
||||||
|
|
||||||
|
@ -159,7 +159,7 @@ class DebugLeds(Module):
|
||||||
class TestDesign(UART2WB, AutoCSR):
|
class TestDesign(UART2WB, AutoCSR):
|
||||||
default_platform = "kc705"
|
default_platform = "kc705"
|
||||||
csr_map = {
|
csr_map = {
|
||||||
"sata_bist": 10,
|
"sata_bist_ctrl": 10,
|
||||||
"mila": 11
|
"mila": 11
|
||||||
}
|
}
|
||||||
csr_map.update(UART2WB.csr_map)
|
csr_map.update(UART2WB.csr_map)
|
||||||
|
@ -172,6 +172,8 @@ class TestDesign(UART2WB, AutoCSR):
|
||||||
self.sata_phy = SATAPHY(platform.request("sata_host"), clk_freq, speed="SATA2")
|
self.sata_phy = SATAPHY(platform.request("sata_host"), clk_freq, speed="SATA2")
|
||||||
self.sata_con = SATACON(self.sata_phy)
|
self.sata_con = SATACON(self.sata_phy)
|
||||||
self.sata_bist = SATABIST(self.sata_con)
|
self.sata_bist = SATABIST(self.sata_con)
|
||||||
|
self.sata_bist_ctrl = SATABISTControl(self.sata_bist)
|
||||||
|
|
||||||
|
|
||||||
self.leds = DebugLeds(platform, self.sata_phy)
|
self.leds = DebugLeds(platform, self.sata_phy)
|
||||||
|
|
||||||
|
|
84
test/bist.py
84
test/bist.py
|
@ -7,47 +7,24 @@ logical_sector_size = 512
|
||||||
class SATABISTDriver:
|
class SATABISTDriver:
|
||||||
def __init__(self, regs):
|
def __init__(self, regs):
|
||||||
self.regs = regs
|
self.regs = regs
|
||||||
self.last_sector = 0
|
|
||||||
self.last_time = time.time()
|
|
||||||
self.last_errors = 0
|
|
||||||
self.mode = "rw"
|
|
||||||
|
|
||||||
def set_mode(self, mode):
|
def run(self, sector, count, loops, mode):
|
||||||
self.mode = mode
|
self.regs.sata_bist_ctrl_sector.write(sector)
|
||||||
self.regs.sata_bist_write_only.write(0)
|
self.regs.sata_bist_ctrl_count.write(count)
|
||||||
self.regs.sata_bist_read_only.write(0)
|
self.regs.sata_bist_ctrl_loops.write(loops)
|
||||||
if mode == "wr":
|
if mode == "write":
|
||||||
self.regs.sata_bist_write_only.write(1)
|
self.regs.sata_bist_ctrl_write.write(1)
|
||||||
if mode == "rd":
|
elif mode == "read":
|
||||||
self.regs.sata_bist_read_only.write(1)
|
self.regs.sata_bist_ctrl_read.write(1)
|
||||||
|
while (self.regs.sata_bist_ctrl_done.read() == 0):
|
||||||
|
pass
|
||||||
|
return self.regs.sata_bist_ctrl_errors.read()
|
||||||
|
|
||||||
def start(self, sector, count, mode):
|
def write(self, sector, count, loops):
|
||||||
self.set_mode(mode)
|
self.run(sector, count, loops, "write")
|
||||||
self.regs.sata_bist_start_sector.write(sector)
|
|
||||||
self.regs.sata_bist_count.write(count)
|
|
||||||
self.regs.sata_bist_stop.write(0)
|
|
||||||
self.regs.sata_bist_start.write(1)
|
|
||||||
|
|
||||||
def stop(self):
|
|
||||||
self.regs.sata_bist_stop.write(1)
|
|
||||||
|
|
||||||
def show_status(self):
|
|
||||||
errors = self.regs.sata_bist_errors.read() - self.last_errors
|
|
||||||
self.last_errors += errors
|
|
||||||
|
|
||||||
sector = self.regs.sata_bist_sector.read()
|
|
||||||
n = sector - self.last_sector
|
|
||||||
self.last_sector = sector
|
|
||||||
|
|
||||||
t = self.last_time - time.time()
|
|
||||||
self.last_time = time.time()
|
|
||||||
|
|
||||||
if self.mode in ["wr", "rd"]:
|
|
||||||
speed_mult = 1
|
|
||||||
else:
|
|
||||||
speed_mult = 2
|
|
||||||
print("%4.2f MB/sec errors=%d sector=%d" %(n*logical_sector_size*speed_mult/(1024*1024), errors, sector))
|
|
||||||
|
|
||||||
|
def read(self, sector, count, loops):
|
||||||
|
return self.run(sector, count, loops, "read")
|
||||||
|
|
||||||
def _get_args():
|
def _get_args():
|
||||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
@ -55,8 +32,8 @@ def _get_args():
|
||||||
SATA BIST utility.
|
SATA BIST utility.
|
||||||
""")
|
""")
|
||||||
parser.add_argument("-s", "--sector", default=0, help="BIST start sector")
|
parser.add_argument("-s", "--sector", default=0, help="BIST start sector")
|
||||||
parser.add_argument("-c", "--count", default=4, help="BIST count (number of sectors per transaction)")
|
parser.add_argument("-c", "--count", default=16384, help="BIST count (number of sectors per transaction)")
|
||||||
parser.add_argument("-m", "--mode", default="rw", help="BIST mode (rw, wr, rd")
|
parser.add_argument("-l", "--loops", default=4, help="BIST loops (number of loop for each transaction")
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
@ -65,13 +42,32 @@ if __name__ == "__main__":
|
||||||
wb.open()
|
wb.open()
|
||||||
###
|
###
|
||||||
bist = SATABISTDriver(wb.regs)
|
bist = SATABISTDriver(wb.regs)
|
||||||
|
sector = int(args.sector)
|
||||||
|
count = int(args.count)
|
||||||
|
loops = int(args.loops)
|
||||||
try:
|
try:
|
||||||
bist.start(int(args.sector), int(args.count), args.mode)
|
write_time = 0
|
||||||
|
read_time = 0
|
||||||
while True:
|
while True:
|
||||||
bist.show_status()
|
# Write
|
||||||
time.sleep(1)
|
start = time.time()
|
||||||
|
bist.write(sector, count, loops)
|
||||||
|
end = time.time()
|
||||||
|
write_time = end-start
|
||||||
|
write_speed = loops*count*logical_sector_size/(1024*1024)/write_time
|
||||||
|
|
||||||
|
# Read
|
||||||
|
start = time.time()
|
||||||
|
read_errors = bist.read(sector, count, loops)
|
||||||
|
end = time.time()
|
||||||
|
read_time = end-start
|
||||||
|
read_speed = loops*count*logical_sector_size/(1024*1024)/read_time
|
||||||
|
|
||||||
|
sector += count
|
||||||
|
|
||||||
|
print("sector=%d write_speed=%4.2fMB/sec read_speed=%4.2fMB/sec errors=%d" %(sector, write_speed, read_speed, read_errors))
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
bist.stop()
|
|
||||||
###
|
###
|
||||||
wb.close()
|
wb.close()
|
||||||
|
|
|
@ -27,9 +27,9 @@ mila.prog_sum("term")
|
||||||
# Trigger / wait / receive
|
# Trigger / wait / receive
|
||||||
mila.trigger(offset=32, length=1024)
|
mila.trigger(offset=32, length=1024)
|
||||||
|
|
||||||
bist.start(0, 4, "rw")
|
bist.write(0, 16, 1)
|
||||||
|
bist.read(0, 16, 1)
|
||||||
mila.wait_done()
|
mila.wait_done()
|
||||||
bist.stop()
|
|
||||||
|
|
||||||
mila.read()
|
mila.read()
|
||||||
mila.export("dump.vcd")
|
mila.export("dump.vcd")
|
||||||
|
|
Loading…
Reference in a new issue