mirror of
https://github.com/enjoy-digital/litex.git
synced 2025-01-04 09:52:26 -05:00
add frontend and improve BIST
This commit is contained in:
parent
62f55e32cf
commit
788546c6ae
11 changed files with 311 additions and 136 deletions
|
@ -3,11 +3,19 @@ from lib.sata.link import SATALink
|
||||||
from lib.sata.transport import SATATransport
|
from lib.sata.transport import SATATransport
|
||||||
from lib.sata.command import SATACommand
|
from lib.sata.command import SATACommand
|
||||||
|
|
||||||
|
from lib.sata.frontend.crossbar import SATACrossbar
|
||||||
|
|
||||||
class SATACON(Module):
|
class SATACON(Module):
|
||||||
def __init__(self, phy):
|
def __init__(self, phy):
|
||||||
###
|
###
|
||||||
|
# core
|
||||||
self.link = SATALink(phy)
|
self.link = SATALink(phy)
|
||||||
self.transport = SATATransport(self.link)
|
self.transport = SATATransport(self.link)
|
||||||
self.command = SATACommand(self.transport)
|
self.command = SATACommand(self.transport)
|
||||||
self.sink, self.source = self.command.sink, self.command.source
|
|
||||||
|
|
||||||
|
# frontend
|
||||||
|
self.crossbar = SATACrossbar(32)
|
||||||
|
self.comb += [
|
||||||
|
Record.connect(self.crossbar.master.source, self.command.sink),
|
||||||
|
Record.connect(self.command.source, self.crossbar.master.sink)
|
||||||
|
]
|
||||||
|
|
175
lib/sata/bist.py
175
lib/sata/bist.py
|
@ -1,22 +1,90 @@
|
||||||
from lib.sata.common import *
|
from lib.sata.common import *
|
||||||
from lib.sata.link.scrambler import Scrambler
|
from lib.sata.link.scrambler import Scrambler
|
||||||
|
|
||||||
|
from migen.fhdl.decorators import ModuleDecorator
|
||||||
from migen.bank.description import *
|
from migen.bank.description import *
|
||||||
|
|
||||||
class SATABIST(Module):
|
class SATABISTGenerator(Module):
|
||||||
def __init__(self, sata_con):
|
def __init__(self, sata_master_port):
|
||||||
self.write = Signal()
|
self.start = Signal()
|
||||||
self.read = Signal()
|
|
||||||
self.sector = Signal(48)
|
self.sector = Signal(48)
|
||||||
self.count = Signal(16)
|
self.count = Signal(16)
|
||||||
self.loops = Signal(8)
|
self.loops = Signal(8)
|
||||||
|
self.random = Signal()
|
||||||
|
|
||||||
|
self.done = Signal()
|
||||||
|
self.errors = Signal(32) # Note: Not used for writes
|
||||||
|
|
||||||
|
###
|
||||||
|
|
||||||
|
source, sink = sata_master_port.source, sata_master_port.sink
|
||||||
|
|
||||||
|
self.counter = counter = Counter(bits_sign=32)
|
||||||
|
self.loops_counter = loops_counter = Counter(bits_sign=8)
|
||||||
|
|
||||||
|
self.scrambler = scrambler = InsertReset(Scrambler())
|
||||||
|
self.comb += [
|
||||||
|
scrambler.reset.eq(counter.reset),
|
||||||
|
scrambler.ce.eq(counter.ce)
|
||||||
|
]
|
||||||
|
|
||||||
|
self.fsm = fsm = FSM(reset_state="IDLE")
|
||||||
|
fsm.act("IDLE",
|
||||||
|
self.done.eq(1),
|
||||||
|
counter.reset.eq(1),
|
||||||
|
loops_counter.reset.eq(1),
|
||||||
|
If(self.start,
|
||||||
|
NextState("SEND_CMD_AND_DATA")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
self.comb += [
|
||||||
|
source.sop.eq(counter.value == 0),
|
||||||
|
source.eop.eq(counter.value == (logical_sector_size//4*self.count)-1),
|
||||||
|
source.write.eq(1),
|
||||||
|
source.sector.eq(self.sector),
|
||||||
|
source.count.eq(self.count),
|
||||||
|
If(self.random,
|
||||||
|
source.data.eq(scrambler.value)
|
||||||
|
).Else(
|
||||||
|
source.data.eq(counter.value)
|
||||||
|
)
|
||||||
|
]
|
||||||
|
fsm.act("SEND_CMD_AND_DATA",
|
||||||
|
source.stb.eq(1),
|
||||||
|
If(source.stb & source.ack,
|
||||||
|
counter.ce.eq(1),
|
||||||
|
If(source.eop,
|
||||||
|
NextState("WAIT_ACK")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fsm.act("WAIT_ACK",
|
||||||
|
sink.ack.eq(1),
|
||||||
|
If(sink.stb,
|
||||||
|
loops_counter.ce.eq(1),
|
||||||
|
If(loops_counter.value == (self.loops-1),
|
||||||
|
NextState("IDLE")
|
||||||
|
).Else(
|
||||||
|
counter.reset.eq(1),
|
||||||
|
NextState("SEND_CMD_AND_DATA")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
class SATABISTChecker(Module):
|
||||||
|
def __init__(self, sata_master_port):
|
||||||
|
self.start = Signal()
|
||||||
|
self.sector = Signal(48)
|
||||||
|
self.count = Signal(16)
|
||||||
|
self.loops = Signal(8)
|
||||||
|
self.random = Signal()
|
||||||
|
|
||||||
self.done = Signal()
|
self.done = Signal()
|
||||||
self.errors = Signal(32)
|
self.errors = Signal(32)
|
||||||
|
|
||||||
###
|
###
|
||||||
|
|
||||||
sink = sata_con.source
|
source, sink = sata_master_port.source, sata_master_port.sink
|
||||||
source = sata_con.sink
|
|
||||||
|
|
||||||
self.counter = counter = Counter(bits_sign=32)
|
self.counter = counter = Counter(bits_sign=32)
|
||||||
self.loops_counter = loops_counter = Counter(bits_sign=8)
|
self.loops_counter = loops_counter = Counter(bits_sign=8)
|
||||||
|
@ -33,63 +101,42 @@ class SATABIST(Module):
|
||||||
self.done.eq(1),
|
self.done.eq(1),
|
||||||
counter.reset.eq(1),
|
counter.reset.eq(1),
|
||||||
loops_counter.reset.eq(1),
|
loops_counter.reset.eq(1),
|
||||||
If(self.write,
|
If(self.start,
|
||||||
self.error_counter.reset.eq(1),
|
self.error_counter.reset.eq(1),
|
||||||
NextState("SEND_WRITE_CMD_AND_DATA")
|
NextState("SEND_CMD")
|
||||||
).Elif(self.read,
|
|
||||||
self.error_counter.reset.eq(1),
|
|
||||||
NextState("SEND_READ_CMD")
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("SEND_WRITE_CMD_AND_DATA",
|
self.comb += [
|
||||||
source.stb.eq(1),
|
|
||||||
source.sop.eq(counter.value == 0),
|
|
||||||
source.eop.eq(counter.value == (logical_sector_size//4*self.count)-1),
|
|
||||||
source.write.eq(1),
|
|
||||||
source.sector.eq(self.sector),
|
|
||||||
source.count.eq(self.count),
|
|
||||||
source.data.eq(scrambler.value),
|
|
||||||
If(source.stb & source.ack,
|
|
||||||
counter.ce.eq(1),
|
|
||||||
If(source.eop,
|
|
||||||
NextState("WAIT_WRITE_ACK")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
fsm.act("WAIT_WRITE_ACK",
|
|
||||||
sink.ack.eq(1),
|
|
||||||
If(sink.stb,
|
|
||||||
loops_counter.ce.eq(1),
|
|
||||||
If(loops_counter.value == (self.loops-1),
|
|
||||||
NextState("IDLE")
|
|
||||||
).Else(
|
|
||||||
counter.reset.eq(1),
|
|
||||||
NextState("SEND_WRITE_CMD_AND_DATA")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
fsm.act("SEND_READ_CMD",
|
|
||||||
source.stb.eq(1),
|
|
||||||
source.sop.eq(1),
|
source.sop.eq(1),
|
||||||
source.eop.eq(1),
|
source.eop.eq(1),
|
||||||
source.read.eq(1),
|
source.read.eq(1),
|
||||||
source.sector.eq(self.sector),
|
source.sector.eq(self.sector),
|
||||||
source.count.eq(self.count),
|
source.count.eq(self.count),
|
||||||
|
]
|
||||||
|
fsm.act("SEND_CMD",
|
||||||
|
source.stb.eq(1),
|
||||||
If(source.ack,
|
If(source.ack,
|
||||||
counter.reset.eq(1),
|
counter.reset.eq(1),
|
||||||
NextState("WAIT_READ_ACK")
|
NextState("WAIT_ACK")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("WAIT_READ_ACK",
|
fsm.act("WAIT_ACK",
|
||||||
If(sink.stb & sink.read,
|
If(sink.stb & sink.read,
|
||||||
NextState("RECEIVE_READ_DATA")
|
NextState("RECEIVE_DATA")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("RECEIVE_READ_DATA",
|
expected_data = Signal(32)
|
||||||
|
self.comb += \
|
||||||
|
If(self.random,
|
||||||
|
expected_data.eq(scrambler.value)
|
||||||
|
).Else(
|
||||||
|
expected_data.eq(counter.value)
|
||||||
|
)
|
||||||
|
fsm.act("RECEIVE_DATA",
|
||||||
sink.ack.eq(1),
|
sink.ack.eq(1),
|
||||||
If(sink.stb,
|
If(sink.stb,
|
||||||
counter.ce.eq(1),
|
counter.ce.eq(1),
|
||||||
If(sink.data != scrambler.value,
|
If(sink.data != expected_data,
|
||||||
self.error_counter.ce.eq(1)
|
self.error_counter.ce.eq(1)
|
||||||
),
|
),
|
||||||
If(sink.eop,
|
If(sink.eop,
|
||||||
|
@ -98,33 +145,45 @@ class SATABIST(Module):
|
||||||
If(loops_counter.value == (self.loops-1),
|
If(loops_counter.value == (self.loops-1),
|
||||||
NextState("IDLE")
|
NextState("IDLE")
|
||||||
).Else(
|
).Else(
|
||||||
NextState("SEND_READ_CMD")
|
NextState("SEND_CMD")
|
||||||
)
|
)
|
||||||
).Else(
|
).Else(
|
||||||
NextState("WAIT_READ_ACK")
|
NextState("WAIT_ACK")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
class SATABISTControl(Module, AutoCSR):
|
class SATABISTControl(Module, AutoCSR):
|
||||||
def __init__(self, sata_bist):
|
def __init__(self, bist_unit):
|
||||||
self._write = CSR()
|
self._start = CSR()
|
||||||
self._read = CSR()
|
|
||||||
self._sector = CSRStorage(48)
|
self._sector = CSRStorage(48)
|
||||||
self._count = CSRStorage(16)
|
self._count = CSRStorage(16)
|
||||||
|
self._random = CSRStorage()
|
||||||
self._loops = CSRStorage(8)
|
self._loops = CSRStorage(8)
|
||||||
|
|
||||||
self._done = CSRStatus()
|
self._done = CSRStatus()
|
||||||
self._errors = CSRStatus(32)
|
self._errors = CSRStatus(32)
|
||||||
|
|
||||||
|
###
|
||||||
|
self.bist_unit = bist_unit
|
||||||
self.comb += [
|
self.comb += [
|
||||||
sata_bist.write.eq(self._write.r & self._write.re),
|
bist_unit.start.eq(self._start.r & self._start.re),
|
||||||
sata_bist.read.eq(self._read.r & self._read.re),
|
bist_unit.sector.eq(self._sector.storage),
|
||||||
sata_bist.sector.eq(self._sector.storage),
|
bist_unit.count.eq(self._count.storage),
|
||||||
sata_bist.count.eq(self._count.storage),
|
bist_unit.loops.eq(self._loops.storage),
|
||||||
sata_bist.loops.eq(self._loops.storage),
|
bist_unit.random.eq(self._random.storage),
|
||||||
|
|
||||||
self._done.status.eq(sata_bist.done),
|
self._done.status.eq(bist_unit.done),
|
||||||
self._errors.status.eq(sata_bist.errors)
|
self._errors.status.eq(bist_unit.errors)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class SATABIST(Module, AutoCSR):
|
||||||
|
def __init__(self, sata_master_ports, with_control=False):
|
||||||
|
generator = SATABISTGenerator(sata_master_ports[0])
|
||||||
|
checker = SATABISTChecker(sata_master_ports[1])
|
||||||
|
if with_control:
|
||||||
|
self.generator = SATABISTControl(generator)
|
||||||
|
self.checker = SATABISTControl(checker)
|
||||||
|
else:
|
||||||
|
self.generator = generator
|
||||||
|
self.checker = checker
|
||||||
|
|
|
@ -26,6 +26,7 @@ class SATACommandTX(Module):
|
||||||
transport.sink.count.eq(sink.count),
|
transport.sink.count.eq(sink.count),
|
||||||
transport.sink.icc.eq(0),
|
transport.sink.icc.eq(0),
|
||||||
transport.sink.control.eq(0),
|
transport.sink.control.eq(0),
|
||||||
|
transport.sink.data.eq(sink.data)
|
||||||
]
|
]
|
||||||
|
|
||||||
self.dwords_counter = dwords_counter = Counter(max=fis_max_dwords)
|
self.dwords_counter = dwords_counter = Counter(max=fis_max_dwords)
|
||||||
|
@ -70,7 +71,6 @@ class SATACommandTX(Module):
|
||||||
transport.sink.eop.eq((dwords_counter.value == (fis_max_dwords-1)) | sink.eop),
|
transport.sink.eop.eq((dwords_counter.value == (fis_max_dwords-1)) | sink.eop),
|
||||||
|
|
||||||
transport.sink.type.eq(fis_types["DATA"]),
|
transport.sink.type.eq(fis_types["DATA"]),
|
||||||
transport.sink.data.eq(sink.data),
|
|
||||||
sink.ack.eq(transport.sink.ack),
|
sink.ack.eq(transport.sink.ack),
|
||||||
If(sink.stb & sink.ack,
|
If(sink.stb & sink.ack,
|
||||||
If(sink.eop,
|
If(sink.eop,
|
||||||
|
@ -171,11 +171,13 @@ class SATACommandRX(Module):
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
fsm.act("PRESENT_READ_DATA",
|
self.comb += [
|
||||||
data_buffer.sink.stb.eq(transport.source.stb),
|
|
||||||
data_buffer.sink.sop.eq(transport.source.sop),
|
data_buffer.sink.sop.eq(transport.source.sop),
|
||||||
data_buffer.sink.eop.eq(transport.source.eop),
|
data_buffer.sink.eop.eq(transport.source.eop),
|
||||||
data_buffer.sink.data.eq(transport.source.data),
|
data_buffer.sink.data.eq(transport.source.data)
|
||||||
|
]
|
||||||
|
fsm.act("PRESENT_READ_DATA",
|
||||||
|
data_buffer.sink.stb.eq(transport.source.stb),
|
||||||
transport.source.ack.eq(data_buffer.sink.ack),
|
transport.source.ack.eq(data_buffer.sink.ack),
|
||||||
If(data_buffer.sink.stb & data_buffer.sink.ack,
|
If(data_buffer.sink.stb & data_buffer.sink.ack,
|
||||||
self.dwords_counter.ce.eq(~read_done),
|
self.dwords_counter.ce.eq(~read_done),
|
||||||
|
@ -230,6 +232,7 @@ class SATACommandRX(Module):
|
||||||
source.last.eq(cmd_buffer.source.last),
|
source.last.eq(cmd_buffer.source.last),
|
||||||
source.success.eq(cmd_buffer.source.success),
|
source.success.eq(cmd_buffer.source.success),
|
||||||
source.failed.eq(cmd_buffer.source.success),
|
source.failed.eq(cmd_buffer.source.success),
|
||||||
|
source.data.eq(data_buffer.source.data)
|
||||||
]
|
]
|
||||||
|
|
||||||
out_fsm.act("PRESENT_RESPONSE_WITH_DATA",
|
out_fsm.act("PRESENT_RESPONSE_WITH_DATA",
|
||||||
|
@ -237,7 +240,6 @@ class SATACommandRX(Module):
|
||||||
source.sop.eq(data_buffer.source.sop),
|
source.sop.eq(data_buffer.source.sop),
|
||||||
source.eop.eq(data_buffer.source.eop),
|
source.eop.eq(data_buffer.source.eop),
|
||||||
|
|
||||||
source.data.eq(data_buffer.source.data),
|
|
||||||
data_buffer.source.ack.eq(source.ack),
|
data_buffer.source.ack.eq(source.ack),
|
||||||
|
|
||||||
If(source.stb & source.eop & source.ack,
|
If(source.stb & source.eop & source.ack,
|
||||||
|
|
|
@ -210,6 +210,7 @@ class Counter(Module):
|
||||||
self.width = flen(self.value)
|
self.width = flen(self.value)
|
||||||
self.sync += self.value.eq(self.value+1)
|
self.sync += self.value.eq(self.value+1)
|
||||||
|
|
||||||
|
# XXX use ModuleDecorator
|
||||||
class BufferizeEndpoints(Module):
|
class BufferizeEndpoints(Module):
|
||||||
def __init__(self, decorated, *args):
|
def __init__(self, decorated, *args):
|
||||||
self.decorated = decorated
|
self.decorated = decorated
|
||||||
|
|
31
lib/sata/frontend/arbiter.py
Normal file
31
lib/sata/frontend/arbiter.py
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
from lib.sata.common import *
|
||||||
|
from lib.sata.frontend.common import *
|
||||||
|
|
||||||
|
from migen.genlib.roundrobin import *
|
||||||
|
|
||||||
|
class SATAArbiter(Module):
|
||||||
|
def __init__(self, slaves, master):
|
||||||
|
if len(slaves) == 1:
|
||||||
|
self.comb += slaves[0].connect(master)
|
||||||
|
else:
|
||||||
|
self.rr = RoundRobin(len(slaves))
|
||||||
|
self.grant = self.rr.grant
|
||||||
|
cases = {}
|
||||||
|
for i, slave in enumerate(slaves):
|
||||||
|
sink, source = slave.sink, slave.source
|
||||||
|
start = Signal()
|
||||||
|
done = Signal()
|
||||||
|
ongoing = Signal()
|
||||||
|
self.comb += [
|
||||||
|
start.eq(sink.stb & sink.sop),
|
||||||
|
done.eq(source.stb & source.last & source.eop & source.ack)
|
||||||
|
]
|
||||||
|
self.sync += \
|
||||||
|
If(start,
|
||||||
|
ongoing.eq(1)
|
||||||
|
).Elif(done,
|
||||||
|
ongoing.eq(0)
|
||||||
|
)
|
||||||
|
self.comb += self.rr.request[i].eq((start | ongoing) & ~done)
|
||||||
|
cases[i] = [slaves[i].connect(master)]
|
||||||
|
self.comb += Case(self.grant, cases)
|
23
lib/sata/frontend/common.py
Normal file
23
lib/sata/frontend/common.py
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
from lib.sata.common import *
|
||||||
|
|
||||||
|
class SATAMasterPort:
|
||||||
|
def __init__(self, dw):
|
||||||
|
self.source = Source(command_tx_description(dw))
|
||||||
|
self.sink = Sink(command_rx_description(dw))
|
||||||
|
|
||||||
|
def connect(self, slave):
|
||||||
|
return [
|
||||||
|
Record.connect(self.source, slave.sink),
|
||||||
|
Record.connect(slave.source, self.sink)
|
||||||
|
]
|
||||||
|
|
||||||
|
class SATASlavePort:
|
||||||
|
def __init__(self, dw):
|
||||||
|
self.sink = Sink(command_tx_description(dw))
|
||||||
|
self.source = Source(command_rx_description(dw))
|
||||||
|
|
||||||
|
def connect(self, master):
|
||||||
|
return [
|
||||||
|
Record.connect(self.sink, master.source),
|
||||||
|
Record.connect(master.sink, self.source)
|
||||||
|
]
|
25
lib/sata/frontend/crossbar.py
Normal file
25
lib/sata/frontend/crossbar.py
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
from lib.sata.common import *
|
||||||
|
from lib.sata.frontend.common import *
|
||||||
|
from lib.sata.frontend.arbiter import SATAArbiter
|
||||||
|
|
||||||
|
class SATACrossbar(Module):
|
||||||
|
def __init__(self, dw):
|
||||||
|
self.dw = dw
|
||||||
|
self.slaves = []
|
||||||
|
self.master = SATAMasterPort(dw)
|
||||||
|
|
||||||
|
def get_port(self):
|
||||||
|
master = SATAMasterPort(self.dw)
|
||||||
|
slave = SATASlavePort(self.dw)
|
||||||
|
self.comb += master.connect(slave)
|
||||||
|
self.slaves.append(slave)
|
||||||
|
return master
|
||||||
|
|
||||||
|
def get_ports(self, n):
|
||||||
|
masters = []
|
||||||
|
for i in range(n):
|
||||||
|
masters.append(self.get_port())
|
||||||
|
return masters
|
||||||
|
|
||||||
|
def do_finalize(self):
|
||||||
|
self.arbiter = SATAArbiter(self.slaves, self.master)
|
|
@ -187,10 +187,12 @@ class SATALinkRX(Module):
|
||||||
NextState("COPY")
|
NextState("COPY")
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
self.comb += [
|
||||||
|
scrambler.sink.sop.eq(sop),
|
||||||
|
scrambler.sink.eop.eq(eop)
|
||||||
|
]
|
||||||
fsm.act("COPY",
|
fsm.act("COPY",
|
||||||
scrambler.sink.stb.eq(cont.source.stb & ((det == 0) | eop)),
|
scrambler.sink.stb.eq(cont.source.stb & ((det == 0) | eop)),
|
||||||
scrambler.sink.sop.eq(sop),
|
|
||||||
scrambler.sink.eop.eq(eop),
|
|
||||||
insert.eq(primitives["R_IP"]),
|
insert.eq(primitives["R_IP"]),
|
||||||
If(det == primitives["HOLD"],
|
If(det == primitives["HOLD"],
|
||||||
insert.eq(primitives["HOLDA"])
|
insert.eq(primitives["HOLDA"])
|
||||||
|
|
|
@ -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 SATABIST
|
from lib.sata.bist import SATABISTGenerator, SATABISTChecker
|
||||||
|
|
||||||
from lib.sata.test.hdd import *
|
from lib.sata.test.hdd import *
|
||||||
from lib.sata.test.common import *
|
from lib.sata.test.common import *
|
||||||
|
@ -11,31 +11,35 @@ class TB(Module):
|
||||||
link_debug=False, link_random_level=0,
|
link_debug=False, link_random_level=0,
|
||||||
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.controller = SATACON(self.hdd.phy)
|
||||||
self.bist = SATABIST(self.con)
|
self.generator = SATABISTGenerator(self.controller.crossbar.get_port())
|
||||||
|
self.checker = SATABISTChecker(self.controller.crossbar.get_port())
|
||||||
|
|
||||||
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.generator.sector = 0
|
||||||
selfp.bist.count = 17
|
selfp.generator.count = 17
|
||||||
selfp.bist.loops = 1
|
selfp.checker.sector = 0
|
||||||
|
selfp.checker.count = 17
|
||||||
while True:
|
while True:
|
||||||
selfp.bist.write = 1
|
selfp.generator.start = 1
|
||||||
yield
|
yield
|
||||||
selfp.bist.write = 0
|
selfp.generator.start = 0
|
||||||
yield
|
yield
|
||||||
while selfp.bist.done == 0:
|
while selfp.generator.done == 0:
|
||||||
yield
|
yield
|
||||||
selfp.bist.read = 1
|
selfp.checker.start = 1
|
||||||
yield
|
yield
|
||||||
selfp.bist.read = 0
|
selfp.checker.start = 0
|
||||||
yield
|
yield
|
||||||
while selfp.bist.done == 0:
|
while selfp.checker.done == 0:
|
||||||
yield
|
yield
|
||||||
print("errors {}".format(selfp.bist.errors))
|
print("errors {}".format(selfp.checker.errors))
|
||||||
selfp.bist.sector += 1
|
selfp.generator.sector += 1
|
||||||
selfp.bist.count = max((selfp.bist.count + 1)%8, 1)
|
selfp.generator.count = max((selfp.generator.count + 1)%8, 1)
|
||||||
|
selfp.checker.sector += 1
|
||||||
|
selfp.checker.count = max((selfp.checker.count + 1)%8, 1)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
run_simulation(TB(), ncycles=8192*2, vcd_name="my.vcd", keep_files=True)
|
run_simulation(TB(), ncycles=8192*2, vcd_name="my.vcd", keep_files=True)
|
||||||
|
|
|
@ -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_ctrl": 10,
|
"sata_bist": 10,
|
||||||
"mila": 11
|
"mila": 11
|
||||||
}
|
}
|
||||||
csr_map.update(UART2WB.csr_map)
|
csr_map.update(UART2WB.csr_map)
|
||||||
|
@ -171,9 +171,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_ctrl = SATABISTControl(self.sata_bist)
|
|
||||||
|
|
||||||
|
self.sata_bist = SATABIST(self.sata_con.crossbar.get_ports(2), with_control=True)
|
||||||
|
|
||||||
self.leds = DebugLeds(platform, self.sata_phy)
|
self.leds = DebugLeds(platform, self.sata_phy)
|
||||||
|
|
||||||
|
@ -189,22 +188,22 @@ class TestDesign(UART2WB, AutoCSR):
|
||||||
self.sata_phy.sink.data,
|
self.sata_phy.sink.data,
|
||||||
self.sata_phy.sink.charisk,
|
self.sata_phy.sink.charisk,
|
||||||
|
|
||||||
self.sata_con.sink.stb,
|
self.sata_con.command.sink.stb,
|
||||||
self.sata_con.sink.sop,
|
self.sata_con.command.sink.sop,
|
||||||
self.sata_con.sink.eop,
|
self.sata_con.command.sink.eop,
|
||||||
self.sata_con.sink.ack,
|
self.sata_con.command.sink.ack,
|
||||||
self.sata_con.sink.write,
|
self.sata_con.command.sink.write,
|
||||||
self.sata_con.sink.read,
|
self.sata_con.command.sink.read,
|
||||||
|
|
||||||
self.sata_con.source.stb,
|
self.sata_con.command.source.stb,
|
||||||
self.sata_con.source.sop,
|
self.sata_con.command.source.sop,
|
||||||
self.sata_con.source.eop,
|
self.sata_con.command.source.eop,
|
||||||
self.sata_con.source.ack,
|
self.sata_con.command.source.ack,
|
||||||
self.sata_con.source.write,
|
self.sata_con.command.source.write,
|
||||||
self.sata_con.source.read,
|
self.sata_con.command.source.read,
|
||||||
self.sata_con.source.success,
|
self.sata_con.command.source.success,
|
||||||
self.sata_con.source.failed,
|
self.sata_con.command.source.failed,
|
||||||
self.sata_con.source.data
|
self.sata_con.command.source.data
|
||||||
)
|
)
|
||||||
|
|
||||||
self.mila = MiLa(depth=2048, dat=Cat(*debug))
|
self.mila = MiLa(depth=2048, dat=Cat(*debug))
|
||||||
|
|
91
test/bist.py
91
test/bist.py
|
@ -5,35 +5,57 @@ from config import *
|
||||||
logical_sector_size = 512
|
logical_sector_size = 512
|
||||||
|
|
||||||
class SATABISTDriver:
|
class SATABISTDriver:
|
||||||
def __init__(self, regs):
|
def __init__(self, regs, name):
|
||||||
self.regs = regs
|
self.regs = regs
|
||||||
|
self.name = name
|
||||||
|
for s in ["start", "sector", "count", "loops", "random", "done", "errors"]:
|
||||||
|
setattr(self, s, getattr(regs, name + "_"+ s))
|
||||||
|
|
||||||
def run(self, sector, count, loops, mode):
|
def run(self, sector, count, loops, random):
|
||||||
self.regs.sata_bist_ctrl_sector.write(sector)
|
self.sector.write(sector)
|
||||||
self.regs.sata_bist_ctrl_count.write(count)
|
self.count.write(count)
|
||||||
self.regs.sata_bist_ctrl_loops.write(loops)
|
self.loops.write(loops)
|
||||||
if mode == "write":
|
self.random.write(random)
|
||||||
self.regs.sata_bist_ctrl_write.write(1)
|
self.start.write(1)
|
||||||
elif mode == "read":
|
while (self.done.read() == 0):
|
||||||
self.regs.sata_bist_ctrl_read.write(1)
|
|
||||||
while (self.regs.sata_bist_ctrl_done.read() == 0):
|
|
||||||
pass
|
pass
|
||||||
return self.regs.sata_bist_ctrl_errors.read()
|
return self.errors.read()
|
||||||
|
|
||||||
def write(self, sector, count, loops):
|
class SATABISTGeneratorDriver(SATABISTDriver):
|
||||||
self.run(sector, count, loops, "write")
|
def __init__(self, regs, name):
|
||||||
|
SATABISTDriver.__init__(self, regs, name + "_generator")
|
||||||
|
|
||||||
def read(self, sector, count, loops):
|
class SATABISTCheckerDriver(SATABISTDriver):
|
||||||
return self.run(sector, count, loops, "read")
|
def __init__(self, regs, name):
|
||||||
|
SATABISTDriver.__init__(self, regs, name + "_checker")
|
||||||
|
|
||||||
|
class Timer:
|
||||||
|
def __init__(self):
|
||||||
|
self.value = None
|
||||||
|
|
||||||
|
def start(self):
|
||||||
|
self._start = time.time()
|
||||||
|
|
||||||
|
def stop(self):
|
||||||
|
self._stop = time.time()
|
||||||
|
self.value = self._stop - self._start
|
||||||
|
|
||||||
|
KB = 1024
|
||||||
|
MB = 1024*KB
|
||||||
|
GB = 1024*MB
|
||||||
|
|
||||||
|
def compute_speed(loops, count, elapsed_time, unit):
|
||||||
|
return loops*count*logical_sector_size/unit/elapsed_time
|
||||||
|
|
||||||
def _get_args():
|
def _get_args():
|
||||||
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description="""\
|
description="""\
|
||||||
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="start sector")
|
||||||
parser.add_argument("-c", "--count", default=16384, help="BIST count (number of sectors per transaction)")
|
parser.add_argument("-c", "--count", default=16384, help="number of sectors per transaction")
|
||||||
parser.add_argument("-l", "--loops", default=4, help="BIST loops (number of loop for each transaction")
|
parser.add_argument("-l", "--loops", default=4, help="number of loop for each transaction")
|
||||||
|
parser.add_argument("-r", "--random", default=True, help="use random data")
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
|
@ -41,31 +63,30 @@ if __name__ == "__main__":
|
||||||
args = _get_args()
|
args = _get_args()
|
||||||
wb.open()
|
wb.open()
|
||||||
###
|
###
|
||||||
bist = SATABISTDriver(wb.regs)
|
generator = SATABISTGeneratorDriver(wb.regs, "sata_bist")
|
||||||
|
checker = SATABISTCheckerDriver(wb.regs, "sata_bist")
|
||||||
|
timer = Timer()
|
||||||
|
|
||||||
sector = int(args.sector)
|
sector = int(args.sector)
|
||||||
count = int(args.count)
|
count = int(args.count)
|
||||||
loops = int(args.loops)
|
loops = int(args.loops)
|
||||||
|
random = int(args.random)
|
||||||
try:
|
try:
|
||||||
write_time = 0
|
|
||||||
read_time = 0
|
|
||||||
while True:
|
while True:
|
||||||
# Write
|
# generator (write data to HDD)
|
||||||
start = time.time()
|
timer.start()
|
||||||
bist.write(sector, count, loops)
|
generator.run(sector, count, loops, random)
|
||||||
end = time.time()
|
timer.stop()
|
||||||
write_time = end-start
|
write_speed = compute_speed(loops, count, timer.value, MB)
|
||||||
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
|
|
||||||
|
|
||||||
|
# checker (read and check data from HDD)
|
||||||
|
timer.start()
|
||||||
|
errors = checker.run(sector, count, loops, random)
|
||||||
|
timer.stop()
|
||||||
|
read_speed = compute_speed(loops, count, timer.value, MB)
|
||||||
sector += count
|
sector += count
|
||||||
|
|
||||||
print("sector=%d write_speed=%4.2fMB/sec read_speed=%4.2fMB/sec errors=%d" %(sector, write_speed, read_speed, read_errors))
|
print("sector=%d write_speed=%4.2fMB/sec read_speed=%4.2fMB/sec errors=%d" %(sector, write_speed, read_speed, errors))
|
||||||
|
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
pass
|
pass
|
||||||
|
|
Loading…
Reference in a new issue