add frontend and improve BIST
authorFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 14 Jan 2015 08:19:41 +0000 (09:19 +0100)
committerFlorent Kermarrec <florent@enjoy-digital.fr>
Wed, 14 Jan 2015 14:47:13 +0000 (15:47 +0100)
lib/sata/__init__.py
lib/sata/bist.py
lib/sata/command/__init__.py
lib/sata/common.py
lib/sata/frontend/arbiter.py [new file with mode: 0644]
lib/sata/frontend/common.py [new file with mode: 0644]
lib/sata/frontend/crossbar.py [new file with mode: 0644]
lib/sata/link/__init__.py
lib/sata/test/bist_tb.py
targets/test.py
test/bist.py

index 34c7a3534b7c3f237402decc96444b4836cba949..0a167bdc7bc2e2d464440df621505882ae464d2b 100644 (file)
@@ -3,11 +3,19 @@ from lib.sata.link import SATALink
 from lib.sata.transport import SATATransport
 from lib.sata.command import SATACommand
 
+from lib.sata.frontend.crossbar import SATACrossbar
+
 class SATACON(Module):
        def __init__(self, phy):
                ###
+               # core
                self.link = SATALink(phy)
                self.transport = SATATransport(self.link)
                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)
+               ]
index 4948022fd8f41a46075c38511f98b5b875430b78..5de8e7c1ac67dfa286bd940e21923e95fba6b465 100644 (file)
@@ -1,26 +1,26 @@
 from lib.sata.common import *
 from lib.sata.link.scrambler import Scrambler
+
+from migen.fhdl.decorators import ModuleDecorator
 from migen.bank.description import *
 
-class SATABIST(Module):
-       def __init__(self, sata_con):
-               self.write = Signal()
-               self.read = Signal()
+class SATABISTGenerator(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.errors = Signal(32)
+               self.errors = Signal(32) # Note: Not used for writes
 
-       ###
+               ###
 
-               sink = sata_con.source
-               source = sata_con.sink
+               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.error_counter = Counter(self.errors, bits_sign=32)
 
                self.scrambler = scrambler = InsertReset(Scrambler())
                self.comb += [
@@ -33,30 +33,32 @@ class SATABIST(Module):
                        self.done.eq(1),
                        counter.reset.eq(1),
                        loops_counter.reset.eq(1),
-                       If(self.write,
-                               self.error_counter.reset.eq(1),
-                               NextState("SEND_WRITE_CMD_AND_DATA")
-                       ).Elif(self.read,
-                               self.error_counter.reset.eq(1),
-                               NextState("SEND_READ_CMD")
+                       If(self.start,
+                               NextState("SEND_CMD_AND_DATA")
                        )
                )
-               fsm.act("SEND_WRITE_CMD_AND_DATA",
-                       source.stb.eq(1),
+               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),
-                       source.data.eq(scrambler.value),
+                       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_WRITE_ACK")
+                                       NextState("WAIT_ACK")
                                )
                        )
                )
-               fsm.act("WAIT_WRITE_ACK",
+               fsm.act("WAIT_ACK",
                        sink.ack.eq(1),
                        If(sink.stb,
                                loops_counter.ce.eq(1),
@@ -64,32 +66,77 @@ class SATABIST(Module):
                                        NextState("IDLE")
                                ).Else(
                                        counter.reset.eq(1),
-                                       NextState("SEND_WRITE_CMD_AND_DATA")
+                                       NextState("SEND_CMD_AND_DATA")
                                )
                        )
                )
-               fsm.act("SEND_READ_CMD",
-                       source.stb.eq(1),
+
+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.errors = Signal(32)
+
+               ###
+
+               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.error_counter = Counter(self.errors, bits_sign=32)
+
+               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,
+                               self.error_counter.reset.eq(1),
+                               NextState("SEND_CMD")
+                       )
+               )
+               self.comb += [
                        source.sop.eq(1),
                        source.eop.eq(1),
                        source.read.eq(1),
                        source.sector.eq(self.sector),
                        source.count.eq(self.count),
+               ]
+               fsm.act("SEND_CMD",
+                       source.stb.eq(1),
                        If(source.ack,
                                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,
-                               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),
                        If(sink.stb,
                                counter.ce.eq(1),
-                               If(sink.data != scrambler.value,
+                               If(sink.data != expected_data,
                                        self.error_counter.ce.eq(1)
                                ),
                                If(sink.eop,
@@ -98,33 +145,45 @@ class SATABIST(Module):
                                                If(loops_counter.value == (self.loops-1),
                                                        NextState("IDLE")
                                                ).Else(
-                                                       NextState("SEND_READ_CMD")
+                                                       NextState("SEND_CMD")
                                                )
                                        ).Else(
-                                               NextState("WAIT_READ_ACK")
+                                               NextState("WAIT_ACK")
                                        )
                                )
                        )
                )
 
 class SATABISTControl(Module, AutoCSR):
-       def __init__(self, sata_bist):
-               self._write = CSR()
-               self._read = CSR()
+       def __init__(self, bist_unit):
+               self._start = CSR()
                self._sector = CSRStorage(48)
                self._count = CSRStorage(16)
+               self._random = CSRStorage()
                self._loops = CSRStorage(8)
-
                self._done = CSRStatus()
                self._errors = CSRStatus(32)
 
+               ###
+               self.bist_unit = bist_unit
                self.comb += [
-                       sata_bist.write.eq(self._write.r & self._write.re),
-                       sata_bist.read.eq(self._read.r & self._read.re),
-                       sata_bist.sector.eq(self._sector.storage),
-                       sata_bist.count.eq(self._count.storage),
-                       sata_bist.loops.eq(self._loops.storage),
-
-                       self._done.status.eq(sata_bist.done),
-                       self._errors.status.eq(sata_bist.errors)
+                       bist_unit.start.eq(self._start.r & self._start.re),
+                       bist_unit.sector.eq(self._sector.storage),
+                       bist_unit.count.eq(self._count.storage),
+                       bist_unit.loops.eq(self._loops.storage),
+                       bist_unit.random.eq(self._random.storage),
+
+                       self._done.status.eq(bist_unit.done),
+                       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
index dafc535b2a5ec8cf33f295bb33775d6a5f19ba62..8b2ce5b8c7e725b3883515588102555e4ccf8fc1 100644 (file)
@@ -26,6 +26,7 @@ class SATACommandTX(Module):
                        transport.sink.count.eq(sink.count),
                        transport.sink.icc.eq(0),
                        transport.sink.control.eq(0),
+                       transport.sink.data.eq(sink.data)
                ]
 
                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.type.eq(fis_types["DATA"]),
-                       transport.sink.data.eq(sink.data),
                        sink.ack.eq(transport.sink.ack),
                        If(sink.stb & sink.ack,
                                If(sink.eop,
@@ -171,11 +171,13 @@ class SATACommandRX(Module):
                                )
                        )
                )
-               fsm.act("PRESENT_READ_DATA",
-                       data_buffer.sink.stb.eq(transport.source.stb),
+               self.comb += [
                        data_buffer.sink.sop.eq(transport.source.sop),
                        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),
                        If(data_buffer.sink.stb & data_buffer.sink.ack,
                                self.dwords_counter.ce.eq(~read_done),
@@ -230,6 +232,7 @@ class SATACommandRX(Module):
                        source.last.eq(cmd_buffer.source.last),
                        source.success.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",
@@ -237,7 +240,6 @@ class SATACommandRX(Module):
                        source.sop.eq(data_buffer.source.sop),
                        source.eop.eq(data_buffer.source.eop),
 
-                       source.data.eq(data_buffer.source.data),
                        data_buffer.source.ack.eq(source.ack),
 
                        If(source.stb & source.eop & source.ack,
index ecb6723a352d7318e9e5e0001714f7da667a610a..32cabdc7b12591cac5e3e60037c9d6ef37f6cc7e 100644 (file)
@@ -210,6 +210,7 @@ class Counter(Module):
                self.width = flen(self.value)
                self.sync += self.value.eq(self.value+1)
 
+# XXX use ModuleDecorator
 class BufferizeEndpoints(Module):
        def __init__(self, decorated, *args):
                self.decorated = decorated
diff --git a/lib/sata/frontend/arbiter.py b/lib/sata/frontend/arbiter.py
new file mode 100644 (file)
index 0000000..678f2d7
--- /dev/null
@@ -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)
diff --git a/lib/sata/frontend/common.py b/lib/sata/frontend/common.py
new file mode 100644 (file)
index 0000000..114a0a8
--- /dev/null
@@ -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)
+               ]
diff --git a/lib/sata/frontend/crossbar.py b/lib/sata/frontend/crossbar.py
new file mode 100644 (file)
index 0000000..41ac806
--- /dev/null
@@ -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)
index 381bba88b43b53f3e65bb4e6f38ece9c46874bb1..b142e68cbc73a667c2a7b64629bd11273e57f345 100644 (file)
@@ -187,10 +187,12 @@ class SATALinkRX(Module):
                                NextState("COPY")
                        )
                )
+               self.comb += [
+                       scrambler.sink.sop.eq(sop),
+                       scrambler.sink.eop.eq(eop)
+               ]
                fsm.act("COPY",
                        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"]),
                        If(det == primitives["HOLD"],
                                insert.eq(primitives["HOLDA"])
index 06476737736acf92b01dc2effe8b5585049e2dba..72c99979fa6779f81207e9e340b3691ca7ec95ea 100644 (file)
@@ -1,6 +1,6 @@
 from lib.sata.common import *
 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.common import *
@@ -11,31 +11,35 @@ class TB(Module):
                                link_debug=False, link_random_level=0,
                                transport_debug=False, transport_loopback=False,
                                hdd_debug=True)
-               self.con = SATACON(self.hdd.phy)
-               self.bist = SATABIST(self.con)
+               self.controller = SATACON(self.hdd.phy)
+               self.generator = SATABISTGenerator(self.controller.crossbar.get_port())
+               self.checker = SATABISTChecker(self.controller.crossbar.get_port())
 
        def gen_simulation(self, selfp):
                hdd = self.hdd
                hdd.malloc(0, 64)
-               selfp.bist.sector = 0
-               selfp.bist.count = 17
-               selfp.bist.loops = 1
+               selfp.generator.sector = 0
+               selfp.generator.count = 17
+               selfp.checker.sector = 0
+               selfp.checker.count = 17
                while True:
-                       selfp.bist.write = 1
+                       selfp.generator.start = 1
                        yield
-                       selfp.bist.write = 0
+                       selfp.generator.start = 0
                        yield
-                       while selfp.bist.done == 0:
+                       while selfp.generator.done == 0:
                                yield
-                       selfp.bist.read = 1
+                       selfp.checker.start = 1
                        yield
-                       selfp.bist.read = 0
+                       selfp.checker.start = 0
                        yield
-                       while selfp.bist.done == 0:
+                       while selfp.checker.done == 0:
                                yield
-                       print("errors {}".format(selfp.bist.errors))
-                       selfp.bist.sector += 1
-                       selfp.bist.count = max((selfp.bist.count + 1)%8, 1)
+                       print("errors {}".format(selfp.checker.errors))
+                       selfp.generator.sector += 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__":
        run_simulation(TB(), ncycles=8192*2, vcd_name="my.vcd", keep_files=True)
index 850086ee3a4d626e7fddde736c28a98a26fafe4f..e186ba8c6909f85a19dd1c5bab9d849cab75bd42 100644 (file)
@@ -159,8 +159,8 @@ class DebugLeds(Module):
 class TestDesign(UART2WB, AutoCSR):
        default_platform = "kc705"
        csr_map = {
-               "sata_bist_ctrl":       10,
-               "mila":                         11
+               "sata_bist":    10,
+               "mila":                 11
        }
        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_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)
 
@@ -189,22 +188,22 @@ class TestDesign(UART2WB, AutoCSR):
                                self.sata_phy.sink.data,
                                self.sata_phy.sink.charisk,
 
-                               self.sata_con.sink.stb,
-                               self.sata_con.sink.sop,
-                               self.sata_con.sink.eop,
-                               self.sata_con.sink.ack,
-                               self.sata_con.sink.write,
-                               self.sata_con.sink.read,
-
-                               self.sata_con.source.stb,
-                               self.sata_con.source.sop,
-                               self.sata_con.source.eop,
-                               self.sata_con.source.ack,
-                               self.sata_con.source.write,
-                               self.sata_con.source.read,
-                               self.sata_con.source.success,
-                               self.sata_con.source.failed,
-                               self.sata_con.source.data
+                               self.sata_con.command.sink.stb,
+                               self.sata_con.command.sink.sop,
+                               self.sata_con.command.sink.eop,
+                               self.sata_con.command.sink.ack,
+                               self.sata_con.command.sink.write,
+                               self.sata_con.command.sink.read,
+
+                               self.sata_con.command.source.stb,
+                               self.sata_con.command.source.sop,
+                               self.sata_con.command.source.eop,
+                               self.sata_con.command.source.ack,
+                               self.sata_con.command.source.write,
+                               self.sata_con.command.source.read,
+                               self.sata_con.command.source.success,
+                               self.sata_con.command.source.failed,
+                               self.sata_con.command.source.data
                        )
 
                        self.mila = MiLa(depth=2048, dat=Cat(*debug))
index 86d116a2e35d2a0126f3ff588bee1d66dc761d98..82d11a726fe0c63cd3155ee8acf8373334ba6bda 100644 (file)
@@ -5,35 +5,57 @@ from config import *
 logical_sector_size = 512
 
 class SATABISTDriver:
-       def __init__(self, regs):
+       def __init__(self, regs, name):
                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):
-               self.regs.sata_bist_ctrl_sector.write(sector)
-               self.regs.sata_bist_ctrl_count.write(count)
-               self.regs.sata_bist_ctrl_loops.write(loops)
-               if mode == "write":
-                       self.regs.sata_bist_ctrl_write.write(1)
-               elif mode == "read":
-                       self.regs.sata_bist_ctrl_read.write(1)
-               while (self.regs.sata_bist_ctrl_done.read() == 0):
+       def run(self, sector, count, loops, random):
+               self.sector.write(sector)
+               self.count.write(count)
+               self.loops.write(loops)
+               self.random.write(random)
+               self.start.write(1)
+               while (self.done.read() == 0):
                        pass
-               return self.regs.sata_bist_ctrl_errors.read()
+               return self.errors.read()
 
-       def write(self, sector, count, loops):
-               self.run(sector, count, loops, "write")
+class SATABISTGeneratorDriver(SATABISTDriver):
+       def __init__(self, regs, name):
+               SATABISTDriver.__init__(self, regs, name + "_generator")
 
-       def read(self, sector, count, loops):
-               return self.run(sector, count, loops, "read")
+class SATABISTCheckerDriver(SATABISTDriver):
+       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():
        parser = argparse.ArgumentParser(formatter_class=argparse.RawDescriptionHelpFormatter,
                description="""\
 SATA BIST utility.
 """)
-       parser.add_argument("-s", "--sector", default=0, help="BIST start sector")
-       parser.add_argument("-c", "--count", default=16384, help="BIST count (number of sectors per transaction)")
-       parser.add_argument("-l", "--loops", default=4, help="BIST loops (number of loop for each transaction")
+       parser.add_argument("-s", "--sector", default=0, help="start sector")
+       parser.add_argument("-c", "--count", default=16384, help="number of sectors per 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()
 
@@ -41,31 +63,30 @@ if __name__ == "__main__":
        args = _get_args()
        wb.open()
        ###
-       bist = SATABISTDriver(wb.regs)
+       generator = SATABISTGeneratorDriver(wb.regs, "sata_bist")
+       checker = SATABISTCheckerDriver(wb.regs, "sata_bist")
+       timer = Timer()
+
        sector = int(args.sector)
        count = int(args.count)
        loops = int(args.loops)
+       random = int(args.random)
        try:
-               write_time = 0
-               read_time = 0
                while True:
-                       # Write
-                       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
+                       # generator (write data to HDD)
+                       timer.start()
+                       generator.run(sector, count, loops, random)
+                       timer.stop()
+                       write_speed = compute_speed(loops, count, timer.value, MB)
 
+                       # 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
 
-                       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:
                pass