From e8cf9908ef0c2247e41102cf9d91c1c823c8efd3 Mon Sep 17 00:00:00 2001 From: Jean THOMAS Date: Thu, 4 Jun 2020 19:17:21 +0200 Subject: [PATCH] Bugfixing --- gram/core/bankmachine.py | 68 +- gram/core/crossbar.py | 35 +- gram/frontend/adaptation.py | 303 ++++--- gram/phy/__init__.py | 12 +- gram/phy/model.py | 8 +- gram/stream.py | 2 +- test/__init__.py | 0 test/access_pattern.csv | 1024 ------------------------ test/benchmark.py | 267 ------- test/benchmarks.yml | 1047 ------------------------- test/common.py | 647 --------------- test/gen_access_pattern.py | 35 - test/gen_config.py | 138 ---- test/reference/ddr3_init.h | 117 --- test/reference/ddr3_init.py | 23 - test/reference/ddr4_init.h | 133 ---- test/reference/ddr4_init.py | 26 - test/reference/sdr_init.h | 90 --- test/reference/sdr_init.py | 21 - test/run_benchmarks.py | 670 ---------------- test/spd_data/MT16KTF1G64HZ-1G6P1.csv | 76 -- test/spd_data/MT16KTF1G64HZ-1G9E1.csv | 76 -- test/spd_data/MT18KSF1G72HZ-1G4E2.csv | 76 -- test/spd_data/MT18KSF1G72HZ-1G6E2.csv | 76 -- test/spd_data/MT8JTF12864AZ-1G4G1.csv | 68 -- test/spd_data/MT8KTF51264HZ-1G4E1.csv | 76 -- test/spd_data/MT8KTF51264HZ-1G6E1.csv | 76 -- test/spd_data/MT8KTF51264HZ-1G9P1.csv | 76 -- test/summary/summary.css | 100 --- test/summary/summary.html.jinja2 | 160 ---- test/test_adaptation.py | 283 ------- test/test_axi.py | 275 ------- test/test_bandwidth.py | 242 ------ test/test_bankmachine.py | 427 ---------- test/test_bist.py | 446 ----------- test/test_command_chooser.py | 223 ------ test/test_crossbar.py | 511 ------------ test/test_dma.py | 174 ---- test/test_ecc.py | 321 -------- test/test_examples.py | 28 - test/test_fifo.py | 304 ------- test/test_init.py | 43 - test/test_modules.py | 170 ---- test/test_multiplexer.py | 580 -------------- test/test_refresh.py | 110 --- test/test_steerer.py | 238 ------ test/test_timing.py | 119 --- test/test_wishbone.py | 111 --- 48 files changed, 238 insertions(+), 9893 deletions(-) delete mode 100644 test/__init__.py delete mode 100644 test/access_pattern.csv delete mode 100755 test/benchmark.py delete mode 100644 test/benchmarks.yml delete mode 100644 test/common.py delete mode 100755 test/gen_access_pattern.py delete mode 100755 test/gen_config.py delete mode 100644 test/reference/ddr3_init.h delete mode 100644 test/reference/ddr3_init.py delete mode 100644 test/reference/ddr4_init.h delete mode 100644 test/reference/ddr4_init.py delete mode 100644 test/reference/sdr_init.h delete mode 100644 test/reference/sdr_init.py delete mode 100755 test/run_benchmarks.py delete mode 100644 test/spd_data/MT16KTF1G64HZ-1G6P1.csv delete mode 100644 test/spd_data/MT16KTF1G64HZ-1G9E1.csv delete mode 100644 test/spd_data/MT18KSF1G72HZ-1G4E2.csv delete mode 100644 test/spd_data/MT18KSF1G72HZ-1G6E2.csv delete mode 100644 test/spd_data/MT8JTF12864AZ-1G4G1.csv delete mode 100644 test/spd_data/MT8KTF51264HZ-1G4E1.csv delete mode 100644 test/spd_data/MT8KTF51264HZ-1G6E1.csv delete mode 100644 test/spd_data/MT8KTF51264HZ-1G9P1.csv delete mode 100644 test/summary/summary.css delete mode 100644 test/summary/summary.html.jinja2 delete mode 100644 test/test_adaptation.py delete mode 100644 test/test_axi.py delete mode 100644 test/test_bandwidth.py delete mode 100644 test/test_bankmachine.py delete mode 100644 test/test_bist.py delete mode 100644 test/test_command_chooser.py delete mode 100644 test/test_crossbar.py delete mode 100644 test/test_dma.py delete mode 100644 test/test_ecc.py delete mode 100644 test/test_examples.py delete mode 100644 test/test_fifo.py delete mode 100644 test/test_init.py delete mode 100644 test/test_modules.py delete mode 100644 test/test_multiplexer.py delete mode 100644 test/test_refresh.py delete mode 100644 test/test_steerer.py delete mode 100644 test/test_timing.py delete mode 100644 test/test_wishbone.py diff --git a/gram/core/bankmachine.py b/gram/core/bankmachine.py index d96230f..417a9b2 100644 --- a/gram/core/bankmachine.py +++ b/gram/core/bankmachine.py @@ -94,6 +94,9 @@ class BankMachine(Elaboratable): ba = settings.geom.bankbits + log2_int(nranks) self.cmd = cmd = stream.Endpoint(cmd_request_rw_layout(a, ba)) + self._address_align = address_align + self._n = n + def elaborate(self, platform): m = Module() @@ -107,13 +110,18 @@ class BankMachine(Elaboratable): cmd_buffer = stream.Buffer(cmd_buffer_layout) # 1 depth buffer to detect row change m.submodules += cmd_buffer_lookahead, cmd_buffer m.d.comb += [ - self.req.connect(cmd_buffer_lookahead.sink, include={"valid", "ready", "we", "addr"}), + #self.req.connect(cmd_buffer_lookahead.sink, include={"valid", "ready", "payload.we", "payload.addr"}), + cmd_buffer_lookahead.sink.valid.eq(self.req.valid), + cmd_buffer_lookahead.sink.ready.eq(self.req.ready), + cmd_buffer_lookahead.sink.payload.we.eq(self.req.we), + cmd_buffer_lookahead.sink.payload.addr.eq(self.req.addr), + cmd_buffer_lookahead.source.connect(cmd_buffer.sink), cmd_buffer.source.ready.eq(self.req.wdata_ready | self.req.rdata_valid), self.req.lock.eq(cmd_buffer_lookahead.source.valid | cmd_buffer.source.valid), ] - slicer = _AddressSlicer(self.settings.geom.colbits, address_align) + slicer = _AddressSlicer(self.settings.geom.colbits, self._address_align) # Row tracking ----------------------------------------------------------------------------- row = Signal(self.settings.geom.rowbits) @@ -132,29 +140,29 @@ class BankMachine(Elaboratable): # Address generation ----------------------------------------------------------------------- row_col_n_addr_sel = Signal() - m.d.comb += cmd.ba.eq(n) + m.d.comb += self.cmd.ba.eq(self._n) with m.If(row_col_n_addr_sel): - m.d.comb += cmd.a.eq(slicer.row(cmd_buffer.source.addr)) + m.d.comb += self.cmd.a.eq(slicer.row(cmd_buffer.source.addr)) with m.Else(): - m.d.comb += cmd.a.eq((auto_precharge << 10) | slicer.col(cmd_buffer.source.addr)) + m.d.comb += self.cmd.a.eq((auto_precharge << 10) | slicer.col(cmd_buffer.source.addr)) # tWTP (write-to-precharge) controller ----------------------------------------------------- write_latency = math.ceil(self.settings.phy.cwl / self.settings.phy.nphases) precharge_time = write_latency + self.settings.timing.tWR + self.settings.timing.tCCD # AL=0 m.submodules.twtpcon = twtpcon = tXXDController(precharge_time) - m.d.comb += twtpcon.valid.eq(cmd.valid & cmd.ready & cmd.is_write) + m.d.comb += twtpcon.valid.eq(self.cmd.valid & self.cmd.ready & self.cmd.is_write) # tRC (activate-activate) controller ------------------------------------------------------- m.submodules.trccon = trccon = tXXDController(self.settings.timing.tRC) - m.d.comb += trccon.valid.eq(cmd.valid & cmd.ready & row_open) + m.d.comb += trccon.valid.eq(self.cmd.valid & self.cmd.ready & row_open) # tRAS (activate-precharge) controller ----------------------------------------------------- m.submodules.trascon = trascon = tXXDController(self.settings.timing.tRAS) - m.d.comb += trascon.valid.eq(cmd.valid & cmd.ready & row_open) + m.d.comb += trascon.valid.eq(self.cmd.valid & self.cmd.ready & row_open) # Auto Precharge generation ---------------------------------------------------------------- # generate auto precharge when current and next cmds are to different rows - if settings.with_auto_precharge: + if self.settings.with_auto_precharge: with m.If(cmd_buffer_lookahead.source.valid & cmd_buffer.source.valid): with m.If(slicer.row(cmd_buffer_lookahead.source.addr) != slicer.row(cmd_buffer.source.addr)): m.d.comb += auto_precharge.eq(row_close == 0) @@ -163,27 +171,27 @@ class BankMachine(Elaboratable): # Note: tRRD, tFAW, tCCD, tWTR timings are enforced by the multiplexer with m.FSM(): with m.State("Regular"): - with m.If(refresh_req): + with m.If(self.refresh_req): m.next = "Refresh" with m.Elif(cmd_buffer.source.valid): with m.If(row_opened): with m.If(row_hit): m.d.comb += [ - cmd.valid.eq(1), - cmd.cas.eq(1), + self.cmd.valid.eq(1), + self.cmd.cas.eq(1), ] with m.If(cmd_buffer.source.we): m.d.comb += [ - self.req.wdata_ready.eq(cmd.ready), - cmd.is_write.eq(1), - cmd.we.eq(1), + self.req.wdata_ready.eq(self.cmd.ready), + self.cmd.is_write.eq(1), + self.cmd.we.eq(1), ] with m.Else(): m.d.comb += [ - self.req.rdata_valid.eq(cmd.ready), - cmd.is_read.eq(1), + self.req.rdata_valid.eq(self.cmd.ready), + self.cmd.is_read.eq(1), ] - with m.If(cmd.ready & auto_precharge): + with m.If(self.cmd.ready & auto_precharge): m.next = "Autoprecharge" with m.Else(): m.next = "Precharge" @@ -195,13 +203,13 @@ class BankMachine(Elaboratable): with m.If(twtpcon.ready & trascon.ready): m.d.comb += [ - cmd.valid.eq(1), - cmd.ras.eq(1), - cmd.we.eq(1), - cmd.is_cmd.eq(1), + self.cmd.valid.eq(1), + self.cmd.ras.eq(1), + self.cmd.we.eq(1), + self.cmd.is_cmd.eq(1), ] - with m.If(cmd.ready): + with m.If(self.cmd.ready): m.next = "tRP" with m.State("Autoprecharge"): @@ -215,22 +223,22 @@ class BankMachine(Elaboratable): m.d.comb += [ row_col_n_addr_sel.eq(1), row_open.eq(1), - cmd.valid.eq(1), - cmd.is_cmd.eq(1), - cmd.ras.eq(1), + self.cmd.valid.eq(1), + self.cmd.is_cmd.eq(1), + self.cmd.ras.eq(1), ] - with m.If(cmd.ready): + with m.If(self.cmd.ready): m.next = "tRCD" with m.State("Refresh"): m.d.comb += [ row_close.eq(1), - cmd.is_cmd.eq(1), + self.cmd.is_cmd.eq(1), ] with m.If(twtpcon.ready): - m.d.comb += refresh_gnt.eq(1) - with m.If(~refresh_req): + m.d.comb += self.refresh_gnt.eq(1) + with m.If(~self.refresh_req): m.next = "Regular" delayed_enter(m, "tRP", "Activate", self.settings.timing.tRP - 1) diff --git a/gram/core/crossbar.py b/gram/core/crossbar.py index 5efbd2b..1ca18e7 100644 --- a/gram/core/crossbar.py +++ b/gram/core/crossbar.py @@ -82,7 +82,7 @@ class gramCrossbar(Elaboratable): data_width = self.controller.data_width # Crossbar port ---------------------------------------------------------------------------- - port = LiteDRAMNativePort( + port = gramNativePort( mode = mode, address_width = self.rca_bits + self.bank_bits - self.rank_bits, data_width = self.controller.data_width, @@ -92,13 +92,13 @@ class gramCrossbar(Elaboratable): # Clock domain crossing -------------------------------------------------------------------- if clock_domain != "sys": - new_port = LiteDRAMNativePort( + new_port = gramNativePort( mode = mode, address_width = port.address_width, data_width = port.data_width, clock_domain = clock_domain, id = port.id) - self.submodules += LiteDRAMNativePortCDC(new_port, port) + self.submodules += gramNativePortCDC(new_port, port) port = new_port # Data width convertion -------------------------------------------------------------------- @@ -107,7 +107,7 @@ class gramCrossbar(Elaboratable): addr_shift = -log2_int(data_width//self.controller.data_width) else: addr_shift = log2_int(self.controller.data_width//data_width) - new_port = LiteDRAMNativePort( + new_port = gramNativePort( mode = mode, address_width = port.address_width + addr_shift, data_width = data_width, @@ -128,8 +128,8 @@ class gramCrossbar(Elaboratable): # Address mapping -------------------------------------------------------------------------- cba_shifts = {"ROW_BANK_COL": controller.settings.geom.colbits - controller.address_align} cba_shift = cba_shifts[controller.settings.address_mapping] - m_ba = [m.get_bank_address(self.bank_bits, cba_shift)for m in self.masters] - m_rca = [m.get_row_column_address(self.bank_bits, self.rca_bits, cba_shift) for m in self.masters] + m_ba = [master.get_bank_address(self.bank_bits, cba_shift) for master in self.masters] + m_rca = [master.get_row_column_address(self.bank_bits, self.rca_bits, cba_shift) for master in self.masters] master_readys = [0]*nmasters master_wdata_readys = [0]*nmasters @@ -195,17 +195,18 @@ class gramCrossbar(Elaboratable): m.d.comb += master.rdata.valid.eq(master_rdata_valid) # Route data writes ------------------------------------------------------------------------ - wdata_cases = {} - for nm, master in enumerate(self.masters): - wdata_cases[2**nm] = [ - controller.wdata.eq(master.wdata.data), - controller.wdata_we.eq(master.wdata.we) - ] - wdata_cases["default"] = [ - controller.wdata.eq(0), - controller.wdata_we.eq(0) - ] - m.d.comb += Case(Cat(*master_wdata_readys), wdata_cases) + with m.Switch(Cat(*master_wdata_readys)): + with m.Case(): + m.d.comb += [ + controller.wdata.eq(0), + controller.wdata_we.eq(0), + ] + for nm, master in enumerate(self.masters): + with m.Case(2**nm): + m.d.comb = [ + controller.wdata.eq(master.wdata.data), + controller.wdata_we.eq(master.wdata.we), + ] # Route data reads ------------------------------------------------------------------------- for master in self.masters: diff --git a/gram/frontend/adaptation.py b/gram/frontend/adaptation.py index 64650fc..ac5c49f 100644 --- a/gram/frontend/adaptation.py +++ b/gram/frontend/adaptation.py @@ -1,15 +1,15 @@ # This file is Copyright (c) 2016-2019 Florent Kermarrec # License: BSD -from migen import * +from nmigen import * +from nmigen.compat import Case -from litex.soc.interconnect import stream - -from litedram.common import * +from gram.common import * +import gram.stream as stream # LiteDRAMNativePortCDC ---------------------------------------------------------------------------- -class LiteDRAMNativePortCDC(Module): +class gramNativePortCDC(Elaboratable): def __init__(self, port_from, port_to, cmd_depth = 4, wdata_depth = 16, @@ -18,21 +18,34 @@ class LiteDRAMNativePortCDC(Module): assert port_from.data_width == port_to.data_width assert port_from.mode == port_to.mode - address_width = port_from.address_width - data_width = port_from.data_width - mode = port_from.mode - clock_domain_from = port_from.clock_domain - clock_domain_to = port_to.clock_domain + self._port_from = port_from + self._port_to = port_to + self._cmd_depth = cmd_depth + self._wdata_depth = wdata_depth + self._rdata_depth = rdata_depth + + def elaborate(self, platform): + m = Module() - # # # + port_from = self._port_from + port_to = self._port_to + cmd_depth = self._cmd_depth + wdata_depth = self._wdata_depth + rdata_depth = self._rdata_depth + + address_width = port_from.address_width + data_width = port_from.data_width + mode = port_from.mode + clock_domain_from = port_from.clock_domain + clock_domain_to = port_to.clock_domain cmd_fifo = stream.AsyncFIFO( [("we", 1), ("addr", address_width)], cmd_depth) cmd_fifo = ClockDomainsRenamer( {"write": clock_domain_from, "read": clock_domain_to})(cmd_fifo) - self.submodules += cmd_fifo - self.submodules += stream.Pipeline( + m.submodules += cmd_fifo + m.submodules += stream.Pipeline( port_from.cmd, cmd_fifo, port_to.cmd) if mode == "write" or mode == "both": @@ -41,8 +54,8 @@ class LiteDRAMNativePortCDC(Module): wdata_fifo = ClockDomainsRenamer( {"write": clock_domain_from, "read": clock_domain_to})(wdata_fifo) - self.submodules += wdata_fifo - self.submodules += stream.Pipeline( + m.submodules += wdata_fifo + m.submodules += stream.Pipeline( port_from.wdata, wdata_fifo, port_to.wdata) if mode == "read" or mode == "both": @@ -50,13 +63,15 @@ class LiteDRAMNativePortCDC(Module): rdata_fifo = ClockDomainsRenamer( {"write": clock_domain_to, "read": clock_domain_from})(rdata_fifo) - self.submodules += rdata_fifo - self.submodules += stream.Pipeline( + m.submodules += rdata_fifo + m.submodules += stream.Pipeline( port_to.rdata, rdata_fifo, port_from.rdata) + return m + # LiteDRAMNativePortDownConverter ------------------------------------------------------------------ -class LiteDRAMNativePortDownConverter(Module): +class gramNativePortDownConverter(Elaboratable): """LiteDRAM port DownConverter This module reduces user port data width to fit controller data width. @@ -74,7 +89,16 @@ class LiteDRAMNativePortDownConverter(Module): if port_from.data_width % port_to.data_width: raise ValueError("Ratio must be an int") - # # # + self._port_from = port_from + self._port_to = port_to + self._reverse = reverse + + def elaborate(self, platform): + m = Module() + + port_from = self._port_from + port_to = self._port_to + reverse = self._reverse ratio = port_from.data_width//port_to.data_width mode = port_from.mode @@ -82,40 +106,37 @@ class LiteDRAMNativePortDownConverter(Module): counter = Signal(max=ratio) counter_reset = Signal() counter_ce = Signal() - self.sync += \ - If(counter_reset, - counter.eq(0) - ).Elif(counter_ce, - counter.eq(counter + 1) - ) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - counter_reset.eq(1), - If(port_from.cmd.valid, - NextState("CONVERT") - ) - ) - fsm.act("CONVERT", - port_to.cmd.valid.eq(1), - port_to.cmd.we.eq(port_from.cmd.we), - port_to.cmd.addr.eq(port_from.cmd.addr*ratio + counter), - If(port_to.cmd.ready, - counter_ce.eq(1), - If(counter == ratio - 1, - port_from.cmd.ready.eq(1), - NextState("IDLE") - ) - ) - ) + with m.If(counter_reset): + m.d.sync += counter.eq(0) + with m.Elif(counter_ce): + m.d.sync += counter.eq(counter+1) + + with m.FSM(): + with m.State("Idle"): + m.d.comb += counter_reset.eq(1) + with m.If(port_from.cmd.valid): + m.next = "Convert" + + with m.State("Convert"): + m.d.comb += [ + port_to.cmd.valid.eq(1), + port_to.cmd.we.eq(port_from.cmd.we), + port_to.cmd.addr.eq(port_from.cmd.addr*ratio + counter), + ] + with m.If(port_to.cmd.ready): + m.d.comb += counter_ce.eq(1) + with m.If(counter == ratio - 1): + m.d.comb += port_from.cmd.ready.eq(1) + m.next = "Idle" if mode == "write" or mode == "both": wdata_converter = stream.StrideConverter( port_from.wdata.description, port_to.wdata.description, reverse=reverse) - self.submodules += wdata_converter - self.submodules += stream.Pipeline( + m.submodules += wdata_converter + m.submodules += stream.Pipeline( port_from.wdata, wdata_converter, port_to.wdata) if mode == "read" or mode == "both": @@ -123,13 +144,15 @@ class LiteDRAMNativePortDownConverter(Module): port_to.rdata.description, port_from.rdata.description, reverse=reverse) - self.submodules += rdata_converter - self.submodules += stream.Pipeline( + m.submodules += rdata_converter + m.submodules += stream.Pipeline( port_to.rdata, rdata_converter, port_from.rdata) + return m + # LiteDRAMNativeWritePortUpConverter --------------------------------------------------------------- -class LiteDRAMNativeWritePortUpConverter(Module): +class gramNativeWritePortUpConverter(Elaboratable): # TODO: finish and remove hack """LiteDRAM write port UpConverter @@ -147,7 +170,16 @@ class LiteDRAMNativeWritePortUpConverter(Module): if port_to.data_width % port_from.data_width: raise ValueError("Ratio must be an int") - # # # + self._port_from = port_from + self._port_to = port_to + self._reverse = reverse + + def elaborate(self, platform): + m = Module() + + port_from = self._port_from + port_to = self._port_to + reverse = self._reverse ratio = port_to.data_width//port_from.data_width @@ -164,47 +196,47 @@ class LiteDRAMNativeWritePortUpConverter(Module): counter.eq(counter + 1) ) - self.submodules.fsm = fsm = FSM(reset_state="IDLE") - fsm.act("IDLE", - port_from.cmd.ready.eq(1), - If(port_from.cmd.valid, - counter_ce.eq(1), - NextValue(we, port_from.cmd.we), - NextValue(address, port_from.cmd.addr), - NextState("RECEIVE") - ) - ) - fsm.act("RECEIVE", - port_from.cmd.ready.eq(1), - If(port_from.cmd.valid, - counter_ce.eq(1), - If(counter == ratio-1, - NextState("GENERATE") - ) - ) - ) - fsm.act("GENERATE", - port_to.cmd.valid.eq(1), - port_to.cmd.we.eq(we), - port_to.cmd.addr.eq(address[log2_int(ratio):]), - If(port_to.cmd.ready, - NextState("IDLE") - ) - ) + with m.FSM(): + with m.State("Idle"): + m.d.comb += port_from.cmd.ready.eq(1) + with m.If(port_from.cmd.valid): + m.d.sync += [ + we.eq(port_from.cmd.we), + address.eq(port_from.cmd.addr), + ] + m.next = "Receive" + + with m.State("Receive"): + m.d.comb += port_from.cmd.ready.eq(1) + with m.If(port_from.cmd.valid): + m.d.comb += counter_ce.eq(1) + with m.If(counter == ratio-1): + m.next = "Generate" + + with m.State("Generate"): + m.d.comb += [ + port_to.cmd.valid.eq(1), + port_to.cmd.we.eq(we), + port_to.cmd.addr.eq(address[log2_int(ratio):]), + ] + with m.If(port_to.cmd.ready): + m.next = "Idle" wdata_converter = stream.StrideConverter( port_from.wdata.description, port_to.wdata.description, reverse=reverse) - self.submodules += wdata_converter - self.submodules += stream.Pipeline( + m.submodules += wdata_converter + m.submodules += stream.Pipeline( port_from.wdata, wdata_converter, port_to.wdata) + return m + # LiteDRAMNativeReadPortUpConverter ---------------------------------------------------------------- -class LiteDRAMNativeReadPortUpConverter(Module): +class gramNativeReadPortUpConverter(Elaboratable): """LiteDRAM port UpConverter This module increase user port data width to fit controller data width. @@ -221,42 +253,49 @@ class LiteDRAMNativeReadPortUpConverter(Module): if port_to.data_width % port_from.data_width: raise ValueError("Ratio must be an int") - # # # + self._port_from = port_from + self._port_to = port_to + self._reverse = reverse - ratio = port_to.data_width//port_from.data_width + def elaborate(self, platform): + m = Module() + port_from = self._port_from + port_to = self._port_to + reverse = self._reverse + + ratio = port_to.data_width//port_from.data_width # Command ---------------------------------------------------------------------------------- cmd_buffer = stream.SyncFIFO([("sel", ratio)], 4) - self.submodules += cmd_buffer + m.submodules += cmd_buffer - counter = Signal(max=ratio) + counter = Signal(range(ratio)) counter_ce = Signal() - self.sync += \ - If(counter_ce, - counter.eq(counter + 1) - ) + with m.If(counter_ce): + m.d.sync += counter.eq(counter+1) - self.comb += \ - If(port_from.cmd.valid, - If(counter == 0, + with m.If(port_from.cmd.valid): + with m.If(counter == 0): + m.d.comb += [ port_to.cmd.valid.eq(1), port_to.cmd.addr.eq(port_from.cmd.addr[log2_int(ratio):]), port_from.cmd.ready.eq(port_to.cmd.ready), - counter_ce.eq(port_to.cmd.ready) - ).Else( + counter_ce.eq(port_to.cmd.ready), + ] + with m.Else(): + m.d.comb += [ port_from.cmd.ready.eq(1), - counter_ce.eq(1) - ) - ) + counter_ce.eq(1), + ] # TODO: fix sel - self.comb += \ - If(port_to.cmd.valid & port_to.cmd.ready, + with m.If(port_to.cmd.valid & port_to.cmd.ready): + m.d.comb += [ cmd_buffer.sink.valid.eq(1), - cmd_buffer.sink.sel.eq(2**ratio-1) - ) + cmd_buffer.sink.sel.eq(2**ratio-1), + ] # Datapath --------------------------------------------------------------------------------- @@ -265,60 +304,70 @@ class LiteDRAMNativeReadPortUpConverter(Module): port_to.rdata.description, port_from.rdata.description, reverse=reverse) - self.submodules += rdata_buffer, rdata_converter + m.submodules += rdata_buffer, rdata_converter rdata_chunk = Signal(ratio, reset=1) rdata_chunk_valid = Signal() - self.sync += \ - If(rdata_converter.source.valid & - rdata_converter.source.ready, - rdata_chunk.eq(Cat(rdata_chunk[ratio-1], rdata_chunk[:ratio-1])) - ) + with m.If(rdata_converter.source.valid & rdata_converter.source.ready): + m.d.sync += rdata_chunk.eq(Cat(rdata_chunk[ratio-1], rdata_chunk[:ratio-1])) - self.comb += [ + m.d.comb += [ port_to.rdata.connect(rdata_buffer.sink), rdata_buffer.source.connect(rdata_converter.sink), rdata_chunk_valid.eq((cmd_buffer.source.sel & rdata_chunk) != 0), - If(port_from.flush, - rdata_converter.source.ready.eq(1) - ).Elif(cmd_buffer.source.valid, - If(rdata_chunk_valid, + cmd_buffer.source.ready.eq(rdata_converter.source.ready & rdata_chunk[ratio-1]), + ] + + with m.If(port_from.flush): + m.d.comb += rdata_converter.source.ready.eq(1) + with m.Elif(cmd_buffer.source.valid): + with m.If(rdata_chunk_valid): + m.d.comb += [ port_from.rdata.valid.eq(rdata_converter.source.valid), port_from.rdata.data.eq(rdata_converter.source.data), - rdata_converter.source.ready.eq(port_from.rdata.ready) - ).Else( - rdata_converter.source.ready.eq(1) - ) - ), - cmd_buffer.source.ready.eq( - rdata_converter.source.ready & rdata_chunk[ratio-1]) - ] + rdata_converter.source.ready.eq(port_from.rdata.ready), + ] + with m.Else(): + m.d.comb += rdata_converter.source.ready.eq(1) + + return m # LiteDRAMNativePortConverter ---------------------------------------------------------------------- -class LiteDRAMNativePortConverter(Module): +class LiteDRAMNativePortConverter(Elaboratable): def __init__(self, port_from, port_to, reverse=False): assert port_from.clock_domain == port_to.clock_domain assert port_from.mode == port_to.mode - # # # + self._port_from = port_from + self._port_to = port_to + self._reverse = reverse + + def elaborate(self, platform): + m = Module() + + port_from = self._port_from + port_to = self._port_to + reverse = self._reverse mode = port_from.mode if port_from.data_width > port_to.data_width: - converter = LiteDRAMNativePortDownConverter(port_from, port_to, reverse) - self.submodules += converter + converter = gramNativePortDownConverter(port_from, port_to, reverse) + m.submodules += converter elif port_from.data_width < port_to.data_width: if mode == "write": - converter = LiteDRAMNativeWritePortUpConverter(port_from, port_to, reverse) + converter = gramNativeWritePortUpConverter(port_from, port_to, reverse) elif mode == "read": - converter = LiteDRAMNativeReadPortUpConverter(port_from, port_to, reverse) + converter = gramNativeReadPortUpConverter(port_from, port_to, reverse) else: raise NotImplementedError - self.submodules += converter + m.submodules += converter else: - self.comb += [ + m.d.comb += [ port_from.cmd.connect(port_to.cmd), port_from.wdata.connect(port_to.wdata), port_to.rdata.connect(port_from.rdata) ] + + return m diff --git a/gram/phy/__init__.py b/gram/phy/__init__.py index e541bc9..0aa4e6a 100644 --- a/gram/phy/__init__.py +++ b/gram/phy/__init__.py @@ -1,11 +1 @@ -from litedram.phy.gensdrphy import GENSDRPHY - -from litedram.phy.s6ddrphy import S6HalfRateDDRPHY, S6QuarterRateDDRPHY -from litedram.phy.s7ddrphy import V7DDRPHY, K7DDRPHY, A7DDRPHY -from litedram.phy.usddrphy import USDDRPHY, USPDDRPHY - -from litedram.phy.ecp5ddrphy import ECP5DDRPHY, ECP5DDRPHYInit - -# backward compatibility (remove when no longer needed) -from litedram.phy import s7ddrphy as a7ddrphy -from litedram.phy import s7ddrphy as k7ddrphy +from gram.phy.ecp5ddrphy import ECP5DDRPHY, ECP5DDRPHYInit diff --git a/gram/phy/model.py b/gram/phy/model.py index 1bfd13c..4a63a2c 100644 --- a/gram/phy/model.py +++ b/gram/phy/model.py @@ -6,11 +6,11 @@ # TODO: # - add multirank support. -from migen import * +from nmigen import * -from litedram.common import burst_lengths -from litedram.phy.dfi import * -from litedram.modules import _speedgrade_timings, _technology_timings +from gram.common import burst_lengths +from gram.phy.dfi import * +from gram.modules import _speedgrade_timings, _technology_timings from functools import reduce from operator import or_ diff --git a/gram/stream.py b/gram/stream.py index 921cb55..725a153 100644 --- a/gram/stream.py +++ b/gram/stream.py @@ -126,7 +126,7 @@ class PipeValid(Elaboratable): self.source.first.eq(self.sink.first), self.source.last.eq(self.sink.last), self.source.payload.eq(self.sink.payload), - self.source.param.eq(self.sink.param), + #self.source.param.eq(self.sink.param), # TODO ensure this can be commented ] m.d.comb += self.sink.ready.eq(~self.source.valid | self.source.ready) diff --git a/test/__init__.py b/test/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/test/access_pattern.csv b/test/access_pattern.csv deleted file mode 100644 index 12ace39..0000000 --- a/test/access_pattern.csv +++ /dev/null @@ -1,1024 +0,0 @@ -0x0000012e,0x61d2c8d5 -0x000000d9,0x8ec8f8f6 -0x00000135,0xf9f6145f -0x0000033c,0xe653e338 -0x000002ff,0xbb609ae9 -0x0000037a,0xb42e5587 -0x00000228,0xce227592 -0x00000317,0xbd257969 -0x0000036e,0x7fe31c88 -0x0000011f,0xda6ba38d -0x000002c7,0x141f40ad -0x000000ab,0xa7c88a54 -0x000003f1,0xa48ddec4 -0x00000123,0xd800a7fe -0x00000098,0x45a96b1d -0x0000003b,0x4a75a15d -0x0000004f,0x90e04e1a -0x00000361,0x9af6660b -0x000000fc,0xa4830b72 -0x00000033,0xb063ccb3 -0x000000c1,0xf60e53ac -0x000002d2,0x47d9b283 -0x0000013f,0xe19843f7 -0x0000031d,0x30920818 -0x000001c3,0x2a830514 -0x000002c6,0xee6a0e7e -0x00000104,0x6ab2c91c -0x00000100,0x2dc79361 -0x000001e7,0xe9bf7c25 -0x00000149,0x29adfad6 -0x00000109,0x4f6c5d4a -0x00000285,0x9ec316ff -0x000001c4,0xf7768be4 -0x00000082,0x7478d35c -0x000001a9,0x1832672d -0x000001e5,0x12449eee -0x000002f3,0x90a205e0 -0x00000217,0x266d0830 -0x0000039a,0xe6a207ac -0x00000265,0x8fd00e38 -0x0000005e,0xc71ce3cc -0x00000116,0x03808ba0 -0x0000025d,0x9db362a9 -0x000002d8,0x04ab3a95 -0x0000018b,0xd8ccace2 -0x0000007d,0x9443ab73 -0x00000187,0x7933b972 -0x0000015e,0xcf6daccc -0x000002bc,0xbb9aa01c -0x00000274,0x790bce70 -0x00000227,0xa2e56a6d -0x0000002a,0xf2a9f0c7 -0x00000173,0x0cd5e422 -0x00000164,0x96c0513f -0x000001fb,0x5d766d17 -0x000001a0,0x55ea28bb -0x000002bd,0x38d65dfa -0x00000142,0x7212fb34 -0x000000b5,0x3b5fa506 -0x00000354,0x6a89900a -0x000001ac,0x2ce6be3f -0x00000342,0xb956396b -0x00000281,0x118b84ad -0x00000300,0x6e091a3c -0x0000029f,0x854141b2 -0x000000c6,0x3aafa04b -0x00000107,0x907c2cb4 -0x0000000a,0xc965666f -0x0000024c,0x2792b3a0 -0x00000203,0x1d19c1e1 -0x00000332,0x9f8ff8ce -0x00000092,0x86c77fe4 -0x00000101,0x5d59d5f3 -0x00000025,0x5dedd914 -0x00000258,0x9c886d9e -0x00000243,0x90a6e12a -0x00000247,0x75f3803e -0x000001ad,0x68843b6d -0x00000071,0x63b4de04 -0x0000026e,0x622eab11 -0x0000034b,0xb42696c1 -0x00000195,0x7685880a -0x000002ce,0x008d2d65 -0x000001c5,0xc064168f -0x00000019,0xf93530a6 -0x000001b3,0xec1b06db -0x000002f9,0x7ce508d3 -0x00000078,0xae78c8eb -0x00000134,0x64c63926 -0x00000255,0xd3646539 -0x00000010,0xa158c47d -0x000000f1,0xf18d4c56 -0x0000001d,0x3a693620 -0x000000e5,0x76b47c71 -0x0000001e,0xa741d479 -0x0000017f,0x84f156b2 -0x000000cb,0x8cc414d8 -0x000001a4,0xcd6cd47f -0x000003e4,0x37307894 -0x000001a1,0x041c0b6e -0x00000236,0x67741810 -0x000000b1,0x573222c0 -0x00000248,0x68e8f7f4 -0x00000316,0x16265757 -0x000001ed,0x85df14f1 -0x0000028e,0x54ec8e2f -0x000002c8,0xfae5e756 -0x000003a4,0x2cd32729 -0x0000035b,0x8ce13b5a -0x0000022d,0x943ce80f -0x00000345,0x278ff629 -0x0000008d,0x94a9c2ec -0x00000111,0xba4e5642 -0x00000011,0x22b3909c -0x000000f7,0x55338938 -0x00000186,0x9218fd6c -0x000000e0,0x3c48a497 -0x0000033a,0xda233663 -0x00000048,0x58855816 -0x0000029d,0x4df9feb1 -0x00000382,0x9f0f2502 -0x00000132,0xddaed3fe -0x000001a7,0xfde6bdba -0x00000128,0x448fce9a -0x0000037e,0x42aaaa1e -0x000001a8,0x4ea6f4df -0x000000ec,0x912aeb2c -0x00000056,0xde7d8aeb -0x000003e6,0x15f855a1 -0x0000001c,0xe0225e1e -0x00000080,0x3686bfb7 -0x000000da,0x7724b050 -0x000001b2,0xfec50f9a -0x000003c8,0x68d72fa8 -0x00000225,0x65df6eb6 -0x00000049,0x5b181430 -0x0000027e,0x35ec0cd3 -0x00000348,0xc1f5138a -0x0000036a,0x47b36f4d -0x00000178,0x073f863c -0x000001fc,0xf6ccbf5f -0x000003b3,0x3729f5ba -0x00000356,0x7f6d4988 -0x00000378,0x31d541ce -0x000001bf,0xe26033b2 -0x000002f4,0x4d009701 -0x0000012a,0x383e7b20 -0x000002f6,0x4ecb429b -0x000002ea,0xac934081 -0x000001d7,0xdf607028 -0x0000005b,0x3d48a4d7 -0x000000dc,0x9b2eed8e -0x00000089,0xe8170872 -0x0000007c,0x64439e56 -0x0000000e,0x3bb95a3c -0x00000239,0x36e6a900 -0x000001d8,0xc4c42852 -0x0000002d,0xa3a1a282 -0x0000000f,0x4f3c81e2 -0x000002c2,0x5d291767 -0x000002fb,0x2e48dcfa -0x00000119,0xc07a0c3c -0x000002e8,0x1cce5cbd -0x00000333,0x3a3a7e63 -0x00000110,0x4b501b3a -0x000001af,0xb1287fe3 -0x000001db,0xee4a7258 -0x0000018c,0xe9276e99 -0x0000013c,0x5bf99b5f -0x0000010b,0x2b1a09ff -0x0000031b,0xd9f78b82 -0x000003d9,0x505c7a02 -0x0000000d,0x9c568cbf -0x00000330,0x6f043b79 -0x000001f1,0x994dda6a -0x0000000b,0xd09629fa -0x00000136,0x41991be6 -0x0000004d,0x5e6a2d20 -0x00000198,0x0e0474d7 -0x000000ac,0x951f892d -0x00000022,0xc9ec5c7c -0x0000000c,0x95301582 -0x000002ef,0x08da98c7 -0x000003fb,0x43b4fd33 -0x000001eb,0x9e9b01ba -0x000000a3,0x325f8442 -0x00000209,0x74878d2f -0x00000159,0x4f1ec90f -0x00000172,0x6089924d -0x0000021a,0xaedaaeb8 -0x0000029a,0x7107bf13 -0x000001e1,0x584d3369 -0x00000106,0x75579cb1 -0x00000148,0x34bb1175 -0x00000398,0xb5d2e270 -0x000001ff,0x5a4cd7c1 -0x000003df,0x5ab6637c -0x0000032f,0xa588b2ab -0x0000033d,0x893d9f9c -0x00000183,0x6c833e74 -0x0000019d,0x9584ba23 -0x000000d4,0x7499251f -0x00000384,0x38c04aee -0x000002d7,0x2f780083 -0x0000003c,0x25ea371f -0x0000014d,0xa422c342 -0x000000a5,0xbb8ca7b1 -0x000000b4,0x600bfbb7 -0x000003a2,0x7536026b -0x0000019f,0xf3056983 -0x000003b5,0x14819baa -0x0000025b,0x22bfc5b4 -0x000001f4,0xf3dcc407 -0x000003d4,0xdd204ebc -0x000000e8,0x19371324 -0x0000031a,0x388f82b1 -0x000000b8,0xaa3c9d73 -0x00000370,0xdf89cab0 -0x00000251,0x149453d0 -0x00000177,0x060e6abb -0x000001d3,0x64c800bf -0x000002e0,0x197fe27c -0x000001bc,0x112c0c05 -0x00000339,0x5c1d0545 -0x0000011d,0xa9cb28e3 -0x00000020,0x9d16cec1 -0x0000037b,0xf46e9e3d -0x00000182,0x99e052fd -0x00000389,0xbd93a71e -0x000002b4,0x4bdf2842 -0x000002fc,0xa93be104 -0x00000192,0x1fd37c83 -0x0000020e,0x542b2943 -0x00000001,0x6a1469d3 -0x00000146,0xbfca75e9 -0x0000010e,0x8e00b2ee -0x00000141,0x4a5c4324 -0x00000023,0x7cfd7c93 -0x00000235,0xce9539ab -0x000002a0,0xe31e7f99 -0x00000231,0xbb3e3d23 -0x00000214,0x6eaa5dfc -0x00000319,0x9f719f0d -0x00000175,0x5ae51df8 -0x000002b0,0xa993d4c0 -0x000002da,0x9bb2a247 -0x00000053,0xd8d2dec4 -0x000003e0,0xaae00f7b -0x00000309,0x3f866f74 -0x00000276,0x4cf2e344 -0x00000055,0x4ba9a459 -0x00000216,0xee2ceffb -0x00000139,0xc9e720fb -0x00000338,0xc6204e59 -0x00000271,0xc98ed7f6 -0x000002a4,0xfd31d029 -0x00000286,0xdbcc04cb -0x0000037f,0x19bfb426 -0x00000064,0x0def53ae -0x00000335,0xbd34fdea -0x00000205,0x331768f4 -0x0000035c,0xa0e11fea -0x00000375,0x43bd9bcf -0x00000246,0xf1f27dd0 -0x00000018,0x3a703637 -0x00000388,0x4ca11d1c -0x00000169,0x7a808c4a -0x00000143,0xde360dec -0x00000088,0xf788f2f8 -0x000002c3,0x20fc77bb -0x0000018a,0x171ffa1c -0x000003bd,0xc1285057 -0x0000032b,0x47a437ab -0x000003ce,0xab34d83e -0x00000066,0x9c21cc65 -0x00000163,0x16b89209 -0x000001a5,0x39ed216e -0x000000d7,0x24e89199 -0x00000125,0xcd425b63 -0x000002e7,0xa3d10901 -0x00000219,0x16d97533 -0x00000363,0xceb7cdc8 -0x000002c9,0xb7ca8bb3 -0x000002a1,0xc9a18b20 -0x00000027,0xaf3a93d3 -0x00000343,0x724cf43c -0x0000016d,0x709cdc2b -0x000003fa,0x0bb57a27 -0x000003d0,0x50ebce7d -0x000003b4,0xcca0fcbd -0x000001d2,0xd47c15f9 -0x00000171,0x23e44721 -0x0000014b,0xfa40a59c -0x000002bf,0x2669def1 -0x000003de,0x029d6b69 -0x00000390,0xd6467cb3 -0x00000013,0x2fa1f2fe -0x00000329,0x39b5b021 -0x00000391,0x7155d9e6 -0x000000a4,0xe65f6a8b -0x0000010d,0xeb081ac3 -0x000001d9,0xc3333042 -0x0000001a,0xa7b3a7a1 -0x0000005c,0x15cc2a0b -0x000001df,0x58349e33 -0x00000081,0xbce62295 -0x00000129,0x4d34e0a5 -0x0000037d,0xae0fb82d -0x0000033f,0xbab64099 -0x000000ae,0x19cf9f0c -0x00000085,0xf65025dc -0x0000030d,0x156184eb -0x000000f3,0xd44874cb -0x000003c4,0x234a08dc -0x00000073,0x89be0b06 -0x0000008c,0x9c2f3f36 -0x0000006a,0x6dbd974e -0x000003ae,0xb1c0fac8 -0x0000036c,0x0158019e -0x0000003f,0x60d2350b -0x000000c3,0xe0bf851a -0x0000005d,0x57f4331e -0x00000160,0x2d01f727 -0x00000074,0xe7420f16 -0x0000001b,0x65193a81 -0x000003b6,0x5404408b -0x000000fe,0x4a912205 -0x0000020f,0xaf1ec7e3 -0x000003f2,0x65284d10 -0x00000038,0xc38902f9 -0x0000006b,0x93f02e10 -0x00000029,0xb73538b1 -0x000002ab,0x3832c214 -0x000001f3,0x7f04e0fe -0x000002e2,0x863662da -0x0000010f,0x6a7b7b52 -0x00000360,0x313fa92d -0x000002e1,0x29574441 -0x00000133,0x8503d7a1 -0x00000072,0xdf037127 -0x00000318,0x1f0a5242 -0x00000154,0x5d171f74 -0x00000197,0xa236ca17 -0x000000c5,0x344b386f -0x0000023b,0xbbfca537 -0x000002dc,0x8ecdbd48 -0x000000d3,0x68417535 -0x000002c4,0xa87d737e -0x00000302,0x5b4ac57d -0x000003b1,0x7208c47a -0x00000264,0xe967870e -0x00000230,0x6b8a64a4 -0x000001c0,0xa90e1999 -0x000000d0,0xfe6134c9 -0x000000e4,0x0d1e3e4f -0x000003ed,0x2765a290 -0x0000038a,0xadefbc7a -0x00000290,0x2253d279 -0x000001da,0xef8c14da -0x00000204,0xfa11139c -0x00000024,0x51773a21 -0x0000022c,0x82e40079 -0x000003e1,0x0d25dc31 -0x000002fa,0xae982f52 -0x000000aa,0xbdf45ea4 -0x0000026f,0x4441d881 -0x00000362,0x9129843f -0x000000d8,0x34175578 -0x000001f6,0x01663b92 -0x000003cc,0x341926d0 -0x00000352,0x4dc5fcc0 -0x00000036,0x1566a8eb -0x00000273,0xfdc7e15c -0x000000af,0xbaed2374 -0x00000041,0x1a0b8317 -0x000001dd,0xd18f699a -0x000000a8,0x90cb209a -0x00000257,0xbf67c32e -0x0000003d,0x0cbb59c4 -0x00000093,0xfe60eac3 -0x00000336,0xcf5be5dc -0x00000084,0x660900fc -0x00000320,0xaf5e2207 -0x0000032e,0x397069f3 -0x000001b7,0x9ed88604 -0x0000005a,0xd9e0f4a5 -0x000001cb,0xf2081a29 -0x00000270,0xe42a12a4 -0x0000027b,0x48fb577a -0x000003c3,0x239ff442 -0x0000015f,0xcef290ee -0x0000002b,0xe894ca29 -0x000002e6,0x00605a5d -0x000003d8,0x8a3309b1 -0x000003ba,0x715efaae -0x00000113,0xa0d1f6a8 -0x000001e8,0x744fd2ca -0x00000065,0x326f3881 -0x00000305,0xf508ccfc -0x00000215,0x594d1b47 -0x000002d4,0x89b4ec73 -0x000001a2,0xf12e7ff3 -0x000003ab,0x270a33a1 -0x000002d9,0x95c40cc3 -0x000001f0,0xadb2d1e6 -0x00000334,0x1f8b03c2 -0x00000359,0x0c8c22df -0x00000016,0xfdef90f8 -0x00000321,0x6d16c2b6 -0x0000012d,0x4a4a85aa -0x00000112,0x1b9612a0 -0x000000c2,0x11b7b67a -0x000003a8,0x0d2ddd6b -0x0000028c,0x9bac58e1 -0x0000001f,0x38060223 -0x00000299,0xa69b4430 -0x0000034e,0x92075ea3 -0x00000068,0x24693370 -0x00000091,0xe20db412 -0x0000029e,0x78539957 -0x00000385,0x7a646c06 -0x0000002c,0xd00f800a -0x00000188,0x0846d6bc -0x000001e0,0x1702b043 -0x000002cb,0x1f438aea -0x0000005f,0xa43309be -0x00000147,0x1609f9c1 -0x000002f7,0x7b851f8e -0x000002dd,0x6bf738a3 -0x000000ca,0x1a50ad66 -0x000001e9,0x37a9593f -0x0000006f,0x6de45853 -0x0000015c,0xeb6cb24e -0x00000030,0xce267ad7 -0x0000002e,0x4ec1453b -0x000001d1,0xfc14bec4 -0x00000017,0x876d7392 -0x000002f8,0x9ac12c44 -0x000000f6,0xf524d27d -0x0000035d,0x30a11607 -0x00000394,0xd3b26a18 -0x00000355,0xee8a455a -0x00000261,0x98c20113 -0x000000d5,0x37fbdd7f -0x00000325,0x85269178 -0x0000011e,0xf74a97ad -0x0000028d,0xb144ba63 -0x000000ef,0xec40f103 -0x000002be,0xda839587 -0x00000061,0xe116a87a -0x000002ae,0xb615d223 -0x000001ab,0x81c40cec -0x000000cd,0xe644b747 -0x0000006e,0x82bd6a8c -0x00000000,0xf000849b -0x0000032d,0xb22bc4c2 -0x00000368,0x7510c7f3 -0x00000067,0xe616e21e -0x00000358,0xb2b4e853 -0x000002a3,0x1a809df7 -0x000000a0,0xbd9649c3 -0x000003d2,0x93cb8b68 -0x00000046,0xf4aa0c1b -0x0000026a,0xb84137a0 -0x000000f4,0x5519ed9c -0x0000025e,0x27785441 -0x000000e2,0xf7c05a5c -0x00000346,0x99448f63 -0x0000008b,0xf7808cc8 -0x0000036b,0xa20fdf9e -0x000000bc,0x0d624554 -0x0000017b,0x328aa94c -0x0000023f,0xab882098 -0x0000033b,0xcb5d14ad -0x00000114,0x62fca8d3 -0x000003fc,0x80a34a21 -0x000001bd,0x2027292c -0x00000328,0x6b1ed1f1 -0x000000b6,0x3cd89d38 -0x0000027c,0xf3f04d4e -0x000003d5,0x482e2cce -0x00000054,0x5d084c63 -0x000002df,0x9694542a -0x000003b8,0x823d6559 -0x00000289,0xc3adcb32 -0x0000035f,0x88e8e6db -0x0000024f,0xc288d6fb -0x000001cc,0xf5a0c23e -0x0000015a,0x04c6ac85 -0x000000e6,0xa2c708a6 -0x000000cc,0x214ae76e -0x0000039e,0x75bf1bc8 -0x000003c9,0x3191a7eb -0x000000e9,0xec7d07db -0x00000060,0xe0710b88 -0x000002a7,0x73d0cd4e -0x000003db,0x1e017f85 -0x000000a2,0x489b1f6c -0x00000076,0x60529d31 -0x0000004b,0x93b6355e -0x00000063,0xe9691ee0 -0x000001ea,0xf1d3e628 -0x000000a6,0x3eaf45d5 -0x0000034a,0x079bc1db -0x00000003,0x2b83ee22 -0x000003cb,0xb38d5007 -0x00000315,0x005c5340 -0x000003f9,0xf61bec1d -0x000003fe,0x459a3987 -0x000001b4,0x955aa611 -0x000000c9,0x0b8502a7 -0x0000025c,0x919b4b7f -0x00000323,0x4e0b307c -0x0000039c,0x25e20b80 -0x00000035,0x15d35def -0x00000155,0xed7988b9 -0x0000007a,0x0d259437 -0x0000031c,0xc448416c -0x00000379,0x588b1ea1 -0x000000ee,0xda9033f2 -0x0000017c,0x5d8510dd -0x0000017d,0x7a845fad -0x0000009d,0x285e125f -0x000003ac,0xc3a8f4f8 -0x00000044,0x562f95f9 -0x000001c2,0xcbcbfc47 -0x000001f8,0x8bb3c481 -0x000002f1,0x5eb9554d -0x0000007e,0x3cd4d757 -0x000003c2,0xf24687c9 -0x00000208,0x22fe40f5 -0x000001c6,0xbd394a93 -0x00000207,0x9f8abb23 -0x0000003e,0x3b084161 -0x00000310,0x5dd566f4 -0x0000038e,0x93cfc737 -0x0000015d,0x248175bd -0x0000009c,0x06a757d2 -0x00000220,0x6298f764 -0x000001cd,0xb7493bd3 -0x00000340,0xcab3638c -0x0000016a,0xba6f41df -0x000000de,0xb583bd95 -0x000000b3,0x55ee3276 -0x00000105,0xe60a6ea0 -0x00000292,0xfa17da23 -0x000001c7,0xc02731ee -0x0000039b,0x314a1f3f -0x00000324,0xaa0e0330 -0x000003ef,0x5606084c -0x000000bb,0x3f139afc -0x0000027d,0x04af2287 -0x0000025f,0x1ddf8f9e -0x00000242,0x0f8a411a -0x000003c1,0xc6518d07 -0x00000303,0x465f710f -0x0000002f,0xed4d052e -0x0000024b,0x1343c957 -0x00000393,0x5c0a5fe4 -0x000002c5,0x0465e58d -0x0000009e,0x2c09e0a8 -0x00000008,0x853a3b86 -0x0000009f,0x0bb6972d -0x000002d3,0x961b173f -0x000000f0,0x9756f025 -0x00000245,0x5d446cad -0x000001b9,0xdd7862a5 -0x000002b5,0xc2d1e49b -0x00000090,0x5dcb1a93 -0x0000019b,0x17c5f622 -0x0000007f,0x2048e019 -0x000000bf,0xe575efda -0x00000050,0x29f4ff94 -0x00000326,0x5af3c8fa -0x0000019e,0xae8ad590 -0x000002ad,0x4325de4c -0x0000030c,0xd00530a4 -0x000002cc,0xf3f7fcf7 -0x0000032c,0xbc35a67f -0x0000016c,0x2ad3a928 -0x000000f8,0x4ddf8b47 -0x0000004c,0x349d1982 -0x0000039f,0x8e06d477 -0x000003ee,0x67e0cbc5 -0x0000021b,0xbbbd1879 -0x0000004a,0x2c55a027 -0x000002a2,0x2634f218 -0x000003cf,0x3d73d279 -0x000000eb,0x6e78b973 -0x0000021e,0xdd01d278 -0x00000127,0xd6fd8840 -0x00000059,0xadb7fd4a -0x000002ec,0x3ced1d8a -0x0000038f,0x1dad4ff2 -0x000002b3,0xa7b024d8 -0x000002d6,0xead8cd71 -0x00000184,0x1ee19ab9 -0x00000120,0xa362afd8 -0x00000260,0xb2d1429d -0x00000005,0x6aa3df1a -0x00000308,0x1ebb5208 -0x000000ff,0xa9df5014 -0x00000087,0x32938571 -0x00000126,0x59d446f1 -0x00000293,0xde9d5490 -0x0000029c,0xa779710c -0x000002a9,0x62c7737d -0x000003bc,0xa800328e -0x000002ca,0xd5b99fa7 -0x00000249,0x06ec5c2f -0x000003ff,0x588a9bdc -0x00000371,0x33386477 -0x000000c4,0x2feeb727 -0x000000fd,0xe950d114 -0x0000033e,0xcccfdb62 -0x000003af,0x9cbb4ec8 -0x00000045,0x4e91087f -0x000000ea,0xfa9c9aac -0x000000be,0x6af216ea -0x0000010c,0x632ae74f -0x000001e2,0xb101bded -0x0000020a,0x7a41e224 -0x00000238,0x4c4b3a6e -0x00000158,0xb7328634 -0x000001be,0xe102181b -0x000003a9,0x5c529dd4 -0x000003a7,0xec370158 -0x00000108,0x889d6ebe -0x0000025a,0x95906629 -0x00000350,0xcf1cd4e7 -0x000001f5,0x7c295b29 -0x000003bb,0xeae747ee -0x00000349,0x82ae2057 -0x000003b9,0x7a249f88 -0x000001b0,0x2563614b -0x00000174,0x325549b4 -0x000000e3,0x6e51ae06 -0x00000006,0xb845331b -0x000003b0,0xbf77e74d -0x00000322,0x444d330a -0x00000191,0x83d91767 -0x000000ad,0x477af9ba -0x0000021f,0xc071f857 -0x0000008f,0x3e8a5d1a -0x0000029b,0x9b0431fd -0x000002a8,0xcebb2ae6 -0x00000165,0x1a2c3cd4 -0x00000157,0x1629e3fe -0x000003d1,0x9dc7627c -0x00000121,0xe1ff1567 -0x0000007b,0x51610f6c -0x000000d1,0x7d5918b4 -0x000002b8,0x74025419 -0x00000395,0x6001080f -0x000000b7,0xbdfa2c1a -0x000001b1,0xe0b9b238 -0x0000038d,0xae0f8b86 -0x00000291,0x7d585c4d -0x0000018f,0x7381b5ac -0x000002ba,0xc3081096 -0x000000ce,0x7f15786e -0x0000022e,0x424bc3fc -0x0000006c,0xee2cc7a7 -0x000001a6,0xb3b219a0 -0x0000034d,0x9a9e73fe -0x00000118,0x63d7a149 -0x0000026d,0x1d6d3ea4 -0x00000162,0x44b271c9 -0x00000241,0xd6da9f44 -0x0000030b,0x3f8a78d2 -0x000001ba,0xd2c0fe52 -0x000000bd,0x723c8910 -0x00000234,0xbf48bec5 -0x000001b8,0xa7874edb -0x00000226,0xdd6aa284 -0x00000144,0xe7d2458c -0x00000012,0xd6d8c04a -0x0000017a,0xf6ae9915 -0x00000014,0xb00b0422 -0x000002f0,0x88041d25 -0x00000069,0x61278220 -0x0000030f,0xf2c3811d -0x00000037,0x9d861d63 -0x000002d5,0x6c37dd6c -0x000000c7,0xc80f3a17 -0x000001d4,0xdf893fdc -0x000002ed,0xc5ec640d -0x000002d1,0xa1bdec12 -0x000001ee,0x4e254439 -0x00000311,0x178b04fc -0x0000019a,0x8da6f6b4 -0x000003e8,0x82797f9b -0x00000152,0x9b9c0438 -0x0000014c,0x909b71e7 -0x000002b9,0x57eefc02 -0x00000279,0x21f30dd9 -0x0000013b,0x282ecf47 -0x0000012b,0xb8240d6c -0x00000272,0x56ce2bbb -0x00000040,0xba39ad57 -0x0000026c,0x35592672 -0x000003e3,0x4eb09c06 -0x000003f3,0x341149c8 -0x000001e3,0xe89b8254 -0x000002c0,0x2dd5663b -0x0000009a,0x9e6c6b56 -0x00000021,0x12fd7034 -0x00000387,0xa027ea96 -0x000001ce,0x8af8e5c7 -0x000003f0,0x4d341384 -0x00000267,0xd2f19763 -0x0000018d,0x765671c5 -0x000000a1,0xaf382a64 -0x00000221,0x7fd9a647 -0x000002fe,0x7d1b99ca -0x00000277,0x4db2b052 -0x000003dc,0xd5a05d52 -0x00000058,0x4ccbf2d4 -0x000000c0,0x33761998 -0x00000254,0xa34acbad -0x000001d5,0xe2064af6 -0x0000021d,0x33c319ae -0x00000083,0x8af6070c -0x00000062,0x2c5c3595 -0x000001b5,0x53c1a11a -0x00000365,0xb7641db3 -0x000000fa,0x8f168750 -0x000003d7,0x62700567 -0x0000035e,0x30cf6a3c -0x00000297,0xaece2cae -0x0000030e,0x4a431c09 -0x000001f2,0xb088d216 -0x0000023a,0x96ce06c1 -0x00000176,0x8a9abb34 -0x00000115,0x311a4837 -0x0000031e,0x5e85164b -0x00000047,0x00a0eeb5 -0x000001a3,0xf84eca18 -0x000000f2,0x2cbee27a -0x0000014e,0x2f191aee -0x000000b9,0x3b12a538 -0x0000026b,0x472f6ac7 -0x00000233,0xa4337bf2 -0x00000052,0xf6959222 -0x000002b7,0xfe1c9ccf -0x0000024a,0x4e6efdf3 -0x00000218,0x5496f22a -0x0000024d,0xcfdaf597 -0x00000009,0x17453936 -0x0000032a,0x8c570977 -0x00000313,0xa5a96add -0x00000179,0xfb73e3f9 -0x00000180,0x31c27b51 -0x000002fd,0x2d15a0cd -0x0000012f,0xc475fc25 -0x000002a5,0xdf36df3c -0x000003be,0xbccd34d7 -0x00000140,0x3f11ac6c -0x000002af,0x4f8f60de -0x00000200,0x6b3ed957 -0x00000372,0x3134dec0 -0x000002bb,0x4677e498 -0x000000a9,0xc657ff78 -0x00000351,0xdaa8f98a -0x00000170,0x865000f4 -0x000001c1,0x0daad104 -0x000003f6,0x54381f7c -0x00000282,0xae0de4fd -0x0000039d,0x930925cc -0x0000020b,0xc04f5b79 -0x00000007,0xe60b3af3 -0x0000027f,0xcb230d4d -0x0000034f,0x6e94cf18 -0x00000026,0x979b5acb -0x000002b2,0xd69292e1 -0x00000137,0x298e7abb -0x000001dc,0xaab2730d -0x0000020d,0x50b57ca0 -0x00000298,0x5f9276c5 -0x0000022a,0x63391f81 -0x00000314,0x00f61207 -0x0000030a,0x1d94bc11 -0x0000017e,0xece45f2a -0x00000196,0x3376ea4f -0x00000212,0x394c781e -0x0000015b,0xaa45c8e4 -0x00000262,0xee189cde -0x000000b2,0x0cf81cad -0x000003e5,0x6a469268 -0x00000122,0x0fe0bf0f -0x000003ca,0x299b8fa4 -0x0000035a,0x18a3db69 -0x00000266,0x0387ddf8 -0x000001c8,0x76d2e831 -0x000001d0,0xd3132dbd -0x00000206,0xfa3a0f73 -0x00000373,0x837f807f -0x00000015,0x8f88a8ab -0x00000386,0x3c2ee566 -0x000003f7,0x56d51358 -0x00000223,0xe644ada5 -0x000002f5,0x8f20bddd -0x0000011b,0xa72467ed -0x000001ef,0x0eeb3073 -0x000000d2,0xfceccbcc -0x000002f2,0x722f9ca7 -0x000002ac,0x134a4fbb -0x00000301,0x3cc98027 -0x0000014f,0xfbec5bf5 -0x000003d3,0x628b4ab9 -0x000001f7,0xf8e6291c -0x000002d0,0x326e58d8 -0x000001ae,0x78256d64 -0x00000057,0x403e8c61 -0x0000008a,0x1d7338bc -0x0000013e,0x1e11634f -0x000002de,0xaf0f3eb1 -0x00000199,0xae5c4f27 -0x00000102,0xb0bac110 -0x000003c6,0x485052b8 -0x0000016e,0x5a38a789 -0x00000252,0x54542916 -0x00000002,0x39b180bd -0x00000250,0x230f1e18 -0x000002db,0x1da31dad -0x0000018e,0xbf914fb7 -0x000003c0,0x63f13c95 -0x00000369,0xbc276edd -0x00000288,0xf2e5c78c -0x00000211,0x8be09b81 -0x00000193,0xa9dd3901 -0x000003d6,0x564698ff -0x000000dd,0x654586cd -0x0000013d,0x17f8cdf8 -0x000003dd,0xf55532d7 -0x000000e1,0xd21d0301 -0x00000344,0x8e5c90b7 -0x00000347,0xce2ea106 -0x000002b6,0xe1456d48 -0x00000096,0x1690a90b -0x000002e4,0xbfcf1ee5 -0x00000284,0x9bbd41e7 -0x00000376,0x0a1b239d -0x00000194,0xb8c0425c -0x000001cf,0x5a5f67b8 -0x0000019c,0x8c1365bf -0x00000269,0x7ccc3095 -0x000001fe,0xeff19023 -0x00000028,0x4c6c96e1 -0x00000075,0x6031fafc -0x000000e7,0x6d066ff7 -0x00000213,0x83a12826 -0x000003a1,0xdff42be1 -0x000000d6,0x74721815 -0x00000094,0x5e9436ba -0x000003ec,0x0f91f2dd -0x00000167,0x2f5d9a5c -0x000001bb,0x41b606be -0x00000222,0x455c3f18 -0x0000038c,0x41938755 -0x00000034,0xf3e676b0 -0x00000031,0xb3b105f0 -0x00000043,0xaebbd49c -0x00000079,0x32e9f285 -0x00000130,0x90514309 -0x00000253,0xda947617 -0x000003c7,0x3a454ada -0x00000131,0x6d9bb5fa -0x00000278,0x5c094e3b -0x00000256,0x19969979 -0x00000357,0x8f966e1a -0x00000185,0xba65d2f8 -0x00000263,0x19417509 -0x000000db,0x1eaadeab -0x00000232,0xef46402c -0x00000240,0x215c8ec5 -0x000003b7,0x1d7489dd -0x00000086,0xa9d49edc -0x000000f5,0xb85554dc -0x00000099,0x5d964de7 -0x000003fd,0x6722db64 -0x00000312,0x829a6b53 -0x000001fd,0xf5abdab3 -0x000002c1,0xe5662f67 -0x000003c5,0x2a5f11dd -0x000002ee,0x69769d62 -0x000001d6,0x76155587 -0x0000016f,0xf474b542 -0x000003b2,0x0e03d080 -0x0000006d,0xcce03f59 -0x00000244,0xae332051 -0x00000366,0xa5d17a7b -0x0000022b,0x0bb8f348 -0x00000150,0xd9d81433 -0x000000f9,0x06f2b1ca -0x000000ed,0x10f3cbb5 -0x0000028a,0xb92f3a08 -0x0000038b,0x2e7839fc -0x0000036d,0x8a55891d -0x00000306,0x004434c7 -0x0000027a,0x2c2fe04e -0x0000010a,0x23317858 -0x000003cd,0xb2e47f17 -0x000003a0,0xed86f8e0 -0x0000013a,0xf295d26e -0x00000042,0xbd71be15 -0x0000016b,0xf52fcd29 -0x000003a3,0x80b123f1 -0x000003f4,0xc7b11df1 -0x000003ad,0x93a20006 -0x000003eb,0x52d781ac -0x000002b1,0x6a5e69a3 -0x0000011a,0x0f63315c -0x00000117,0x33659391 -0x00000051,0x1a05f763 -0x0000009b,0xde4ef3eb -0x00000161,0xcd7d1638 -0x000001ec,0xee053da6 -0x000001ca,0x42044d3f -0x000001de,0xcd1d0123 -0x0000028f,0x51f7b994 -0x000003bf,0x108f008e -0x00000032,0x1ec7d1cb -0x00000124,0xab39af81 -0x00000189,0x1678f062 -0x000002cd,0x510dc040 -0x00000331,0x4d33628a -0x00000229,0x944e008a -0x00000341,0x5a7a5372 -0x00000166,0xa92e5b7d -0x00000337,0x174610f0 -0x000002e3,0x38695e89 -0x0000023e,0x96675159 -0x000003da,0x64ab9558 -0x00000097,0x3f86cd0f -0x000000fb,0x107b81b4 -0x000002eb,0x7fd9a144 -0x00000039,0x30a2b470 -0x00000145,0x5f730f7d -0x0000011c,0x966cf066 -0x00000275,0x21d87efc -0x00000202,0xa470e81e -0x00000380,0x7f1c9cfe -0x000002a6,0x83ef8a4a -0x00000392,0x7f080fa5 -0x00000304,0x24a98eb9 -0x000003f8,0xd1a6e7cb -0x00000224,0xc8497258 -0x000003a6,0x6b304020 -0x00000201,0x30733eea -0x0000004e,0xe5996b9a -0x00000383,0x11421776 -0x000000cf,0x35b5d61d -0x00000367,0x630ff9ae -0x000001aa,0xbee7db59 -0x0000021c,0x341d6960 -0x00000283,0x89c0976d -0x00000070,0x599deb7b -0x000003a5,0xb79a547e -0x000003aa,0x990a9aeb -0x00000399,0xd867d08c -0x000001b6,0x9c822c9e -0x00000153,0x05f7124a -0x00000296,0x1014c48d -0x000002e5,0xc948f761 -0x00000190,0x74483f9b -0x00000077,0x805f10a1 -0x00000280,0xb6fdd0fe -0x000000c8,0xb7147ac4 -0x000003e9,0x39daa1ed -0x00000259,0xc3d82fe5 -0x000002e9,0x1781b102 -0x000002aa,0xfb0674fd -0x00000396,0xa2f79ac4 -0x00000353,0x796131a3 -0x00000294,0x3a4f253c -0x00000268,0x8819efeb -0x00000364,0xbbac1595 -0x000003f5,0x6468a5f3 -0x00000103,0xd39a7cf1 -0x00000004,0x2d311b72 -0x000002cf,0xbeda8a15 -0x0000031f,0x92221439 -0x00000374,0xb790d8a9 -0x0000020c,0x45db5760 -0x000003e2,0x6332d00f -0x0000028b,0xcfb7b189 -0x000001c9,0x6380385f -0x0000037c,0x443714c5 -0x00000397,0x3a84c720 -0x00000377,0x6cd3807c -0x000000a7,0xeed1718a -0x00000168,0xb2d6b00f -0x000000ba,0xd4143f6b -0x000001e6,0x70a5cba8 -0x0000003a,0x6db46c23 -0x00000138,0x8b1cbc57 -0x00000327,0x1417447b -0x0000023d,0xf824f9fe -0x000000b0,0xa4afe544 -0x0000024e,0xcdeefb90 -0x00000156,0x9116659d -0x00000095,0xbec1d9ff -0x000003ea,0x418440ad -0x000001e4,0x60b154d8 -0x00000381,0x05bee376 -0x0000023c,0x56313370 -0x000000df,0x2271ed24 -0x00000237,0x5e79fb1a -0x0000034c,0x00a28d23 -0x00000307,0x9a60280a -0x00000287,0x4aebb908 -0x0000036f,0x15b250b7 -0x000003e7,0xc03cd972 -0x0000022f,0x07b8b4f6 -0x00000295,0xba38ebb6 -0x00000210,0xba34a72a -0x000001f9,0x3f3d8c6d -0x000001fa,0xeec12a22 -0x00000151,0xcf258683 -0x0000012c,0x52c63dee -0x00000181,0x7a1b33cb -0x0000014a,0x87b6f8b2 -0x0000008e,0x18c0f3a6 diff --git a/test/benchmark.py b/test/benchmark.py deleted file mode 100755 index 2a71126..0000000 --- a/test/benchmark.py +++ /dev/null @@ -1,267 +0,0 @@ -#!/usr/bin/env python3 - -# This file is Copyright (c) 2020 Florent Kermarrec -# License: BSD - -import csv -import logging -import argparse -from operator import and_ -from functools import reduce -from itertools import zip_longest - -from migen import * -from migen.genlib.misc import WaitTimer - -from litex.build.sim.config import SimConfig - -from litex.soc.interconnect.csr import * -from litex.soc.integration.soc_sdram import * -from litex.soc.integration.builder import * - -from litex.tools.litex_sim import SimSoC - -from litedram.frontend.bist import _LiteDRAMBISTGenerator, _LiteDRAMBISTChecker -from litedram.frontend.bist import _LiteDRAMPatternGenerator, _LiteDRAMPatternChecker - -# LiteDRAM Benchmark SoC --------------------------------------------------------------------------- - -class LiteDRAMBenchmarkSoC(SimSoC): - def __init__(self, - mode = "bist", - sdram_module = "MT48LC16M16", - sdram_data_width = 32, - bist_base = 0x0000000, - bist_end = 0x0100000, - bist_length = 1024, - bist_random = False, - bist_alternating = False, - num_generators = 1, - num_checkers = 1, - access_pattern = None, - **kwargs): - assert mode in ["bist", "pattern"] - assert not (mode == "pattern" and access_pattern is None) - - # SimSoC ----------------------------------------------------------------------------------- - SimSoC.__init__(self, - with_sdram = True, - sdram_module = sdram_module, - sdram_data_width = sdram_data_width, - **kwargs - ) - - # BIST/Pattern Generator / Checker --------------------------------------------------------- - if mode == "pattern": - make_generator = lambda: _LiteDRAMPatternGenerator(self.sdram.crossbar.get_port(), init=access_pattern) - make_checker = lambda: _LiteDRAMPatternChecker(self.sdram.crossbar.get_port(), init=access_pattern) - if mode == "bist": - make_generator = lambda: _LiteDRAMBISTGenerator(self.sdram.crossbar.get_port()) - make_checker = lambda: _LiteDRAMBISTChecker(self.sdram.crossbar.get_port()) - - generators = [make_generator() for _ in range(num_generators)] - checkers = [make_checker() for _ in range(num_checkers)] - self.submodules += generators + checkers - - if mode == "pattern": - def bist_config(module): - return [] - - if not bist_alternating: - address_set = set() - for addr, _ in access_pattern: - assert addr not in address_set, \ - "Duplicate address 0x%08x in access_pattern, write will overwrite previous value!" % addr - address_set.add(addr) - if mode == "bist": - # Make sure that we perform at least one access - bist_length = max(bist_length, self.sdram.controller.interface.data_width // 8) - def bist_config(module): - return [ - module.base.eq(bist_base), - module.end.eq(bist_end), - module.length.eq(bist_length), - module.random_addr.eq(bist_random), - ] - - assert not (bist_random and not bist_alternating), \ - "Write to random address may overwrite previously written data before reading!" - - # Check address correctness - assert bist_end > bist_base - assert bist_end <= 2**(len(generators[0].end)) - 1, "End address outside of range" - bist_addr_range = bist_end - bist_base - assert bist_addr_range > 0 and bist_addr_range & (bist_addr_range - 1) == 0, \ - "Length of the address range must be a power of 2" - - def combined_read(modules, signal, operator): - sig = Signal() - self.comb += sig.eq(reduce(operator, (getattr(m, signal) for m in modules))) - return sig - - def combined_write(modules, signal): - sig = Signal() - self.comb += [getattr(m, signal).eq(sig) for m in modules] - return sig - - # Sequencer -------------------------------------------------------------------------------- - class LiteDRAMCoreControl(Module, AutoCSR): - def __init__(self): - self.init_done = CSRStorage() - self.init_error = CSRStorage() - self.submodules.ddrctrl = ddrctrl = LiteDRAMCoreControl() - self.add_csr("ddrctrl") - - display = Signal() - finish = Signal() - self.submodules.fsm = fsm = FSM(reset_state="WAIT-INIT") - fsm.act("WAIT-INIT", - If(self.ddrctrl.init_done.storage, # Written by CPU when initialization is done - NextState("BIST-GENERATOR") - ) - ) - if bist_alternating: - # Force generators to wait for checkers and vice versa. Connect them in pairs, with each - # unpaired connected to the first of the others. - bist_connections = [] - for generator, checker in zip_longest(generators, checkers): - g = generator or generators[0] - c = checker or checkers[0] - bist_connections += [ - g.run_cascade_in.eq(c.run_cascade_out), - c.run_cascade_in.eq(g.run_cascade_out), - ] - - fsm.act("BIST-GENERATOR", - combined_write(generators + checkers, "start").eq(1), - *bist_connections, - *map(bist_config, generators + checkers), - If(combined_read(checkers, "done", and_), - NextState("DISPLAY") - ) - ) - else: - fsm.act("BIST-GENERATOR", - combined_write(generators, "start").eq(1), - *map(bist_config, generators), - If(combined_read(generators, "done", and_), - NextState("BIST-CHECKER") - ) - ) - fsm.act("BIST-CHECKER", - combined_write(checkers, "start").eq(1), - *map(bist_config, checkers), - If(combined_read(checkers, "done", and_), - NextState("DISPLAY") - ) - ) - fsm.act("DISPLAY", - display.eq(1), - NextState("FINISH") - ) - fsm.act("FINISH", - finish.eq(1) - ) - - # Simulation Results ----------------------------------------------------------------------- - def max_signal(signals): - signals = iter(signals) - s = next(signals) - out = Signal(len(s)) - self.comb += out.eq(s) - for curr in signals: - prev = out - out = Signal(max(len(prev), len(curr))) - self.comb += If(prev > curr, out.eq(prev)).Else(out.eq(curr)) - return out - - generator_ticks = max_signal((g.ticks for g in generators)) - checker_errors = max_signal((c.errors for c in checkers)) - checker_ticks = max_signal((c.ticks for c in checkers)) - - self.sync += [ - If(display, - Display("BIST-GENERATOR ticks: %08d", generator_ticks), - Display("BIST-CHECKER errors: %08d", checker_errors), - Display("BIST-CHECKER ticks: %08d", checker_ticks), - ) - ] - - # Simulation End --------------------------------------------------------------------------- - end_timer = WaitTimer(2**16) - self.submodules += end_timer - self.comb += end_timer.wait.eq(finish) - self.sync += If(end_timer.done, Finish()) - -# Build -------------------------------------------------------------------------------------------- - -def load_access_pattern(filename): - with open(filename, newline="") as f: - reader = csv.reader(f) - access_pattern = [(int(addr, 0), int(data, 0)) for addr, data in reader] - return access_pattern - -def main(): - parser = argparse.ArgumentParser(description="LiteDRAM Benchmark SoC Simulation") - builder_args(parser) - soc_sdram_args(parser) - parser.add_argument("--threads", default=1, help="Set number of threads (default=1)") - parser.add_argument("--sdram-module", default="MT48LC16M16", help="Select SDRAM chip") - parser.add_argument("--sdram-data-width", default=32, help="Set SDRAM chip data width") - parser.add_argument("--sdram-verbosity", default=0, help="Set SDRAM checker verbosity") - parser.add_argument("--trace", action="store_true", help="Enable VCD tracing") - parser.add_argument("--trace-start", default=0, help="Cycle to start VCD tracing") - parser.add_argument("--trace-end", default=-1, help="Cycle to end VCD tracing") - parser.add_argument("--opt-level", default="O0", help="Compilation optimization level") - parser.add_argument("--bist-base", default="0x00000000", help="Base address of the test (default=0)") - parser.add_argument("--bist-length", default="1024", help="Length of the test (default=1024)") - parser.add_argument("--bist-random", action="store_true", help="Use random data during the test") - parser.add_argument("--bist-alternating", action="store_true", help="Perform alternating writes/reads (WRWRWR... instead of WWW...RRR...)") - parser.add_argument("--num-generators", default=1, help="Number of BIST generators") - parser.add_argument("--num-checkers", default=1, help="Number of BIST checkers") - parser.add_argument("--access-pattern", help="Load access pattern (address, data) from CSV (ignores --bist-*)") - parser.add_argument("--log-level", default="info", help="Set logging verbosity", - choices=["critical", "error", "warning", "info", "debug"]) - args = parser.parse_args() - - root_logger = logging.getLogger() - root_logger.setLevel(getattr(logging, args.log_level.upper())) - - soc_kwargs = soc_sdram_argdict(args) - builder_kwargs = builder_argdict(args) - - sim_config = SimConfig(default_clk="sys_clk") - sim_config.add_module("serial2console", "serial") - - # Configuration -------------------------------------------------------------------------------- - soc_kwargs["uart_name"] = "sim" - soc_kwargs["sdram_module"] = args.sdram_module - soc_kwargs["sdram_data_width"] = int(args.sdram_data_width) - soc_kwargs["sdram_verbosity"] = int(args.sdram_verbosity) - soc_kwargs["bist_base"] = int(args.bist_base, 0) - soc_kwargs["bist_length"] = int(args.bist_length, 0) - soc_kwargs["bist_random"] = args.bist_random - soc_kwargs["bist_alternating"] = args.bist_alternating - soc_kwargs["num_generators"] = int(args.num_generators) - soc_kwargs["num_checkers"] = int(args.num_checkers) - - if args.access_pattern: - soc_kwargs["access_pattern"] = load_access_pattern(args.access_pattern) - - # SoC ------------------------------------------------------------------------------------------ - soc = LiteDRAMBenchmarkSoC(mode="pattern" if args.access_pattern else "bist", **soc_kwargs) - - # Build/Run ------------------------------------------------------------------------------------ - builder_kwargs["csr_csv"] = "csr.csv" - builder = Builder(soc, **builder_kwargs) - vns = builder.build( - threads = args.threads, - sim_config = sim_config, - opt_level = args.opt_level, - trace = args.trace, - trace_start = int(args.trace_start), - trace_end = int(args.trace_end) - ) - -if __name__ == "__main__": - main() diff --git a/test/benchmarks.yml b/test/benchmarks.yml deleted file mode 100644 index a77421b..0000000 --- a/test/benchmarks.yml +++ /dev/null @@ -1,1047 +0,0 @@ -# ============================================================ -# Auto-generated on 2020-02-12 15:41:38 by ./gen_config.py -# ------------------------------------------------------------ -# {'name_format': 'test_%d', -# 'sdram_module': ['MT41K128M16', 'MT46V32M16', 'MT48LC16M16'], -# 'sdram_data_width': [32], -# 'bist_alternating': [True, False], -# 'bist_length': [1, 1024], -# 'bist_random': [True, False], -# 'num_generators': [1, 3], -# 'num_checkers': [1, 3], -# 'access_pattern': ['access_pattern.csv']} -# ============================================================ -{ - "test_0": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_1": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_2": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_3": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_4": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_5": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_6": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_7": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_8": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_9": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_10": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_11": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_12": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_13": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_14": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_15": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_16": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_17": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_18": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_19": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_20": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_21": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_22": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_23": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_24": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_25": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_26": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_27": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_28": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_29": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_30": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_31": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_32": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_33": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_34": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_35": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_36": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_37": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_38": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_39": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_40": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_41": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_42": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_43": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_44": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_45": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_46": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_47": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_48": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_49": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_50": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_51": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_52": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_53": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_54": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_55": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_56": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_57": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_58": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_59": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_60": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": true - } - }, - "test_61": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_62": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": true - } - }, - "test_63": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_64": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_65": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_66": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_67": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_68": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_69": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_70": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1, - "bist_random": false - } - }, - "test_71": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "bist_length": 1024, - "bist_random": false - } - }, - "test_72": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_73": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_74": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_75": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_76": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_77": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_78": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_79": { - "sdram_module": "MT41K128M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_80": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_81": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_82": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_83": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_84": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_85": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_86": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_87": { - "sdram_module": "MT46V32M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_88": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_89": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_90": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_91": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": true, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_92": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_93": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 1, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_94": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 1, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - }, - "test_95": { - "sdram_module": "MT48LC16M16", - "sdram_data_width": 32, - "bist_alternating": false, - "num_generators": 3, - "num_checkers": 3, - "access_pattern": { - "pattern_file": "access_pattern.csv" - } - } -} diff --git a/test/common.py b/test/common.py deleted file mode 100644 index 2fb0416..0000000 --- a/test/common.py +++ /dev/null @@ -1,647 +0,0 @@ -# This file is Copyright (c) 2016-2019 Florent Kermarrec -# This file is Copyright (c) 2016 Tim 'mithro' Ansell -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import os -import random -import itertools -from functools import partial -from operator import or_ - -from migen import * - - -def seed_to_data(seed, random=True, nbits=32): - if nbits == 32: - if random: - return (seed * 0x31415979 + 1) & 0xffffffff - else: - return seed - else: - assert nbits%32 == 0 - data = 0 - for i in range(nbits//32): - data = data << 32 - data |= seed_to_data(seed*nbits//32 + i, random, 32) - return data - - -@passive -def timeout_generator(ticks): - # raise exception after given timeout effectively stopping simulation - # because of @passive, simulation can end even if this generator is still running - for _ in range(ticks): - yield - raise TimeoutError("Timeout after %d ticks" % ticks) - - -class NativePortDriver: - """Generates sequences for reading/writing to LiteDRAMNativePort - - The write/read versions with wait_data=False are a cheap way to perform - burst during which the port is being held locked, but this way all the - data is being lost (would require separate coroutine to handle data). - """ - def __init__(self, port): - self.port = port - - def read(self, address, wait_data=True): - yield self.port.cmd.valid.eq(1) - yield self.port.cmd.we.eq(0) - yield self.port.cmd.addr.eq(address) - yield - while (yield self.port.cmd.ready) == 0: - yield - yield self.port.cmd.valid.eq(0) - yield - if wait_data: - while (yield self.port.rdata.valid) == 0: - yield - data = (yield self.port.rdata.data) - yield self.port.rdata.ready.eq(1) - yield - yield self.port.rdata.ready.eq(0) - yield - return data - else: - yield self.port.rdata.ready.eq(1) - - def write(self, address, data, we=None, wait_data=True): - if we is None: - we = 2**self.port.wdata.we.nbits - 1 - yield self.port.cmd.valid.eq(1) - yield self.port.cmd.we.eq(1) - yield self.port.cmd.addr.eq(address) - yield - while (yield self.port.cmd.ready) == 0: - yield - yield self.port.cmd.valid.eq(0) - yield self.port.wdata.valid.eq(1) - yield self.port.wdata.data.eq(data) - yield self.port.wdata.we.eq(we) - yield - if wait_data: - while (yield self.port.wdata.ready) == 0: - yield - yield self.port.wdata.valid.eq(0) - yield - - -class CmdRequestRWDriver: - """Simple driver for Endpoint(cmd_request_rw_layout())""" - def __init__(self, req, i=0, ep_layout=True, rw_layout=True): - self.req = req - self.rw_layout = rw_layout # if False, omit is_* signals - self.ep_layout = ep_layout # if False, omit endpoint signals (valid, etc.) - - # used to distinguish commands - self.i = self.bank = self.row = self.col = i - - def request(self, char): - # convert character to matching command invocation - return { - "w": self.write, - "r": self.read, - "W": partial(self.write, auto_precharge=True), - "R": partial(self.read, auto_precharge=True), - "a": self.activate, - "p": self.precharge, - "f": self.refresh, - "_": self.nop, - }[char]() - - def activate(self): - yield from self._drive(valid=1, is_cmd=1, ras=1, a=self.row, ba=self.bank) - - def precharge(self, all_banks=False): - a = 0 if not all_banks else (1 << 10) - yield from self._drive(valid=1, is_cmd=1, ras=1, we=1, a=a, ba=self.bank) - - def refresh(self): - yield from self._drive(valid=1, is_cmd=1, cas=1, ras=1, ba=self.bank) - - def write(self, auto_precharge=False): - assert not (self.col & (1 << 10)) - col = self.col | (1 << 10) if auto_precharge else self.col - yield from self._drive(valid=1, is_write=1, cas=1, we=1, a=col, ba=self.bank) - - def read(self, auto_precharge=False): - assert not (self.col & (1 << 10)) - col = self.col | (1 << 10) if auto_precharge else self.col - yield from self._drive(valid=1, is_read=1, cas=1, a=col, ba=self.bank) - - def nop(self): - yield from self._drive() - - def _drive(self, **kwargs): - signals = ["a", "ba", "cas", "ras", "we"] - if self.rw_layout: - signals += ["is_cmd", "is_read", "is_write"] - if self.ep_layout: - signals += ["valid", "first", "last"] - for s in signals: - yield getattr(self.req, s).eq(kwargs.get(s, 0)) - # drive ba even for nop, to be able to distinguish bank machines anyway - if "ba" not in kwargs: - yield self.req.ba.eq(self.bank) - - -class DRAMMemory: - def __init__(self, width, depth, init=[]): - self.width = width - self.depth = depth - self.mem = [] - for d in init: - self.mem.append(d) - for _ in range(depth-len(init)): - self.mem.append(0) - - # "W" enables write msgs, "R" - read msgs and "1" both - self._debug = os.environ.get("DRAM_MEM_DEBUG", "0") - - def show_content(self): - for addr in range(self.depth): - print("0x{:08x}: 0x{:0{dwidth}x}".format(addr, self.mem[addr], dwidth=self.width//4)) - - def _warn(self, address): - if address > self.depth * self.width: - print("! adr > 0x{:08x}".format( - self.depth * self.width)) - - def _write(self, address, data, we): - mask = reduce(or_, [0xff << (8 * bit) for bit in range(self.width//8) - if (we & (1 << bit)) != 0], 0) - data = data & mask - self.mem[address%self.depth] = data - if self._debug in ["1", "W"]: - print("W 0x{:08x}: 0x{:0{dwidth}x}".format(address, self.mem[address%self.depth], - dwidth=self.width//4)) - self._warn(address) - - def _read(self, address): - if self._debug in ["1", "R"]: - print("R 0x{:08x}: 0x{:0{dwidth}x}".format(address, self.mem[address%self.depth], - dwidth=self.width//4)) - self._warn(address) - return self.mem[address%self.depth] - - @passive - def read_handler(self, dram_port, rdata_valid_random=0): - address = 0 - pending = 0 - prng = random.Random(42) - yield dram_port.cmd.ready.eq(0) - while True: - yield dram_port.rdata.valid.eq(0) - if pending: - while prng.randrange(100) < rdata_valid_random: - yield - yield dram_port.rdata.valid.eq(1) - yield dram_port.rdata.data.eq(self._read(address)) - yield - yield dram_port.rdata.valid.eq(0) - yield dram_port.rdata.data.eq(0) - pending = 0 - elif (yield dram_port.cmd.valid): - pending = not (yield dram_port.cmd.we) - address = (yield dram_port.cmd.addr) - if pending: - yield dram_port.cmd.ready.eq(1) - yield - yield dram_port.cmd.ready.eq(0) - yield - - @passive - def write_handler(self, dram_port, wdata_ready_random=0): - address = 0 - pending = 0 - prng = random.Random(42) - yield dram_port.cmd.ready.eq(0) - while True: - yield dram_port.wdata.ready.eq(0) - if pending: - while (yield dram_port.wdata.valid) == 0: - yield - while prng.randrange(100) < wdata_ready_random: - yield - yield dram_port.wdata.ready.eq(1) - yield - self._write(address, (yield dram_port.wdata.data), (yield dram_port.wdata.we)) - yield dram_port.wdata.ready.eq(0) - yield - pending = 0 - yield - elif (yield dram_port.cmd.valid): - pending = (yield dram_port.cmd.we) - address = (yield dram_port.cmd.addr) - if pending: - yield dram_port.cmd.ready.eq(1) - yield - yield dram_port.cmd.ready.eq(0) - yield - - -class MemoryTestDataMixin: - @property - def bist_test_data(self): - data = { - "8bit": dict( - base = 2, - end = 2 + 8, # (end - base) must be pow of 2 - length = 5, - # 2 3 4 5 6 7=2+5 - expected = [0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00], - ), - "32bit": dict( - base = 0x04, - end = 0x04 + 8, - length = 5 * 4, - expected = [ - 0x00000000, # 0x00 - 0x00000000, # 0x04 - 0x00000001, # 0x08 - 0x00000002, # 0x0c - 0x00000003, # 0x10 - 0x00000004, # 0x14 - 0x00000000, # 0x18 - 0x00000000, # 0x1c - ], - ), - "64bit": dict( - base = 0x10, - end = 0x10 + 8, - length = 5 * 8, - expected = [ - 0x0000000000000000, # 0x00 - 0x0000000000000000, # 0x08 - 0x0000000000000000, # 0x10 - 0x0000000000000001, # 0x18 - 0x0000000000000002, # 0x20 - 0x0000000000000003, # 0x28 - 0x0000000000000004, # 0x30 - 0x0000000000000000, # 0x38 - ], - ), - "32bit_masked": dict( - base = 0x04, - end = 0x04 + 0x04, # TODO: fix address masking to be consistent - length = 6 * 4, - expected = [ # due to masking - 0x00000000, # 0x00 - 0x00000004, # 0x04 - 0x00000005, # 0x08 - 0x00000002, # 0x0c - 0x00000003, # 0x10 - 0x00000000, # 0x14 - 0x00000000, # 0x18 - 0x00000000, # 0x1c - ], - ), - } - data["32bit_long_sequential"] = dict( - base = 16, - end = 16 + 128, - length = 64, - expected = [0x00000000] * 128 - ) - expected = data["32bit_long_sequential"]["expected"] - expected[16//4:(16 + 64)//4] = list(range(64//4)) - return data - - @property - def pattern_test_data(self): - data = { - "8bit": dict( - pattern=[ - # address, data - (0x00, 0xaa), - (0x05, 0xbb), - (0x02, 0xcc), - (0x07, 0xdd), - ], - expected=[ - # data, address - 0xaa, # 0x00 - 0x00, # 0x01 - 0xcc, # 0x02 - 0x00, # 0x03 - 0x00, # 0x04 - 0xbb, # 0x05 - 0x00, # 0x06 - 0xdd, # 0x07 - ], - ), - "32bit": dict( - pattern=[ - # address, data - (0x00, 0xabadcafe), - (0x07, 0xbaadf00d), - (0x02, 0xcafefeed), - (0x01, 0xdeadc0de), - ], - expected=[ - # data, address - 0xabadcafe, # 0x00 - 0xdeadc0de, # 0x04 - 0xcafefeed, # 0x08 - 0x00000000, # 0x0c - 0x00000000, # 0x10 - 0x00000000, # 0x14 - 0x00000000, # 0x18 - 0xbaadf00d, # 0x1c - ], - ), - "64bit": dict( - pattern=[ - # address, data - (0x00, 0x0ddf00dbadc0ffee), - (0x05, 0xabadcafebaadf00d), - (0x02, 0xcafefeedfeedface), - (0x07, 0xdeadc0debaadbeef), - ], - expected=[ - # data, address - 0x0ddf00dbadc0ffee, # 0x00 - 0x0000000000000000, # 0x08 - 0xcafefeedfeedface, # 0x10 - 0x0000000000000000, # 0x18 - 0x0000000000000000, # 0x20 - 0xabadcafebaadf00d, # 0x28 - 0x0000000000000000, # 0x30 - 0xdeadc0debaadbeef, # 0x38 - ], - ), - "64bit_to_32bit": dict( - pattern=[ - # address, data - (0x00, 0x0d15ea5e00facade), - (0x05, 0xabadcafe8badf00d), - (0x01, 0xcafefeedbaadf00d), - (0x02, 0xfee1deaddeadc0de), - ], - expected=[ - # data, word, address - 0x00facade, # 0 0x00 - 0x0d15ea5e, # 1 0x04 - 0xbaadf00d, # 2 0x08 - 0xcafefeed, # 3 0x0c - 0xdeadc0de, # 4 0x10 - 0xfee1dead, # 5 0x14 - 0x00000000, # 6 0x18 - 0x00000000, # 7 0x1c - 0x00000000, # 8 0x20 - 0x00000000, # 9 0x24 - 0x8badf00d, # 10 0x28 - 0xabadcafe, # 11 0x2c - 0x00000000, # 12 0x30 - ] - ), - "32bit_to_8bit": dict( - pattern=[ - # address, data - (0x00, 0x00112233), - (0x05, 0x44556677), - (0x01, 0x8899aabb), - (0x02, 0xccddeeff), - ], - expected=[ - # data, address - 0x33, # 0x00 - 0x22, # 0x01 - 0x11, # 0x02 - 0x00, # 0x03 - 0xbb, # 0x04 - 0xaa, # 0x05 - 0x99, # 0x06 - 0x88, # 0x07 - 0xff, # 0x08 - 0xee, # 0x09 - 0xdd, # 0x0a - 0xcc, # 0x0b - 0x00, # 0x0c - 0x00, # 0x0d - 0x00, # 0x0e - 0x00, # 0x0f - 0x00, # 0x10 - 0x00, # 0x11 - 0x00, # 0x12 - 0x00, # 0x13 - 0x77, # 0x14 - 0x66, # 0x15 - 0x55, # 0x16 - 0x44, # 0x17 - 0x00, # 0x18 - 0x00, # 0x19 - ] - ), - "8bit_to_32bit": dict( - pattern=[ - # address, data - (0x00, 0x00), - (0x01, 0x11), - (0x02, 0x22), - (0x03, 0x33), - (0x10, 0x44), - (0x11, 0x55), - (0x12, 0x66), - (0x13, 0x77), - (0x08, 0x88), - (0x09, 0x99), - (0x0a, 0xaa), - (0x0b, 0xbb), - (0x0c, 0xcc), - (0x0d, 0xdd), - (0x0e, 0xee), - (0x0f, 0xff), - ], - expected=[ - # data, address - 0x33221100, # 0x00 - 0x00000000, # 0x04 - 0xbbaa9988, # 0x08 - 0xffeeddcc, # 0x0c - 0x77665544, # 0x10 - 0x00000000, # 0x14 - 0x00000000, # 0x18 - 0x00000000, # 0x1c - ] - ), - "8bit_to_32bit_not_aligned": dict( - pattern=[ - # address, data - (0x00, 0x00), - (0x05, 0x11), - (0x0a, 0x22), - (0x0f, 0x33), - (0x1d, 0x44), - (0x15, 0x55), - (0x13, 0x66), - (0x18, 0x77), - ], - expected=[ - # data, address - 0x00000000, # 0x00 - 0x00001100, # 0x04 - 0x00220000, # 0x08 - 0x33000000, # 0x0c - 0x66000000, # 0x10 - 0x00005500, # 0x14 - 0x00000077, # 0x18 - 0x00440000, # 0x1c - ] - ), - "32bit_to_256bit": dict( - pattern=[ - # address, data - (0x00, 0x00000000), - (0x01, 0x11111111), - (0x02, 0x22222222), - (0x03, 0x33333333), - (0x04, 0x44444444), - (0x05, 0x55555555), - (0x06, 0x66666666), - (0x07, 0x77777777), - (0x10, 0x88888888), - (0x11, 0x99999999), - (0x12, 0xaaaaaaaa), - (0x13, 0xbbbbbbbb), - (0x14, 0xcccccccc), - (0x15, 0xdddddddd), - (0x16, 0xeeeeeeee), - (0x17, 0xffffffff), - ], - expected=[ - # data, address - 0x7777777766666666555555554444444433333333222222221111111100000000, # 0x00 - 0x0000000000000000000000000000000000000000000000000000000000000000, # 0x20 - 0xffffffffeeeeeeeeddddddddccccccccbbbbbbbbaaaaaaaa9999999988888888, # 0x40 - 0x0000000000000000000000000000000000000000000000000000000000000000, # 0x60 - ] - ), - "32bit_to_256bit_not_aligned": dict( - pattern=[ - # address, data - (0x00, 0x00000000), - (0x01, 0x11111111), - (0x02, 0x22222222), - (0x03, 0x33333333), - (0x04, 0x44444444), - (0x05, 0x55555555), - (0x06, 0x66666666), - (0x07, 0x77777777), - (0x14, 0x88888888), - (0x15, 0x99999999), - (0x16, 0xaaaaaaaa), - (0x17, 0xbbbbbbbb), - (0x18, 0xcccccccc), - (0x19, 0xdddddddd), - (0x1a, 0xeeeeeeee), - (0x1b, 0xffffffff), - ], - expected=[ - # data, address - 0x7777777766666666555555554444444433333333222222221111111100000000, # 0x00 - 0x0000000000000000000000000000000000000000000000000000000000000000, # 0x20 - 0xbbbbbbbbaaaaaaaa999999998888888800000000000000000000000000000000, # 0x40 - 0x00000000000000000000000000000000ffffffffeeeeeeeeddddddddcccccccc, # 0x60 - ] - ), - "32bit_not_aligned": dict( - pattern=[ - # address, data - (0x00, 0xabadcafe), - (0x07, 0xbaadf00d), - (0x02, 0xcafefeed), - (0x01, 0xdeadc0de), - ], - expected=[ - # data, address - 0xabadcafe, # 0x00 - 0xdeadc0de, # 0x04 - 0xcafefeed, # 0x08 - 0x00000000, # 0x0c - 0x00000000, # 0x10 - 0x00000000, # 0x14 - 0x00000000, # 0x18 - 0xbaadf00d, # 0x1c - ], - ), - "32bit_duplicates": dict( - pattern=[ - # address, data - (0x00, 0xabadcafe), - (0x07, 0xbaadf00d), - (0x00, 0xcafefeed), - (0x07, 0xdeadc0de), - ], - expected=[ - # data, address - 0xcafefeed, # 0x00 - 0x00000000, # 0x04 - 0x00000000, # 0x08 - 0x00000000, # 0x0c - 0x00000000, # 0x10 - 0x00000000, # 0x14 - 0x00000000, # 0x18 - 0xdeadc0de, # 0x1c - ], - ), - "32bit_sequential": dict( - pattern=[ - # address, data - (0x02, 0xabadcafe), - (0x03, 0xbaadf00d), - (0x04, 0xcafefeed), - (0x05, 0xdeadc0de), - ], - expected=[ - # data, address - 0x00000000, # 0x00 - 0x00000000, # 0x04 - 0xabadcafe, # 0x08 - 0xbaadf00d, # 0x0c - 0xcafefeed, # 0x10 - 0xdeadc0de, # 0x14 - 0x00000000, # 0x18 - 0x00000000, # 0x1c - ], - ), - "32bit_long_sequential": dict(pattern=[], expected=[0] * 64), - } - - # 32bit_long_sequential - for i in range(32): - data["32bit_long_sequential"]["pattern"].append((i, 64 + i)) - data["32bit_long_sequential"]["expected"][i] = 64 + i - - def half_width(data, from_width): - half_mask = 2**(from_width//2) - 1 - chunks = [(val & half_mask, (val >> from_width//2) & half_mask) for val in data] - return list(itertools.chain.from_iterable(chunks)) - - # down conversion - data["64bit_to_16bit"] = dict( - pattern = data["64bit_to_32bit"]["pattern"].copy(), - expected = half_width(data["64bit_to_32bit"]["expected"], from_width=32), - ) - data["64bit_to_8bit"] = dict( - pattern = data["64bit_to_16bit"]["pattern"].copy(), - expected = half_width(data["64bit_to_16bit"]["expected"], from_width=16), - ) - - # up conversion - data["8bit_to_16bit"] = dict( - pattern = data["8bit_to_32bit"]["pattern"].copy(), - expected = half_width(data["8bit_to_32bit"]["expected"], from_width=32), - ) - data["32bit_to_128bit"] = dict( - pattern = data["32bit_to_256bit"]["pattern"].copy(), - expected = half_width(data["32bit_to_256bit"]["expected"], from_width=256), - ) - data["32bit_to_64bit"] = dict( - pattern = data["32bit_to_128bit"]["pattern"].copy(), - expected = half_width(data["32bit_to_128bit"]["expected"], from_width=128), - ) - - return data diff --git a/test/gen_access_pattern.py b/test/gen_access_pattern.py deleted file mode 100755 index ba52145..0000000 --- a/test/gen_access_pattern.py +++ /dev/null @@ -1,35 +0,0 @@ -#!/usr/bin/env python3 - -import random -import argparse - -def main(): - description = """ - Generate random access pattern for LiteDRAM Pattern Generator/Checker. - - Each address in range [base, base+length) will be accessed only once, but in random order. - This ensures that no data will be overwritten. - """ - parser = argparse.ArgumentParser(description=description) - parser.add_argument("base", help="Base address") - parser.add_argument("length", help="Number of (address, data) pairs") - parser.add_argument("data_width", help="Width of data (used to determine max value)") - parser.add_argument("--seed", help="Use given random seed (int)") - args = parser.parse_args() - - if args.seed: - random.seed(int(args.seed, 0)) - - base = int(args.base, 0) - length = int(args.length, 0) - data_width = int(args.data_width, 0) - - address = list(range(length)) - random.shuffle(address) - data = [random.randrange(0, 2**data_width) for _ in range(length)] - - for a, d in zip(address, data): - print("0x{:08x}, 0x{:08x}".format(a, d)) - -if __name__ == "__main__": - main() diff --git a/test/gen_config.py b/test/gen_config.py deleted file mode 100755 index b778c1f..0000000 --- a/test/gen_config.py +++ /dev/null @@ -1,138 +0,0 @@ -#!/usr/bin/env python3 - -import sys -import json -import pprint -import argparse -import datetime -import itertools - - -defaults = { - "--sdram-module": [ - "IS42S16160", - "IS42S16320", - "MT48LC4M16", - "MT48LC16M16", - "AS4C16M16", - "AS4C32M16", - "AS4C32M8", - "M12L64322A", - "M12L16161A", - "MT46V32M16", - "MT46H32M16", - "MT46H32M32", - "MT47H128M8", - "MT47H32M16", - "MT47H64M16", - "P3R1GE4JGF", - "MT41K64M16", - "MT41J128M16", - "MT41K128M16", - "MT41J256M16", - "MT41K256M16", - "K4B1G0446F", - "K4B2G1646F", - "H5TC4G63CFR", - "IS43TR16128B", - "MT8JTF12864", - "MT8KTF51264", - #"MT18KSF1G72HZ", - #"AS4C256M16D3A", - #"MT16KTF1G64HZ", - #"EDY4016A", - #"MT40A1G8", - #"MT40A512M16", - ], - "--sdram-data-width": [32], - "--bist-alternating": [True, False], - "--bist-length": [1, 4096], - "--bist-random": [True, False], - "--num-generators": [1], - "--num-checkers": [1], - "--access-pattern": ["access_pattern.csv"] -} - - -def convert_string_arg(args, arg, type): - map_func = { - bool: lambda s: {"false": False, "true": True}[s.lower()], - int: lambda s: int(s, 0), - } - setattr(args, arg, [map_func[type](val) if not isinstance(val, type) else val for val in getattr(args, arg)]) - - -def generate_header(args): - header = "Auto-generated on {} by {}".format( - datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), - sys.argv[0], - ) - #args_str = pprint.pformat(vars(args), sort_dicts=False) # FIXME: python3.7 specific? - args_str = pprint.pformat(vars(args)) - arg_lines = args_str.split("\n") - lines = [60*"=", header, 60*"-", *arg_lines, 60*"="] - return "\n".join("# " + line for line in lines) - - -def main(): - parser = argparse.ArgumentParser(description="Generate configuration for all possible argument combinations.", - formatter_class=argparse.ArgumentDefaultsHelpFormatter) - parser.add_argument("--name-format", default="test_%d", help="Name format for i-th test") - for name, default in defaults.items(): - parser.add_argument(name, nargs="+", default=default, help="%s options" % name) - args = parser.parse_args() - - # Make sure not to write those as strings - convert_string_arg(args, "sdram_data_width", int) - convert_string_arg(args, "bist_alternating", bool) - convert_string_arg(args, "bist_length", int) - convert_string_arg(args, "bist_random", bool) - convert_string_arg(args, "num_generators", int) - convert_string_arg(args, "num_checkers", int) - - common_args = ("sdram_module", "sdram_data_width", "bist_alternating", "num_generators", "num_checkers") - generated_pattern_args = ("bist_length", "bist_random") - custom_pattern_args = ("access_pattern", ) - - def generated_pattern_configuration(values): - config = dict(zip(common_args + generated_pattern_args, values)) - # Move access pattern parameters deeper - config["access_pattern"] = { - "bist_length": config.pop("bist_length"), - "bist_random": config.pop("bist_random"), - } - return config - - def custom_pattern_configuration(values): - config = dict(zip(common_args + custom_pattern_args, values)) - # "rename" --access-pattern to access_pattern.pattern_file due to name difference between - # command line args and run_benchmarks.py configuration format - config["access_pattern"] = { - "pattern_file": config.pop("access_pattern"), - } - return config - - # Iterator over the product of given command line arguments - def args_product(names): - return itertools.product(*(getattr(args, name) for name in names)) - - generated_pattern_iter = zip(itertools.repeat(generated_pattern_configuration), args_product(common_args + generated_pattern_args)) - custom_pattern_iter = zip(itertools.repeat(custom_pattern_configuration), args_product(common_args + custom_pattern_args)) - - i = 0 - configurations = {} - for config_generator, values in itertools.chain(generated_pattern_iter, custom_pattern_iter): - config = config_generator(values) - # Ignore unsupported case: bist_random=True and bist_alternating=False - if config["access_pattern"].get("bist_random", False) and not config["bist_alternating"]: - continue - configurations[args.name_format % i] = config - i += 1 - - json_str = json.dumps(configurations, indent=4) - print(generate_header(args)) - print(json_str) - - -if __name__ == "__main__": - main() diff --git a/test/reference/ddr3_init.h b/test/reference/ddr3_init.h deleted file mode 100644 index e8f2f06..0000000 --- a/test/reference/ddr3_init.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef __GENERATED_SDRAM_PHY_H -#define __GENERATED_SDRAM_PHY_H -#include -#include - -#define DFII_CONTROL_SEL 0x01 -#define DFII_CONTROL_CKE 0x02 -#define DFII_CONTROL_ODT 0x04 -#define DFII_CONTROL_RESET_N 0x08 - -#define DFII_COMMAND_CS 0x01 -#define DFII_COMMAND_WE 0x02 -#define DFII_COMMAND_CAS 0x04 -#define DFII_COMMAND_RAS 0x08 -#define DFII_COMMAND_WRDATA 0x10 -#define DFII_COMMAND_RDDATA 0x20 - -#define SDRAM_PHY_K7DDRPHY -#define SDRAM_PHY_PHASES 4 -#define SDRAM_PHY_WRITE_LEVELING_CAPABLE -#define SDRAM_PHY_READ_LEVELING_CAPABLE -#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2 -#define SDRAM_PHY_DELAYS 32 -#define SDRAM_PHY_BITSLIPS 16 - -static void cdelay(int i); - -__attribute__((unused)) static void command_p0(int cmd) -{ - sdram_dfii_pi0_command_write(cmd); - sdram_dfii_pi0_command_issue_write(1); -} -__attribute__((unused)) static void command_p1(int cmd) -{ - sdram_dfii_pi1_command_write(cmd); - sdram_dfii_pi1_command_issue_write(1); -} -__attribute__((unused)) static void command_p2(int cmd) -{ - sdram_dfii_pi2_command_write(cmd); - sdram_dfii_pi2_command_issue_write(1); -} -__attribute__((unused)) static void command_p3(int cmd) -{ - sdram_dfii_pi3_command_write(cmd); - sdram_dfii_pi3_command_issue_write(1); -} - - -#define sdram_dfii_pird_address_write(X) sdram_dfii_pi1_address_write(X) -#define sdram_dfii_piwr_address_write(X) sdram_dfii_pi1_address_write(X) -#define sdram_dfii_pird_baddress_write(X) sdram_dfii_pi1_baddress_write(X) -#define sdram_dfii_piwr_baddress_write(X) sdram_dfii_pi1_baddress_write(X) -#define command_prd(X) command_p1(X) -#define command_pwr(X) command_p1(X) - -#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE - -const unsigned long sdram_dfii_pix_wrdata_addr[SDRAM_PHY_PHASES] = { - CSR_SDRAM_DFII_PI0_WRDATA_ADDR, - CSR_SDRAM_DFII_PI1_WRDATA_ADDR, - CSR_SDRAM_DFII_PI2_WRDATA_ADDR, - CSR_SDRAM_DFII_PI3_WRDATA_ADDR -}; - -const unsigned long sdram_dfii_pix_rddata_addr[SDRAM_PHY_PHASES] = { - CSR_SDRAM_DFII_PI0_RDDATA_ADDR, - CSR_SDRAM_DFII_PI1_RDDATA_ADDR, - CSR_SDRAM_DFII_PI2_RDDATA_ADDR, - CSR_SDRAM_DFII_PI3_RDDATA_ADDR -}; - -#define DDRX_MR1 6 - -static void init_sequence(void) -{ - /* Release reset */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(0); - sdram_dfii_control_write(DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); - cdelay(50000); - - /* Bring CKE high */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(0); - sdram_dfii_control_write(DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); - cdelay(10000); - - /* Load Mode Register 2, CWL=6 */ - sdram_dfii_pi0_address_write(0x208); - sdram_dfii_pi0_baddress_write(2); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 3 */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(3); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 1 */ - sdram_dfii_pi0_address_write(0x6); - sdram_dfii_pi0_baddress_write(1); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 0, CL=7, BL=8 */ - sdram_dfii_pi0_address_write(0x930); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - cdelay(200); - - /* ZQ Calibration */ - sdram_dfii_pi0_address_write(0x400); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_WE|DFII_COMMAND_CS); - cdelay(200); - -} -#endif diff --git a/test/reference/ddr3_init.py b/test/reference/ddr3_init.py deleted file mode 100644 index a530f98..0000000 --- a/test/reference/ddr3_init.py +++ /dev/null @@ -1,23 +0,0 @@ -dfii_control_sel = 0x01 -dfii_control_cke = 0x02 -dfii_control_odt = 0x04 -dfii_control_reset_n = 0x08 - -dfii_command_cs = 0x01 -dfii_command_we = 0x02 -dfii_command_cas = 0x04 -dfii_command_ras = 0x08 -dfii_command_wrdata = 0x10 -dfii_command_rddata = 0x20 - -ddrx_mr1 = 0x6 - -init_sequence = [ - ("Release reset", 0, 0, dfii_control_odt|dfii_control_reset_n, 50000), - ("Bring CKE high", 0, 0, dfii_control_cke|dfii_control_odt|dfii_control_reset_n, 10000), - ("Load Mode Register 2, CWL=6", 520, 2, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 3", 0, 3, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 1", 6, 1, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 0, CL=7, BL=8", 2352, 0, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 200), - ("ZQ Calibration", 1024, 0, dfii_command_we|dfii_command_cs, 200), -] diff --git a/test/reference/ddr4_init.h b/test/reference/ddr4_init.h deleted file mode 100644 index ba42f19..0000000 --- a/test/reference/ddr4_init.h +++ /dev/null @@ -1,133 +0,0 @@ -#ifndef __GENERATED_SDRAM_PHY_H -#define __GENERATED_SDRAM_PHY_H -#include -#include - -#define DFII_CONTROL_SEL 0x01 -#define DFII_CONTROL_CKE 0x02 -#define DFII_CONTROL_ODT 0x04 -#define DFII_CONTROL_RESET_N 0x08 - -#define DFII_COMMAND_CS 0x01 -#define DFII_COMMAND_WE 0x02 -#define DFII_COMMAND_CAS 0x04 -#define DFII_COMMAND_RAS 0x08 -#define DFII_COMMAND_WRDATA 0x10 -#define DFII_COMMAND_RDDATA 0x20 - -#define SDRAM_PHY_USDDRPHY -#define SDRAM_PHY_PHASES 4 -#define SDRAM_PHY_WRITE_LEVELING_CAPABLE -#define SDRAM_PHY_WRITE_LEVELING_REINIT -#define SDRAM_PHY_READ_LEVELING_CAPABLE -#define SDRAM_PHY_MODULES DFII_PIX_DATA_BYTES/2 -#define SDRAM_PHY_DELAYS 512 -#define SDRAM_PHY_BITSLIPS 16 - -static void cdelay(int i); - -__attribute__((unused)) static void command_p0(int cmd) -{ - sdram_dfii_pi0_command_write(cmd); - sdram_dfii_pi0_command_issue_write(1); -} -__attribute__((unused)) static void command_p1(int cmd) -{ - sdram_dfii_pi1_command_write(cmd); - sdram_dfii_pi1_command_issue_write(1); -} -__attribute__((unused)) static void command_p2(int cmd) -{ - sdram_dfii_pi2_command_write(cmd); - sdram_dfii_pi2_command_issue_write(1); -} -__attribute__((unused)) static void command_p3(int cmd) -{ - sdram_dfii_pi3_command_write(cmd); - sdram_dfii_pi3_command_issue_write(1); -} - - -#define sdram_dfii_pird_address_write(X) sdram_dfii_pi1_address_write(X) -#define sdram_dfii_piwr_address_write(X) sdram_dfii_pi2_address_write(X) -#define sdram_dfii_pird_baddress_write(X) sdram_dfii_pi1_baddress_write(X) -#define sdram_dfii_piwr_baddress_write(X) sdram_dfii_pi2_baddress_write(X) -#define command_prd(X) command_p1(X) -#define command_pwr(X) command_p2(X) - -#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE - -const unsigned long sdram_dfii_pix_wrdata_addr[SDRAM_PHY_PHASES] = { - CSR_SDRAM_DFII_PI0_WRDATA_ADDR, - CSR_SDRAM_DFII_PI1_WRDATA_ADDR, - CSR_SDRAM_DFII_PI2_WRDATA_ADDR, - CSR_SDRAM_DFII_PI3_WRDATA_ADDR -}; - -const unsigned long sdram_dfii_pix_rddata_addr[SDRAM_PHY_PHASES] = { - CSR_SDRAM_DFII_PI0_RDDATA_ADDR, - CSR_SDRAM_DFII_PI1_RDDATA_ADDR, - CSR_SDRAM_DFII_PI2_RDDATA_ADDR, - CSR_SDRAM_DFII_PI3_RDDATA_ADDR -}; - -#define DDRX_MR1 769 - -static void init_sequence(void) -{ - /* Release reset */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(0); - sdram_dfii_control_write(DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); - cdelay(50000); - - /* Bring CKE high */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(0); - sdram_dfii_control_write(DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); - cdelay(10000); - - /* Load Mode Register 3 */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(3); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 6 */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(6); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 5 */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(5); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 4 */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(4); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 2, CWL=9 */ - sdram_dfii_pi0_address_write(0x200); - sdram_dfii_pi0_baddress_write(2); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 1 */ - sdram_dfii_pi0_address_write(0x301); - sdram_dfii_pi0_baddress_write(1); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register 0, CL=11, BL=8 */ - sdram_dfii_pi0_address_write(0x110); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - cdelay(200); - - /* ZQ Calibration */ - sdram_dfii_pi0_address_write(0x400); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_WE|DFII_COMMAND_CS); - cdelay(200); - -} -#endif diff --git a/test/reference/ddr4_init.py b/test/reference/ddr4_init.py deleted file mode 100644 index 49051ac..0000000 --- a/test/reference/ddr4_init.py +++ /dev/null @@ -1,26 +0,0 @@ -dfii_control_sel = 0x01 -dfii_control_cke = 0x02 -dfii_control_odt = 0x04 -dfii_control_reset_n = 0x08 - -dfii_command_cs = 0x01 -dfii_command_we = 0x02 -dfii_command_cas = 0x04 -dfii_command_ras = 0x08 -dfii_command_wrdata = 0x10 -dfii_command_rddata = 0x20 - -ddrx_mr1 = 0x301 - -init_sequence = [ - ("Release reset", 0, 0, dfii_control_odt|dfii_control_reset_n, 50000), - ("Bring CKE high", 0, 0, dfii_control_cke|dfii_control_odt|dfii_control_reset_n, 10000), - ("Load Mode Register 3", 0, 3, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 6", 0, 6, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 5", 0, 5, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 4", 0, 4, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 2, CWL=9", 512, 2, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 1", 769, 1, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register 0, CL=11, BL=8", 272, 0, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 200), - ("ZQ Calibration", 1024, 0, dfii_command_we|dfii_command_cs, 200), -] diff --git a/test/reference/sdr_init.h b/test/reference/sdr_init.h deleted file mode 100644 index 81f975a..0000000 --- a/test/reference/sdr_init.h +++ /dev/null @@ -1,90 +0,0 @@ -#ifndef __GENERATED_SDRAM_PHY_H -#define __GENERATED_SDRAM_PHY_H -#include -#include - -#define DFII_CONTROL_SEL 0x01 -#define DFII_CONTROL_CKE 0x02 -#define DFII_CONTROL_ODT 0x04 -#define DFII_CONTROL_RESET_N 0x08 - -#define DFII_COMMAND_CS 0x01 -#define DFII_COMMAND_WE 0x02 -#define DFII_COMMAND_CAS 0x04 -#define DFII_COMMAND_RAS 0x08 -#define DFII_COMMAND_WRDATA 0x10 -#define DFII_COMMAND_RDDATA 0x20 - -#define SDRAM_PHY_GENSDRPHY -#define SDRAM_PHY_PHASES 1 - -static void cdelay(int i); - -__attribute__((unused)) static void command_p0(int cmd) -{ - sdram_dfii_pi0_command_write(cmd); - sdram_dfii_pi0_command_issue_write(1); -} - - -#define sdram_dfii_pird_address_write(X) sdram_dfii_pi0_address_write(X) -#define sdram_dfii_piwr_address_write(X) sdram_dfii_pi0_address_write(X) -#define sdram_dfii_pird_baddress_write(X) sdram_dfii_pi0_baddress_write(X) -#define sdram_dfii_piwr_baddress_write(X) sdram_dfii_pi0_baddress_write(X) -#define command_prd(X) command_p0(X) -#define command_pwr(X) command_p0(X) - -#define DFII_PIX_DATA_SIZE CSR_SDRAM_DFII_PI0_WRDATA_SIZE - -const unsigned long sdram_dfii_pix_wrdata_addr[SDRAM_PHY_PHASES] = { - CSR_SDRAM_DFII_PI0_WRDATA_ADDR -}; - -const unsigned long sdram_dfii_pix_rddata_addr[SDRAM_PHY_PHASES] = { - CSR_SDRAM_DFII_PI0_RDDATA_ADDR -}; - -static void init_sequence(void) -{ - /* Bring CKE high */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(0); - sdram_dfii_control_write(DFII_CONTROL_CKE|DFII_CONTROL_ODT|DFII_CONTROL_RESET_N); - cdelay(20000); - - /* Precharge All */ - sdram_dfii_pi0_address_write(0x400); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Load Mode Register / Reset DLL, CL=2, BL=1 */ - sdram_dfii_pi0_address_write(0x120); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - cdelay(200); - - /* Precharge All */ - sdram_dfii_pi0_address_write(0x400); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - - /* Auto Refresh */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS); - cdelay(4); - - /* Auto Refresh */ - sdram_dfii_pi0_address_write(0x0); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_CS); - cdelay(4); - - /* Load Mode Register / CL=2, BL=1 */ - sdram_dfii_pi0_address_write(0x20); - sdram_dfii_pi0_baddress_write(0); - command_p0(DFII_COMMAND_RAS|DFII_COMMAND_CAS|DFII_COMMAND_WE|DFII_COMMAND_CS); - cdelay(200); - -} -#endif diff --git a/test/reference/sdr_init.py b/test/reference/sdr_init.py deleted file mode 100644 index 30e464f..0000000 --- a/test/reference/sdr_init.py +++ /dev/null @@ -1,21 +0,0 @@ -dfii_control_sel = 0x01 -dfii_control_cke = 0x02 -dfii_control_odt = 0x04 -dfii_control_reset_n = 0x08 - -dfii_command_cs = 0x01 -dfii_command_we = 0x02 -dfii_command_cas = 0x04 -dfii_command_ras = 0x08 -dfii_command_wrdata = 0x10 -dfii_command_rddata = 0x20 - -init_sequence = [ - ("Bring CKE high", 0, 0, dfii_control_cke|dfii_control_odt|dfii_control_reset_n, 20000), - ("Precharge All", 1024, 0, dfii_command_ras|dfii_command_we|dfii_command_cs, 0), - ("Load Mode Register / Reset DLL, CL=2, BL=1", 288, 0, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 200), - ("Precharge All", 1024, 0, dfii_command_ras|dfii_command_we|dfii_command_cs, 0), - ("Auto Refresh", 0, 0, dfii_command_ras|dfii_command_cas|dfii_command_cs, 4), - ("Auto Refresh", 0, 0, dfii_command_ras|dfii_command_cas|dfii_command_cs, 4), - ("Load Mode Register / CL=2, BL=1", 32, 0, dfii_command_ras|dfii_command_cas|dfii_command_we|dfii_command_cs, 200), -] diff --git a/test/run_benchmarks.py b/test/run_benchmarks.py deleted file mode 100755 index 8ae80bf..0000000 --- a/test/run_benchmarks.py +++ /dev/null @@ -1,670 +0,0 @@ -#!/usr/bin/env python3 - -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -# Limitations/TODO -# - add configurable sdram_clk_freq - using hardcoded value now -# - sdram_controller_data_width - try to expose the value from litex_sim to avoid duplicated code - -import os -import re -import sys -import json -import argparse -import datetime -import subprocess -from collections import defaultdict, namedtuple - -import yaml -try: - import numpy as np - import pandas as pd - import matplotlib - from matplotlib.ticker import FuncFormatter, PercentFormatter, ScalarFormatter - _summary = True -except ImportError as e: - _summary = False - print("[WARNING] Results summary not available:", e, file=sys.stderr) - -from litex.tools.litex_sim import get_sdram_phy_settings, sdram_module_nphases -from litedram import modules as litedram_modules -from litedram.common import Settings as _Settings - -from test import benchmark - -# Benchmark configuration -------------------------------------------------------------------------- - -class Settings(_Settings): - def as_dict(self): - d = dict() - for attr, value in vars(self).items(): - if attr == "self" or attr.startswith("_"): - continue - if isinstance(value, Settings): - value = value.as_dict() - d[attr] = value - return d - - -class GeneratedAccess(Settings): - def __init__(self, bist_length, bist_random): - self.set_attributes(locals()) - - @property - def length(self): - return self.bist_length - - def as_args(self): - args = ["--bist-length=%d" % self.bist_length] - if self.bist_random: - args.append("--bist-random") - return args - - -class CustomAccess(Settings): - def __init__(self, pattern_file): - self.set_attributes(locals()) - - @property - def pattern(self): - # We have to load the file to know pattern length, cache it when requested - if not hasattr(self, "_pattern"): - path = self.pattern_file - if not os.path.isabs(path): - benchmark_dir = os.path.dirname(benchmark.__file__) - path = os.path.join(benchmark_dir, path) - self._pattern = benchmark.load_access_pattern(path) - return self._pattern - - @property - def length(self): - return len(self.pattern) - - def as_args(self): - return ["--access-pattern=%s" % self.pattern_file] - - -class BenchmarkConfiguration(Settings): - def __init__(self, name, sdram_module, sdram_data_width, bist_alternating, - num_generators, num_checkers, access_pattern): - self.set_attributes(locals()) - - def as_args(self): - args = [ - "--sdram-module=%s" % self.sdram_module, - "--sdram-data-width=%d" % self.sdram_data_width, - "--num-generators=%d" % self.num_generators, - "--num-checkers=%d" % self.num_checkers, - ] - if self.bist_alternating: - args.append("--bist-alternating") - args += self.access_pattern.as_args() - return args - - def __eq__(self, other): - if not isinstance(other, BenchmarkConfiguration): - return NotImplemented - return self.as_dict() == other.as_dict() - - @property - def length(self): - return self.access_pattern.length - - @classmethod - def from_dict(cls, d): - access_cls = CustomAccess if "pattern_file" in d["access_pattern"] else GeneratedAccess - d["access_pattern"] = access_cls(**d["access_pattern"]) - return cls(**d) - - @classmethod - def load_yaml(cls, yaml_file): - with open(yaml_file) as f: - description = yaml.safe_load(f) - configs = [] - for name, desc in description.items(): - desc["name"] = name - configs.append(cls.from_dict(desc)) - return configs - - def __repr__(self): - return "BenchmarkConfiguration(%s)" % self.as_dict() - - @property - def sdram_clk_freq(self): - return 100e6 # FIXME: Value of 100MHz is hardcoded in litex_sim - - @property - def sdram_memtype(self): - # Use values from module class (no need to instantiate it) - sdram_module_cls = getattr(litedram_modules, self.sdram_module) - return sdram_module_cls.memtype - - @property - def sdram_controller_data_width(self): - nphases = sdram_module_nphases[self.sdram_memtype] - dfi_databits = self.sdram_data_width * (1 if self.sdram_memtype == "SDR" else 2) - return dfi_databits * nphases - -# Benchmark results -------------------------------------------------------------------------------- - -# Constructs python regex named group -def ng(name, regex): - return r"(?P<{}>{})".format(name, regex) - - -def _compiled_pattern(stage, var): - pattern_fmt = r"{stage}\s+{var}:\s+{value}" - pattern = pattern_fmt.format( - stage = stage, - var = var, - value = ng("value", "[0-9]+"), - ) - return re.compile(pattern) - result = re.search(pattern, benchmark_output) - - -class BenchmarkResult: - # Pre-compiled patterns for all benchmarks - patterns = { - "generator_ticks": _compiled_pattern("BIST-GENERATOR", "ticks"), - "checker_errors": _compiled_pattern("BIST-CHECKER", "errors"), - "checker_ticks": _compiled_pattern("BIST-CHECKER", "ticks"), - } - - @staticmethod - def find(pattern, output): - result = pattern.search(output) - assert result is not None, \ - "Could not find pattern {} in output".format(pattern) - return int(result.group("value")) - - def __init__(self, output): - self._output = output - for attr, pattern in self.patterns.items(): - setattr(self, attr, self.find(pattern, output)) - - def __repr__(self): - d = {attr: getattr(self, attr) for attr in self.patterns.keys()} - return "BenchmarkResult(%s)" % d - -# Results summary ---------------------------------------------------------------------------------- - -def human_readable(value): - binary_prefixes = ["", "k", "M", "G", "T"] - mult = 1.0 - for prefix in binary_prefixes: - if value * mult < 1024: - break - mult /= 1024 - return mult, prefix - - -def clocks_fmt(clocks): - return "{:d} clk".format(int(clocks)) - - -def bandwidth_fmt(bw): - mult, prefix = human_readable(bw) - return "{:.1f} {}bps".format(bw * mult, prefix) - - -def efficiency_fmt(eff): - return "{:.1f} %".format(eff * 100) - - -def get_git_file_path(filename): - cmd = ["git", "ls-files", "--full-name", filename] - proc = subprocess.run(cmd, stdout=subprocess.PIPE, cwd=os.path.dirname(__file__)) - return proc.stdout.decode().strip() if proc.returncode == 0 else "" - - -def get_git_revision_hash(short=False): - short = ["--short"] if short else [] - cmd = ["git", "rev-parse", *short, "HEAD"] - proc = subprocess.run(cmd, stdout=subprocess.PIPE, cwd=os.path.dirname(__file__)) - return proc.stdout.decode().strip() if proc.returncode == 0 else "" - - -class ResultsSummary: - def __init__(self, run_data, plots_dir="plots"): - self.plots_dir = plots_dir - - # Because .sdram_controller_data_width may fail for unimplemented modules - def except_none(func): - try: - return func() - except: - return None - - # Gather results into tabular data - column_mappings = { - "name": lambda d: d.config.name, - "sdram_module": lambda d: d.config.sdram_module, - "sdram_data_width": lambda d: d.config.sdram_data_width, - "bist_alternating": lambda d: d.config.bist_alternating, - "num_generators": lambda d: d.config.num_generators, - "num_checkers": lambda d: d.config.num_checkers, - "bist_length": lambda d: getattr(d.config.access_pattern, "bist_length", None), - "bist_random": lambda d: getattr(d.config.access_pattern, "bist_random", None), - "pattern_file": lambda d: getattr(d.config.access_pattern, "pattern_file", None), - "length": lambda d: d.config.length, - "generator_ticks": lambda d: getattr(d.result, "generator_ticks", None), # None means benchmark failure - "checker_errors": lambda d: getattr(d.result, "checker_errors", None), - "checker_ticks": lambda d: getattr(d.result, "checker_ticks", None), - "ctrl_data_width": lambda d: except_none(lambda: d.config.sdram_controller_data_width), - "sdram_memtype": lambda d: except_none(lambda: d.config.sdram_memtype), - "clk_freq": lambda d: d.config.sdram_clk_freq, - } - columns = {name: [mapping(data) for data in run_data] for name, mapping, in column_mappings.items()} - self._df = df = pd.DataFrame(columns) - - # Replace None with NaN - df.fillna(value=np.nan, inplace=True) - - # Compute other metrics based on ticks and configuration parameters - df["clk_period"] = 1 / df["clk_freq"] - # Bandwidth is the number of bits per time - # in case with N generators/checkers we actually process N times more data - df["write_bandwidth"] = (8 * df["length"] * df["num_generators"]) / (df["generator_ticks"] * df["clk_period"]) - df["read_bandwidth"] = (8 * df["length"] * df["num_checkers"]) / (df["checker_ticks"] * df["clk_period"]) - - # Efficiency calculated as number of write/read commands to number of cycles spent on writing/reading (ticks) - # for multiple generators/checkers multiply by their number - df["cmd_count"] = df["length"] / (df["ctrl_data_width"] / 8) - df["write_efficiency"] = df["cmd_count"] * df["num_generators"] / df["generator_ticks"] - df["read_efficiency"] = df["cmd_count"] * df["num_checkers"] / df["checker_ticks"] - - df["write_latency"] = df[df["bist_length"] == 1]["generator_ticks"] - df["read_latency"] = df[df["bist_length"] == 1]["checker_ticks"] - - # Boolean distinction between latency benchmarks and sequence benchmarks, - # as thier results differ significanly - df["is_latency"] = ~pd.isna(df["write_latency"]) - assert (df["is_latency"] == ~pd.isna(df["read_latency"])).all(), \ - "write_latency and read_latency should both have a value or both be NaN" - - # Data formatting for text summary - self.text_formatters = { - "write_bandwidth": bandwidth_fmt, - "read_bandwidth": bandwidth_fmt, - "write_efficiency": efficiency_fmt, - "read_efficiency": efficiency_fmt, - "write_latency": clocks_fmt, - "read_latency": clocks_fmt, - } - - # Data formatting for plot summary - self.plot_xticks_formatters = { - "write_bandwidth": FuncFormatter(lambda value, pos: bandwidth_fmt(value)), - "read_bandwidth": FuncFormatter(lambda value, pos: bandwidth_fmt(value)), - "write_efficiency": PercentFormatter(1.0), - "read_efficiency": PercentFormatter(1.0), - "write_latency": ScalarFormatter(), - "read_latency": ScalarFormatter(), - } - - def df(self, ok=True, failures=False): - is_failure = lambda df: pd.isna(df["generator_ticks"]) | pd.isna(df["checker_ticks"]) | pd.isna(df["checker_errors"]) - df = self._df - if not ok: # remove ok - is_ok = ~is_failure(df) - df = df[~is_ok] - if not failures: # remove failures - df = df[~is_failure(df)] - return df - - def header(self, text): - return "===> {}".format(text) - - def print_df(self, title, df): - # Make sure all data will be shown - with pd.option_context("display.max_rows", None, "display.max_columns", None, "display.width", None): - print(self.header(title + ":")) - print(df) - - def get_summary(self, df, mask=None, columns=None, column_formatting=None, sort_kwargs=None): - # Work on a copy - df = df.copy() - - if sort_kwargs is not None: - df = df.sort_values(**sort_kwargs) - - if column_formatting is not None: - for column, mapping in column_formatting.items(): - old = "_{}".format(column) - df[old] = df[column].copy() - df[column] = df[column].map(lambda value: mapping(value) if not pd.isna(value) else value) - - df = df[mask] if mask is not None else df - df = df[columns] if columns is not None else df - - return df - - def text_summary(self): - for title, df in self.groupped_results(): - self.print_df(title, df) - print() - - def html_summary(self, output_dir): - import jinja2 - - tables = {} - names = {} - for title, df in self.groupped_results(): - table_id = title.lower().replace(" ", "_") - - tables[table_id] = df.to_html(table_id=table_id, border=0) - names[table_id] = title - - template_dir = os.path.join(os.path.dirname(__file__), "summary") - env = jinja2.Environment(loader=jinja2.FileSystemLoader(template_dir)) - template = env.get_template("summary.html.jinja2") - - os.makedirs(output_dir, exist_ok=True) - with open(os.path.join(output_dir, "summary.html"), "w") as f: - f.write(template.render( - title = "LiteDRAM benchmarks summary", - tables = tables, - names = names, - script_path = get_git_file_path(__file__), - revision = get_git_revision_hash(), - revision_short = get_git_revision_hash(short=True), - generation_date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), - )) - - def groupped_results(self, formatters=None): - df = self.df() - - if formatters is None: - formatters = self.text_formatters - - common_columns = [ - "name", "sdram_module", "sdram_memtype", "sdram_data_width", - "bist_alternating", "num_generators", "num_checkers" - ] - latency_columns = ["write_latency", "read_latency"] - performance_columns = [ - "write_bandwidth", "read_bandwidth", "write_efficiency", "read_efficiency" - ] - failure_columns = [ - "bist_length", "bist_random", "pattern_file", "length", - "generator_ticks", "checker_errors", "checker_ticks" - ] - - yield "Latency", self.get_summary(df, - mask = df["is_latency"] == True, - columns = common_columns + latency_columns, - column_formatting = formatters, - ) - yield "Custom access pattern", self.get_summary(df, - mask = (df["is_latency"] == False) & (~pd.isna(df["pattern_file"])), - columns = common_columns + ["length", "pattern_file"] + performance_columns, - column_formatting = formatters, - ), - yield "Sequential access pattern", self.get_summary(df, - mask = (df["is_latency"] == False) & (pd.isna(df["pattern_file"])) & (df["bist_random"] == False), - columns = common_columns + ["bist_length"] + performance_columns, # could be length - column_formatting = formatters, - ), - yield "Random access pattern", self.get_summary(df, - mask = (df["is_latency"] == False) & (pd.isna(df["pattern_file"])) & (df["bist_random"] == True), - columns = common_columns + ["bist_length"] + performance_columns, - column_formatting = formatters, - ), - yield "Failures", self.get_summary(self.df(ok=False, failures=True), - columns = common_columns + failure_columns, - column_formatting = None, - ), - - def plot_summary(self, plots_dir="plots", backend="Agg", theme="default", save_format="png", **savefig_kw): - matplotlib.use(backend) - import matplotlib.pyplot as plt - plt.style.use(theme) - - for title, df in self.groupped_results(formatters={}): - for column in self.plot_xticks_formatters.keys(): - if column not in df.columns or df[column].empty: - continue - axis = self.plot_df(title, df, column) - - # construct path - def path_name(name): - return name.lower().replace(" ", "_") - - filename = "{}.{}".format(path_name(column), save_format) - path = os.path.join(plots_dir, path_name(title), filename) - os.makedirs(os.path.dirname(path), exist_ok=True) - - # save figure - axis.get_figure().savefig(path, **savefig_kw) - - if backend != "Agg": - plt.show() - - def plot_df(self, title, df, column, fig_width=6.4, fig_min_height=2.2, save_format="png", save_filename=None): - if save_filename is None: - save_filename = os.path.join(self.plots_dir, title.lower().replace(" ", "_")) - - axis = df.plot(kind="barh", x="name", y=column, title=title, grid=True, legend=False) - fig = axis.get_figure() - - if column in self.plot_xticks_formatters: - axis.xaxis.set_major_formatter(self.plot_xticks_formatters[column]) - axis.xaxis.set_tick_params(rotation=15) - axis.spines["top"].set_visible(False) - axis.spines["right"].set_visible(False) - axis.set_axisbelow(True) - axis.set_ylabel("") # No need for label as we have only one series - - # For large number of rows, the bar labels start overlapping - # use fixed ratio between number of rows and height of figure - n_ok = 16 - new_height = (fig_width / n_ok) * len(df) - fig.set_size_inches(fig_width, max(fig_min_height, new_height)) - - # Remove empty spaces - fig.tight_layout() - - return axis - -# Run ---------------------------------------------------------------------------------------------- - -class RunCache(list): - RunData = namedtuple("RunData", ["config", "result"]) - - def dump_json(self, filename): - json_data = [{"config": data.config.as_dict(), "output": getattr(data.result, "_output", None) } for data in self] - with open(filename, "w") as f: - json.dump(json_data, f) - - @classmethod - def load_json(cls, filename): - with open(filename, "r") as f: - json_data = json.load(f) - loaded = [] - for data in json_data: - config = BenchmarkConfiguration.from_dict(data["config"]) - result = BenchmarkResult(data["output"]) if data["output"] is not None else None - loaded.append(cls.RunData(config=config, result=result)) - return loaded - - -def run_python(script, args, **kwargs): - command = ["python3", script, *args] - proc = subprocess.run(command, stdout=subprocess.PIPE, cwd=os.path.dirname(script), **kwargs) - return str(proc.stdout) - - -BenchmarkArgs = namedtuple("BenchmarkArgs", ["config", "output_dir", "ignore_failures", "timeout"]) - - -def run_single_benchmark(fargs): - # Run as separate process, because else we cannot capture all output from verilator - print(" {}: {}".format(fargs.config.name, " ".join(fargs.config.as_args()))) - try: - args = fargs.config.as_args() + ["--output-dir", fargs.output_dir, "--log-level", "warning"] - output = run_python(benchmark.__file__, args, timeout=fargs.timeout) - result = BenchmarkResult(output) - # Exit if checker had any read error - if result.checker_errors != 0: - raise RuntimeError("Error during benchmark: checker_errors = {}, args = {}".format( - result.checker_errors, fargs.config.as_args() - )) - except Exception as e: - if fargs.ignore_failures: - print(" {}: ERROR: {}".format(fargs.config.name, e)) - return None - else: - raise - print(" {}: ok".format(fargs.config.name)) - return result - - -InQueueItem = namedtuple("InQueueItem", ["index", "config"]) -OutQueueItem = namedtuple("OutQueueItem", ["index", "result"]) - - -def run_parallel(configurations, output_base_dir, njobs, ignore_failures, timeout): - from multiprocessing import Process, Queue - import queue - - def worker(in_queue, out_queue, out_dir): - while True: - in_item = in_queue.get() - if in_item is None: - return - fargs = BenchmarkArgs(in_item.config, out_dir, ignore_failures, timeout) - result = run_single_benchmark(fargs) - out_queue.put(OutQueueItem(in_item.index, result)) - - if njobs == 0: - njobs = os.cpu_count() - print("Using {:d} parallel jobs".format(njobs)) - - # Use one directory per worker, as running each benchmark in separate directory - # takes too much disk space (~2GB per 100 benchmarks) - dir_pool = [os.path.join(output_base_dir, "worker_%02d" % i) for i in range(njobs)] - - in_queue, out_queue = Queue(), Queue() - workers = [Process(target=worker, args=(in_queue, out_queue, dir)) for dir in dir_pool] - for w in workers: - w.start() - - # Put all benchmark configurations with index to retrieve them in order - for i, config in enumerate(configurations): - in_queue.put(InQueueItem(i, config)) - - # Send "finish signal" for each worker - for _ in workers: - in_queue.put(None) - - # Retrieve results in proper order - out_items = [out_queue.get() for _ in configurations] - results = [out.result for out in sorted(out_items, key=lambda o: o.index)] - - for p in workers: - p.join() - - return results - - -def run_benchmarks(configurations, output_base_dir, njobs, ignore_failures, timeout): - print("Running {:d} benchmarks ...".format(len(configurations))) - if njobs == 1: - results = [run_single_benchmark(BenchmarkArgs(config, output_base_dir, ignore_failures, timeout)) - for config in configurations] - else: - results = run_parallel(configurations, output_base_dir, njobs, ignore_failures, timeout) - run_data = [RunCache.RunData(config, result) for config, result in zip(configurations, results)] - return run_data - - -def main(argv=None): - parser = argparse.ArgumentParser(description="Run LiteDRAM benchmarks and collect the results.") - parser.add_argument("config", help="YAML config file") - parser.add_argument("--names", nargs="*", help="Limit benchmarks to given names") - parser.add_argument("--regex", help="Limit benchmarks to names matching the regex") - parser.add_argument("--not-regex", help="Limit benchmarks to names not matching the regex") - parser.add_argument("--html", action="store_true", help="Generate HTML summary") - parser.add_argument("--html-output-dir", default="html", help="Output directory for generated HTML") - parser.add_argument("--plot", action="store_true", help="Generate plots with results summary") - parser.add_argument("--plot-format", default="png", help="Specify plots file format (default=png)") - parser.add_argument("--plot-backend", default="Agg", help="Optionally specify matplotlib GUI backend") - parser.add_argument("--plot-transparent", action="store_true", help="Use transparent background when saving plots") - parser.add_argument("--plot-output-dir", default="plots", help="Specify where to save the plots") - parser.add_argument("--plot-theme", default="default", help="Use different matplotlib theme") - parser.add_argument("--fail-fast", action="store_true", help="Exit on any benchmark error, do not continue") - parser.add_argument("--output-dir", default="build", help="Directory to store benchmark build output") - parser.add_argument("--njobs", default=0, type=int, help="Use N parallel jobs to run benchmarks (default=0, which uses CPU count)") - parser.add_argument("--heartbeat", default=0, type=int, help="Print heartbeat message with given interval (default=0 => never)") - parser.add_argument("--timeout", default=None, help="Set timeout for a single benchmark") - parser.add_argument("--results-cache", help="""Use given JSON file as results cache. If the file exists, - it will be loaded instead of running actual benchmarks, - else benchmarks will be run normally, and then saved - to the given file. This allows to easily rerun the script - to generate different summary without having to rerun benchmarks.""") - args = parser.parse_args(argv) - - if not args.results_cache and not _summary: - print("Summary not available and not running with --results-cache - run would not produce any results! Aborting.", - file=sys.stderr) - sys.exit(1) - - # Load and filter configurations - configurations = BenchmarkConfiguration.load_yaml(args.config) - filters = { - "regex": lambda config: re.search(args.regex, config.name), - "not_regex": lambda config: not re.search(args.not_regex, config.name), - "names": lambda config: config.name in args.names, - } - for arg, f in filters.items(): - if getattr(args, arg): - configurations = filter(f, configurations) - configurations = list(configurations) - - # Load outputs from cache if it exsits - cache_exists = args.results_cache and os.path.isfile(args.results_cache) - if args.results_cache and cache_exists: - cache = RunCache.load_json(args.results_cache) - - # Take only those that match configurations - names_to_load = [c.name for c in configurations] - run_data = [data for data in cache if data.config.name in names_to_load] - else: # Run all the benchmarks normally - if args.heartbeat: - heartbeat_cmd = ["/bin/sh", "-c", "while true; do sleep %d; echo Heartbeat...; done" % args.heartbeat] - heartbeat = subprocess.Popen(heartbeat_cmd) - if args.timeout is not None: - args.timeout = int(args.timeout) - run_data = run_benchmarks(configurations, args.output_dir, args.njobs, not args.fail_fast, args.timeout) - if args.heartbeat: - heartbeat.kill() - - # Store outputs in cache - if args.results_cache and not cache_exists: - cache = RunCache(run_data) - cache.dump_json(args.results_cache) - - # Display summary - if _summary: - summary = ResultsSummary(run_data) - summary.text_summary() - if args.html: - summary.html_summary(args.html_output_dir) - if args.plot: - summary.plot_summary( - plots_dir=args.plot_output_dir, - backend=args.plot_backend, - theme=args.plot_theme, - save_format=args.plot_format, - transparent=args.plot_transparent, - ) - - # Exit with error when there is no single benchmark that succeeded - succeeded = sum(1 if d.result is not None else 0 for d in run_data) - if succeeded == 0: - sys.exit(1) - -if __name__ == "__main__": - main() diff --git a/test/spd_data/MT16KTF1G64HZ-1G6P1.csv b/test/spd_data/MT16KTF1G64HZ-1G6P1.csv deleted file mode 100644 index 08eb780..0000000 --- a/test/spd_data/MT16KTF1G64HZ-1G6P1.csv +++ /dev/null @@ -1,76 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT16KTF1G64HZ-1G6P1,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT16KTF1G64HZ-1G6P1,1,DDR3-SPD REVISON,13 -MT16KTF1G64HZ-1G6P1,2,DDR3-DRAM DEVICE TYPE,0B -MT16KTF1G64HZ-1G6P1,3,DDR3-MODULE TYPE (FORM FACTOR),03 -MT16KTF1G64HZ-1G6P1,4,DDR3-SDRAM DEVICE DENSITY BANKS,04 -MT16KTF1G64HZ-1G6P1,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,21 -MT16KTF1G64HZ-1G6P1,6,DDR3-MODULE NOMINAL VDD,02 -MT16KTF1G64HZ-1G6P1,7,DDR3-MODULE RANKS DEVICE DQ COUNT,09 -MT16KTF1G64HZ-1G6P1,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,03 -MT16KTF1G64HZ-1G6P1,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,11 -MT16KTF1G64HZ-1G6P1,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT16KTF1G64HZ-1G6P1,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT16KTF1G64HZ-1G6P1,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),0A -MT16KTF1G64HZ-1G6P1,13,DDR3-BYTE 13 RESERVED,00 -MT16KTF1G64HZ-1G6P1,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),FE -MT16KTF1G64HZ-1G6P1,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),00 -MT16KTF1G64HZ-1G6P1,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT16KTF1G64HZ-1G6P1,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT16KTF1G64HZ-1G6P1,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT16KTF1G64HZ-1G6P1,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),30 -MT16KTF1G64HZ-1G6P1,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT16KTF1G64HZ-1G6P1,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT16KTF1G64HZ-1G6P1,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),18 -MT16KTF1G64HZ-1G6P1,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),81 -MT16KTF1G64HZ-1G6P1,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,20 -MT16KTF1G64HZ-1G6P1,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,08 -MT16KTF1G64HZ-1G6P1,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT16KTF1G64HZ-1G6P1,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT16KTF1G64HZ-1G6P1,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT16KTF1G64HZ-1G6P1,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,F0 -MT16KTF1G64HZ-1G6P1,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,83 -MT16KTF1G64HZ-1G6P1,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT16KTF1G64HZ-1G6P1,32,DDR3-MODULE THERMAL SENSOR,00 -MT16KTF1G64HZ-1G6P1,33,DDR3-SDRAM DEVICE TYPE,00 -MT16KTF1G64HZ-1G6P1,34,DDR3-FINE OFFSET FOR TCKMIN,00 -MT16KTF1G64HZ-1G6P1,35,DDR3-FINE OFFSET FOR TAAMIN,00 -MT16KTF1G64HZ-1G6P1,36,DDR3-FINE OFFSET FOR TRCDMIN,00 -MT16KTF1G64HZ-1G6P1,37,DDR3-FINE OFFSET FOR TRPMIN,00 -MT16KTF1G64HZ-1G6P1,38,DDR3-FINE OFFSET FOR TRCMIN,00 -MT16KTF1G64HZ-1G6P1,39,DDR3-BYTE 39 RESERVED,00 -MT16KTF1G64HZ-1G6P1,40,DDR3-BYTE 40 RESERVED,00 -MT16KTF1G64HZ-1G6P1,41,DDR3-PTRR TMAW MAC,88 -MT16KTF1G64HZ-1G6P1,42-59,DDR3-RESERVED BYTES 42-59,000000000000000000000000000000000000 -MT16KTF1G64HZ-1G6P1,60,DDR3-RC REV NOM MODULE HEIGHT,0F -MT16KTF1G64HZ-1G6P1,61,DDR3-MODULE THICKNESS (MAX),11 -MT16KTF1G64HZ-1G6P1,62,DDR3-REFERENCE RAW CARD ID,65 -MT16KTF1G64HZ-1G6P1,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT16KTF1G64HZ-1G6P1,64,DDR3-HEATSPREADER SOLUTION,00 -MT16KTF1G64HZ-1G6P1,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT16KTF1G64HZ-1G6P1,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT16KTF1G64HZ-1G6P1,67,DDR3-REGISTER REVISON NUMBER,00 -MT16KTF1G64HZ-1G6P1,68,DDR3-REGISTER TYPE,00 -MT16KTF1G64HZ-1G6P1,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT16KTF1G64HZ-1G6P1,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT16KTF1G64HZ-1G6P1,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT16KTF1G64HZ-1G6P1,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT16KTF1G64HZ-1G6P1,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT16KTF1G64HZ-1G6P1,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT16KTF1G64HZ-1G6P1,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT16KTF1G64HZ-1G6P1,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT16KTF1G64HZ-1G6P1,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT16KTF1G64HZ-1G6P1,117,DDR3-MODULE MFR ID (LSB),80 -MT16KTF1G64HZ-1G6P1,118,DDR3-MODULE MFR ID (MSB),2C -MT16KTF1G64HZ-1G6P1,119,DDR3-MODULE MFR LOCATION ID,00 -MT16KTF1G64HZ-1G6P1,120,DDR3-MODULE MFR YEAR,00 -MT16KTF1G64HZ-1G6P1,121,DDR3-MODULE MFR WEEK,00 -MT16KTF1G64HZ-1G6P1,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT16KTF1G64HZ-1G6P1,126-127,DDR3-CRC,5759 -MT16KTF1G64HZ-1G6P1,128-145,DDR3-MODULE PART NUMBER,16KTF1G64HZ-1G6P1 -MT16KTF1G64HZ-1G6P1,146,DDR3-MODULE DIE REV,50 -MT16KTF1G64HZ-1G6P1,147,DDR3-MODULE PCB REV,31 -MT16KTF1G64HZ-1G6P1,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT16KTF1G64HZ-1G6P1,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT16KTF1G64HZ-1G6P1,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT16KTF1G64HZ-1G6P1,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/spd_data/MT16KTF1G64HZ-1G9E1.csv b/test/spd_data/MT16KTF1G64HZ-1G9E1.csv deleted file mode 100644 index ac33154..0000000 --- a/test/spd_data/MT16KTF1G64HZ-1G9E1.csv +++ /dev/null @@ -1,76 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT16KTF1G64HZ-1G9E1,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT16KTF1G64HZ-1G9E1,1,DDR3-SPD REVISON,13 -MT16KTF1G64HZ-1G9E1,2,DDR3-DRAM DEVICE TYPE,0B -MT16KTF1G64HZ-1G9E1,3,DDR3-MODULE TYPE (FORM FACTOR),03 -MT16KTF1G64HZ-1G9E1,4,DDR3-SDRAM DEVICE DENSITY BANKS,04 -MT16KTF1G64HZ-1G9E1,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,21 -MT16KTF1G64HZ-1G9E1,6,DDR3-MODULE NOMINAL VDD,02 -MT16KTF1G64HZ-1G9E1,7,DDR3-MODULE RANKS DEVICE DQ COUNT,09 -MT16KTF1G64HZ-1G9E1,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,03 -MT16KTF1G64HZ-1G9E1,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,11 -MT16KTF1G64HZ-1G9E1,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT16KTF1G64HZ-1G9E1,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT16KTF1G64HZ-1G9E1,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),09 -MT16KTF1G64HZ-1G9E1,13,DDR3-BYTE 13 RESERVED,00 -MT16KTF1G64HZ-1G9E1,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),FE -MT16KTF1G64HZ-1G9E1,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),02 -MT16KTF1G64HZ-1G9E1,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT16KTF1G64HZ-1G9E1,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT16KTF1G64HZ-1G9E1,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT16KTF1G64HZ-1G9E1,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),28 -MT16KTF1G64HZ-1G9E1,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT16KTF1G64HZ-1G9E1,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT16KTF1G64HZ-1G9E1,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),10 -MT16KTF1G64HZ-1G9E1,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),79 -MT16KTF1G64HZ-1G9E1,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,20 -MT16KTF1G64HZ-1G9E1,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,08 -MT16KTF1G64HZ-1G9E1,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT16KTF1G64HZ-1G9E1,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT16KTF1G64HZ-1G9E1,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT16KTF1G64HZ-1G9E1,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,D8 -MT16KTF1G64HZ-1G9E1,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,83 -MT16KTF1G64HZ-1G9E1,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT16KTF1G64HZ-1G9E1,32,DDR3-MODULE THERMAL SENSOR,00 -MT16KTF1G64HZ-1G9E1,33,DDR3-SDRAM DEVICE TYPE,00 -MT16KTF1G64HZ-1G9E1,34,DDR3-FINE OFFSET FOR TCKMIN,CA -MT16KTF1G64HZ-1G9E1,35,DDR3-FINE OFFSET FOR TAAMIN,00 -MT16KTF1G64HZ-1G9E1,36,DDR3-FINE OFFSET FOR TRCDMIN,00 -MT16KTF1G64HZ-1G9E1,37,DDR3-FINE OFFSET FOR TRPMIN,00 -MT16KTF1G64HZ-1G9E1,38,DDR3-FINE OFFSET FOR TRCMIN,00 -MT16KTF1G64HZ-1G9E1,39,DDR3-BYTE 39 RESERVED,00 -MT16KTF1G64HZ-1G9E1,40,DDR3-BYTE 40 RESERVED,00 -MT16KTF1G64HZ-1G9E1,41,DDR3-PTRR TMAW MAC,84 -MT16KTF1G64HZ-1G9E1,42-59,DDR3-RESERVED BYTES 42-59,000000000000000000000000000000000000 -MT16KTF1G64HZ-1G9E1,60,DDR3-RC REV NOM MODULE HEIGHT,0F -MT16KTF1G64HZ-1G9E1,61,DDR3-MODULE THICKNESS (MAX),11 -MT16KTF1G64HZ-1G9E1,62,DDR3-REFERENCE RAW CARD ID,05 -MT16KTF1G64HZ-1G9E1,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT16KTF1G64HZ-1G9E1,64,DDR3-HEATSPREADER SOLUTION,00 -MT16KTF1G64HZ-1G9E1,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT16KTF1G64HZ-1G9E1,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT16KTF1G64HZ-1G9E1,67,DDR3-REGISTER REVISON NUMBER,00 -MT16KTF1G64HZ-1G9E1,68,DDR3-REGISTER TYPE,00 -MT16KTF1G64HZ-1G9E1,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT16KTF1G64HZ-1G9E1,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT16KTF1G64HZ-1G9E1,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT16KTF1G64HZ-1G9E1,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT16KTF1G64HZ-1G9E1,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT16KTF1G64HZ-1G9E1,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT16KTF1G64HZ-1G9E1,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT16KTF1G64HZ-1G9E1,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT16KTF1G64HZ-1G9E1,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT16KTF1G64HZ-1G9E1,117,DDR3-MODULE MFR ID (LSB),80 -MT16KTF1G64HZ-1G9E1,118,DDR3-MODULE MFR ID (MSB),2C -MT16KTF1G64HZ-1G9E1,119,DDR3-MODULE MFR LOCATION ID,00 -MT16KTF1G64HZ-1G9E1,120,DDR3-MODULE MFR YEAR,00 -MT16KTF1G64HZ-1G9E1,121,DDR3-MODULE MFR WEEK,00 -MT16KTF1G64HZ-1G9E1,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT16KTF1G64HZ-1G9E1,126-127,DDR3-CRC,DDA5 -MT16KTF1G64HZ-1G9E1,128-145,DDR3-MODULE PART NUMBER,16KTF1G64HZ-1G9E1 -MT16KTF1G64HZ-1G9E1,146,DDR3-MODULE DIE REV,45 -MT16KTF1G64HZ-1G9E1,147,DDR3-MODULE PCB REV,31 -MT16KTF1G64HZ-1G9E1,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT16KTF1G64HZ-1G9E1,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT16KTF1G64HZ-1G9E1,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT16KTF1G64HZ-1G9E1,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/spd_data/MT18KSF1G72HZ-1G4E2.csv b/test/spd_data/MT18KSF1G72HZ-1G4E2.csv deleted file mode 100644 index 76c5e16..0000000 --- a/test/spd_data/MT18KSF1G72HZ-1G4E2.csv +++ /dev/null @@ -1,76 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT18KSF1G72HZ-1G4E2,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT18KSF1G72HZ-1G4E2,1,DDR3-SPD REVISON,13 -MT18KSF1G72HZ-1G4E2,2,DDR3-DRAM DEVICE TYPE,0B -MT18KSF1G72HZ-1G4E2,3,DDR3-MODULE TYPE (FORM FACTOR),08 -MT18KSF1G72HZ-1G4E2,4,DDR3-SDRAM DEVICE DENSITY BANKS,04 -MT18KSF1G72HZ-1G4E2,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,21 -MT18KSF1G72HZ-1G4E2,6,DDR3-MODULE NOMINAL VDD,02 -MT18KSF1G72HZ-1G4E2,7,DDR3-MODULE RANKS DEVICE DQ COUNT,09 -MT18KSF1G72HZ-1G4E2,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,0B -MT18KSF1G72HZ-1G4E2,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,11 -MT18KSF1G72HZ-1G4E2,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT18KSF1G72HZ-1G4E2,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT18KSF1G72HZ-1G4E2,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),0C -MT18KSF1G72HZ-1G4E2,13,DDR3-BYTE 13 RESERVED,00 -MT18KSF1G72HZ-1G4E2,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),7E -MT18KSF1G72HZ-1G4E2,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),00 -MT18KSF1G72HZ-1G4E2,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT18KSF1G72HZ-1G4E2,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT18KSF1G72HZ-1G4E2,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT18KSF1G72HZ-1G4E2,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),30 -MT18KSF1G72HZ-1G4E2,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT18KSF1G72HZ-1G4E2,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT18KSF1G72HZ-1G4E2,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),20 -MT18KSF1G72HZ-1G4E2,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),89 -MT18KSF1G72HZ-1G4E2,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,20 -MT18KSF1G72HZ-1G4E2,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,08 -MT18KSF1G72HZ-1G4E2,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT18KSF1G72HZ-1G4E2,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT18KSF1G72HZ-1G4E2,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT18KSF1G72HZ-1G4E2,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,F0 -MT18KSF1G72HZ-1G4E2,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,83 -MT18KSF1G72HZ-1G4E2,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT18KSF1G72HZ-1G4E2,32,DDR3-MODULE THERMAL SENSOR,80 -MT18KSF1G72HZ-1G4E2,33,DDR3-SDRAM DEVICE TYPE,00 -MT18KSF1G72HZ-1G4E2,34,DDR3-FINE OFFSET FOR TCKMIN,00 -MT18KSF1G72HZ-1G4E2,35,DDR3-FINE OFFSET FOR TAAMIN,00 -MT18KSF1G72HZ-1G4E2,36,DDR3-FINE OFFSET FOR TRCDMIN,00 -MT18KSF1G72HZ-1G4E2,37,DDR3-FINE OFFSET FOR TRPMIN,00 -MT18KSF1G72HZ-1G4E2,38,DDR3-FINE OFFSET FOR TRCMIN,00 -MT18KSF1G72HZ-1G4E2,39,DDR3-BYTE 39 RESERVED,00 -MT18KSF1G72HZ-1G4E2,40,DDR3-BYTE 40 RESERVED,00 -MT18KSF1G72HZ-1G4E2,41,DDR3-PTRR TMAW MAC,84 -MT18KSF1G72HZ-1G4E2,42-59,DDR3-RESERVED BYTES 42-59,000000000000000000000000000000000000 -MT18KSF1G72HZ-1G4E2,60,DDR3-RC REV NOM MODULE HEIGHT,0F -MT18KSF1G72HZ-1G4E2,61,DDR3-MODULE THICKNESS (MAX),11 -MT18KSF1G72HZ-1G4E2,62,DDR3-REFERENCE RAW CARD ID,23 -MT18KSF1G72HZ-1G4E2,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT18KSF1G72HZ-1G4E2,64,DDR3-HEATSPREADER SOLUTION,00 -MT18KSF1G72HZ-1G4E2,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT18KSF1G72HZ-1G4E2,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT18KSF1G72HZ-1G4E2,67,DDR3-REGISTER REVISON NUMBER,00 -MT18KSF1G72HZ-1G4E2,68,DDR3-REGISTER TYPE,00 -MT18KSF1G72HZ-1G4E2,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT18KSF1G72HZ-1G4E2,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT18KSF1G72HZ-1G4E2,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT18KSF1G72HZ-1G4E2,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT18KSF1G72HZ-1G4E2,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT18KSF1G72HZ-1G4E2,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT18KSF1G72HZ-1G4E2,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT18KSF1G72HZ-1G4E2,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT18KSF1G72HZ-1G4E2,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT18KSF1G72HZ-1G4E2,117,DDR3-MODULE MFR ID (LSB),80 -MT18KSF1G72HZ-1G4E2,118,DDR3-MODULE MFR ID (MSB),2C -MT18KSF1G72HZ-1G4E2,119,DDR3-MODULE MFR LOCATION ID,00 -MT18KSF1G72HZ-1G4E2,120,DDR3-MODULE MFR YEAR,00 -MT18KSF1G72HZ-1G4E2,121,DDR3-MODULE MFR WEEK,00 -MT18KSF1G72HZ-1G4E2,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT18KSF1G72HZ-1G4E2,126-127,DDR3-CRC,FCB1 -MT18KSF1G72HZ-1G4E2,128-145,DDR3-MODULE PART NUMBER,18KSF1G72HZ-1G4E2 -MT18KSF1G72HZ-1G4E2,146,DDR3-MODULE DIE REV,45 -MT18KSF1G72HZ-1G4E2,147,DDR3-MODULE PCB REV,32 -MT18KSF1G72HZ-1G4E2,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT18KSF1G72HZ-1G4E2,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT18KSF1G72HZ-1G4E2,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT18KSF1G72HZ-1G4E2,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/spd_data/MT18KSF1G72HZ-1G6E2.csv b/test/spd_data/MT18KSF1G72HZ-1G6E2.csv deleted file mode 100644 index 1cffcf3..0000000 --- a/test/spd_data/MT18KSF1G72HZ-1G6E2.csv +++ /dev/null @@ -1,76 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT18KSF1G72HZ-1G6E2,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT18KSF1G72HZ-1G6E2,1,DDR3-SPD REVISON,13 -MT18KSF1G72HZ-1G6E2,2,DDR3-DRAM DEVICE TYPE,0B -MT18KSF1G72HZ-1G6E2,3,DDR3-MODULE TYPE (FORM FACTOR),08 -MT18KSF1G72HZ-1G6E2,4,DDR3-SDRAM DEVICE DENSITY BANKS,04 -MT18KSF1G72HZ-1G6E2,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,21 -MT18KSF1G72HZ-1G6E2,6,DDR3-MODULE NOMINAL VDD,02 -MT18KSF1G72HZ-1G6E2,7,DDR3-MODULE RANKS DEVICE DQ COUNT,09 -MT18KSF1G72HZ-1G6E2,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,0B -MT18KSF1G72HZ-1G6E2,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,11 -MT18KSF1G72HZ-1G6E2,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT18KSF1G72HZ-1G6E2,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT18KSF1G72HZ-1G6E2,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),0A -MT18KSF1G72HZ-1G6E2,13,DDR3-BYTE 13 RESERVED,00 -MT18KSF1G72HZ-1G6E2,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),FE -MT18KSF1G72HZ-1G6E2,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),00 -MT18KSF1G72HZ-1G6E2,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT18KSF1G72HZ-1G6E2,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT18KSF1G72HZ-1G6E2,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT18KSF1G72HZ-1G6E2,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),30 -MT18KSF1G72HZ-1G6E2,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT18KSF1G72HZ-1G6E2,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT18KSF1G72HZ-1G6E2,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),18 -MT18KSF1G72HZ-1G6E2,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),81 -MT18KSF1G72HZ-1G6E2,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,20 -MT18KSF1G72HZ-1G6E2,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,08 -MT18KSF1G72HZ-1G6E2,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT18KSF1G72HZ-1G6E2,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT18KSF1G72HZ-1G6E2,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT18KSF1G72HZ-1G6E2,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,F0 -MT18KSF1G72HZ-1G6E2,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,83 -MT18KSF1G72HZ-1G6E2,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT18KSF1G72HZ-1G6E2,32,DDR3-MODULE THERMAL SENSOR,80 -MT18KSF1G72HZ-1G6E2,33,DDR3-SDRAM DEVICE TYPE,00 -MT18KSF1G72HZ-1G6E2,34,DDR3-FINE OFFSET FOR TCKMIN,00 -MT18KSF1G72HZ-1G6E2,35,DDR3-FINE OFFSET FOR TAAMIN,00 -MT18KSF1G72HZ-1G6E2,36,DDR3-FINE OFFSET FOR TRCDMIN,00 -MT18KSF1G72HZ-1G6E2,37,DDR3-FINE OFFSET FOR TRPMIN,00 -MT18KSF1G72HZ-1G6E2,38,DDR3-FINE OFFSET FOR TRCMIN,00 -MT18KSF1G72HZ-1G6E2,39,DDR3-BYTE 39 RESERVED,00 -MT18KSF1G72HZ-1G6E2,40,DDR3-BYTE 40 RESERVED,00 -MT18KSF1G72HZ-1G6E2,41,DDR3-PTRR TMAW MAC,84 -MT18KSF1G72HZ-1G6E2,42-59,DDR3-RESERVED BYTES 42-59,000000000000000000000000000000000000 -MT18KSF1G72HZ-1G6E2,60,DDR3-RC REV NOM MODULE HEIGHT,0F -MT18KSF1G72HZ-1G6E2,61,DDR3-MODULE THICKNESS (MAX),11 -MT18KSF1G72HZ-1G6E2,62,DDR3-REFERENCE RAW CARD ID,23 -MT18KSF1G72HZ-1G6E2,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT18KSF1G72HZ-1G6E2,64,DDR3-HEATSPREADER SOLUTION,00 -MT18KSF1G72HZ-1G6E2,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT18KSF1G72HZ-1G6E2,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT18KSF1G72HZ-1G6E2,67,DDR3-REGISTER REVISON NUMBER,00 -MT18KSF1G72HZ-1G6E2,68,DDR3-REGISTER TYPE,00 -MT18KSF1G72HZ-1G6E2,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT18KSF1G72HZ-1G6E2,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT18KSF1G72HZ-1G6E2,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT18KSF1G72HZ-1G6E2,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT18KSF1G72HZ-1G6E2,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT18KSF1G72HZ-1G6E2,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT18KSF1G72HZ-1G6E2,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT18KSF1G72HZ-1G6E2,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT18KSF1G72HZ-1G6E2,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT18KSF1G72HZ-1G6E2,117,DDR3-MODULE MFR ID (LSB),80 -MT18KSF1G72HZ-1G6E2,118,DDR3-MODULE MFR ID (MSB),2C -MT18KSF1G72HZ-1G6E2,119,DDR3-MODULE MFR LOCATION ID,00 -MT18KSF1G72HZ-1G6E2,120,DDR3-MODULE MFR YEAR,00 -MT18KSF1G72HZ-1G6E2,121,DDR3-MODULE MFR WEEK,00 -MT18KSF1G72HZ-1G6E2,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT18KSF1G72HZ-1G6E2,126-127,DDR3-CRC,296F -MT18KSF1G72HZ-1G6E2,128-145,DDR3-MODULE PART NUMBER,18KSF1G72HZ-1G6E2 -MT18KSF1G72HZ-1G6E2,146,DDR3-MODULE DIE REV,45 -MT18KSF1G72HZ-1G6E2,147,DDR3-MODULE PCB REV,32 -MT18KSF1G72HZ-1G6E2,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT18KSF1G72HZ-1G6E2,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT18KSF1G72HZ-1G6E2,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT18KSF1G72HZ-1G6E2,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/spd_data/MT8JTF12864AZ-1G4G1.csv b/test/spd_data/MT8JTF12864AZ-1G4G1.csv deleted file mode 100644 index 4d975f5..0000000 --- a/test/spd_data/MT8JTF12864AZ-1G4G1.csv +++ /dev/null @@ -1,68 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT8JTF12864AZ-1G4G1,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT8JTF12864AZ-1G4G1,1,DDR3-SPD REVISON,10 -MT8JTF12864AZ-1G4G1,2,DDR3-DRAM DEVICE TYPE,0B -MT8JTF12864AZ-1G4G1,3,DDR3-MODULE TYPE (FORM FACTOR),02 -MT8JTF12864AZ-1G4G1,4,DDR3-SDRAM DEVICE DENSITY BANKS,02 -MT8JTF12864AZ-1G4G1,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,11 -MT8JTF12864AZ-1G4G1,6,DDR3-MODULE NOMINAL VDD,00 -MT8JTF12864AZ-1G4G1,7,DDR3-MODULE RANKS DEVICE DQ COUNT,01 -MT8JTF12864AZ-1G4G1,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,03 -MT8JTF12864AZ-1G4G1,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,52 -MT8JTF12864AZ-1G4G1,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT8JTF12864AZ-1G4G1,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT8JTF12864AZ-1G4G1,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),0C -MT8JTF12864AZ-1G4G1,13,DDR3-BYTE 13 RESERVED,00 -MT8JTF12864AZ-1G4G1,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),7E -MT8JTF12864AZ-1G4G1,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),00 -MT8JTF12864AZ-1G4G1,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT8JTF12864AZ-1G4G1,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT8JTF12864AZ-1G4G1,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT8JTF12864AZ-1G4G1,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),30 -MT8JTF12864AZ-1G4G1,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT8JTF12864AZ-1G4G1,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT8JTF12864AZ-1G4G1,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),20 -MT8JTF12864AZ-1G4G1,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),89 -MT8JTF12864AZ-1G4G1,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,70 -MT8JTF12864AZ-1G4G1,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,03 -MT8JTF12864AZ-1G4G1,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT8JTF12864AZ-1G4G1,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT8JTF12864AZ-1G4G1,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT8JTF12864AZ-1G4G1,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,F0 -MT8JTF12864AZ-1G4G1,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,82 -MT8JTF12864AZ-1G4G1,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT8JTF12864AZ-1G4G1,32,DDR3-MODULE THERMAL SENSOR,00 -MT8JTF12864AZ-1G4G1,33,DDR3-SDRAM DEVICE TYPE,00 -MT8JTF12864AZ-1G4G1,34-59,DDR3-RESERVED BYTES 34-59,0000000000000000000000000000000000000000000000000000 -MT8JTF12864AZ-1G4G1,60,DDR3-MODULE HEIGHT (NOMINAL),0F -MT8JTF12864AZ-1G4G1,61,DDR3-MODULE THICKNESS (MAX),01 -MT8JTF12864AZ-1G4G1,62,DDR3-REFERENCE RAW CARD ID,00 -MT8JTF12864AZ-1G4G1,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT8JTF12864AZ-1G4G1,64,DDR3-HEATSPREADER SOLUTION,00 -MT8JTF12864AZ-1G4G1,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT8JTF12864AZ-1G4G1,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT8JTF12864AZ-1G4G1,67,DDR3-REGISTER REVISON NUMBER,00 -MT8JTF12864AZ-1G4G1,68,DDR3-REGISTER TYPE,00 -MT8JTF12864AZ-1G4G1,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT8JTF12864AZ-1G4G1,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT8JTF12864AZ-1G4G1,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT8JTF12864AZ-1G4G1,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT8JTF12864AZ-1G4G1,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT8JTF12864AZ-1G4G1,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT8JTF12864AZ-1G4G1,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT8JTF12864AZ-1G4G1,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT8JTF12864AZ-1G4G1,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT8JTF12864AZ-1G4G1,117,DDR3-MODULE MFR ID (LSB),80 -MT8JTF12864AZ-1G4G1,118,DDR3-MODULE MFR ID (MSB),2C -MT8JTF12864AZ-1G4G1,119,DDR3-MODULE MFR LOCATION ID,00 -MT8JTF12864AZ-1G4G1,120,DDR3-MODULE MFR YEAR,00 -MT8JTF12864AZ-1G4G1,121,DDR3-MODULE MFR WEEK,00 -MT8JTF12864AZ-1G4G1,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT8JTF12864AZ-1G4G1,126-127,DDR3-CRC,1461 -MT8JTF12864AZ-1G4G1,128-145,DDR3-MODULE PART NUMBER,8JTF12864AZ-1G4G1 -MT8JTF12864AZ-1G4G1,146,DDR3-MODULE DIE REV,47 -MT8JTF12864AZ-1G4G1,147,DDR3-MODULE PCB REV,31 -MT8JTF12864AZ-1G4G1,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT8JTF12864AZ-1G4G1,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT8JTF12864AZ-1G4G1,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT8JTF12864AZ-1G4G1,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/spd_data/MT8KTF51264HZ-1G4E1.csv b/test/spd_data/MT8KTF51264HZ-1G4E1.csv deleted file mode 100644 index a710ef0..0000000 --- a/test/spd_data/MT8KTF51264HZ-1G4E1.csv +++ /dev/null @@ -1,76 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT8KTF51264HZ-1G4E1,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT8KTF51264HZ-1G4E1,1,DDR3-SPD REVISON,13 -MT8KTF51264HZ-1G4E1,2,DDR3-DRAM DEVICE TYPE,0B -MT8KTF51264HZ-1G4E1,3,DDR3-MODULE TYPE (FORM FACTOR),03 -MT8KTF51264HZ-1G4E1,4,DDR3-SDRAM DEVICE DENSITY BANKS,04 -MT8KTF51264HZ-1G4E1,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,21 -MT8KTF51264HZ-1G4E1,6,DDR3-MODULE NOMINAL VDD,02 -MT8KTF51264HZ-1G4E1,7,DDR3-MODULE RANKS DEVICE DQ COUNT,01 -MT8KTF51264HZ-1G4E1,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,03 -MT8KTF51264HZ-1G4E1,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,11 -MT8KTF51264HZ-1G4E1,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT8KTF51264HZ-1G4E1,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT8KTF51264HZ-1G4E1,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),0C -MT8KTF51264HZ-1G4E1,13,DDR3-BYTE 13 RESERVED,00 -MT8KTF51264HZ-1G4E1,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),7E -MT8KTF51264HZ-1G4E1,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),00 -MT8KTF51264HZ-1G4E1,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT8KTF51264HZ-1G4E1,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT8KTF51264HZ-1G4E1,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT8KTF51264HZ-1G4E1,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),30 -MT8KTF51264HZ-1G4E1,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT8KTF51264HZ-1G4E1,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT8KTF51264HZ-1G4E1,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),20 -MT8KTF51264HZ-1G4E1,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),89 -MT8KTF51264HZ-1G4E1,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,20 -MT8KTF51264HZ-1G4E1,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,08 -MT8KTF51264HZ-1G4E1,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT8KTF51264HZ-1G4E1,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT8KTF51264HZ-1G4E1,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT8KTF51264HZ-1G4E1,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,F0 -MT8KTF51264HZ-1G4E1,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,83 -MT8KTF51264HZ-1G4E1,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT8KTF51264HZ-1G4E1,32,DDR3-MODULE THERMAL SENSOR,00 -MT8KTF51264HZ-1G4E1,33,DDR3-SDRAM DEVICE TYPE,00 -MT8KTF51264HZ-1G4E1,34,DDR3-FINE OFFSET FOR TCKMIN,00 -MT8KTF51264HZ-1G4E1,35,DDR3-FINE OFFSET FOR TAAMIN,00 -MT8KTF51264HZ-1G4E1,36,DDR3-FINE OFFSET FOR TRCDMIN,00 -MT8KTF51264HZ-1G4E1,37,DDR3-FINE OFFSET FOR TRPMIN,00 -MT8KTF51264HZ-1G4E1,38,DDR3-FINE OFFSET FOR TRCMIN,00 -MT8KTF51264HZ-1G4E1,39,DDR3-BYTE 39 RESERVED,00 -MT8KTF51264HZ-1G4E1,40,DDR3-BYTE 40 RESERVED,00 -MT8KTF51264HZ-1G4E1,41,DDR3-PTRR TMAW MAC,84 -MT8KTF51264HZ-1G4E1,42-59,DDR3-RESERVED BYTES 42-59,000000000000000000000000000000000000 -MT8KTF51264HZ-1G4E1,60,DDR3-RC REV NOM MODULE HEIGHT,0F -MT8KTF51264HZ-1G4E1,61,DDR3-MODULE THICKNESS (MAX),11 -MT8KTF51264HZ-1G4E1,62,DDR3-REFERENCE RAW CARD ID,41 -MT8KTF51264HZ-1G4E1,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT8KTF51264HZ-1G4E1,64,DDR3-HEATSPREADER SOLUTION,00 -MT8KTF51264HZ-1G4E1,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT8KTF51264HZ-1G4E1,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT8KTF51264HZ-1G4E1,67,DDR3-REGISTER REVISON NUMBER,00 -MT8KTF51264HZ-1G4E1,68,DDR3-REGISTER TYPE,00 -MT8KTF51264HZ-1G4E1,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT8KTF51264HZ-1G4E1,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT8KTF51264HZ-1G4E1,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT8KTF51264HZ-1G4E1,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT8KTF51264HZ-1G4E1,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT8KTF51264HZ-1G4E1,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT8KTF51264HZ-1G4E1,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT8KTF51264HZ-1G4E1,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT8KTF51264HZ-1G4E1,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT8KTF51264HZ-1G4E1,117,DDR3-MODULE MFR ID (LSB),80 -MT8KTF51264HZ-1G4E1,118,DDR3-MODULE MFR ID (MSB),2C -MT8KTF51264HZ-1G4E1,119,DDR3-MODULE MFR LOCATION ID,00 -MT8KTF51264HZ-1G4E1,120,DDR3-MODULE MFR YEAR,00 -MT8KTF51264HZ-1G4E1,121,DDR3-MODULE MFR WEEK,00 -MT8KTF51264HZ-1G4E1,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT8KTF51264HZ-1G4E1,126-127,DDR3-CRC,3D17 -MT8KTF51264HZ-1G4E1,128-145,DDR3-MODULE PART NUMBER,8KTF51264HZ-1G4E1 -MT8KTF51264HZ-1G4E1,146,DDR3-MODULE DIE REV,45 -MT8KTF51264HZ-1G4E1,147,DDR3-MODULE PCB REV,31 -MT8KTF51264HZ-1G4E1,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT8KTF51264HZ-1G4E1,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT8KTF51264HZ-1G4E1,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT8KTF51264HZ-1G4E1,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/spd_data/MT8KTF51264HZ-1G6E1.csv b/test/spd_data/MT8KTF51264HZ-1G6E1.csv deleted file mode 100644 index 0bb0cbd..0000000 --- a/test/spd_data/MT8KTF51264HZ-1G6E1.csv +++ /dev/null @@ -1,76 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT8KTF51264HZ-1G6E1,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT8KTF51264HZ-1G6E1,1,DDR3-SPD REVISON,13 -MT8KTF51264HZ-1G6E1,2,DDR3-DRAM DEVICE TYPE,0B -MT8KTF51264HZ-1G6E1,3,DDR3-MODULE TYPE (FORM FACTOR),03 -MT8KTF51264HZ-1G6E1,4,DDR3-SDRAM DEVICE DENSITY BANKS,04 -MT8KTF51264HZ-1G6E1,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,21 -MT8KTF51264HZ-1G6E1,6,DDR3-MODULE NOMINAL VDD,02 -MT8KTF51264HZ-1G6E1,7,DDR3-MODULE RANKS DEVICE DQ COUNT,01 -MT8KTF51264HZ-1G6E1,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,03 -MT8KTF51264HZ-1G6E1,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,11 -MT8KTF51264HZ-1G6E1,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT8KTF51264HZ-1G6E1,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT8KTF51264HZ-1G6E1,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),0A -MT8KTF51264HZ-1G6E1,13,DDR3-BYTE 13 RESERVED,00 -MT8KTF51264HZ-1G6E1,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),FE -MT8KTF51264HZ-1G6E1,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),00 -MT8KTF51264HZ-1G6E1,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT8KTF51264HZ-1G6E1,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT8KTF51264HZ-1G6E1,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT8KTF51264HZ-1G6E1,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),30 -MT8KTF51264HZ-1G6E1,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT8KTF51264HZ-1G6E1,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT8KTF51264HZ-1G6E1,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),18 -MT8KTF51264HZ-1G6E1,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),81 -MT8KTF51264HZ-1G6E1,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,20 -MT8KTF51264HZ-1G6E1,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,08 -MT8KTF51264HZ-1G6E1,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT8KTF51264HZ-1G6E1,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT8KTF51264HZ-1G6E1,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT8KTF51264HZ-1G6E1,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,F0 -MT8KTF51264HZ-1G6E1,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,83 -MT8KTF51264HZ-1G6E1,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT8KTF51264HZ-1G6E1,32,DDR3-MODULE THERMAL SENSOR,00 -MT8KTF51264HZ-1G6E1,33,DDR3-SDRAM DEVICE TYPE,00 -MT8KTF51264HZ-1G6E1,34,DDR3-FINE OFFSET FOR TCKMIN,00 -MT8KTF51264HZ-1G6E1,35,DDR3-FINE OFFSET FOR TAAMIN,00 -MT8KTF51264HZ-1G6E1,36,DDR3-FINE OFFSET FOR TRCDMIN,00 -MT8KTF51264HZ-1G6E1,37,DDR3-FINE OFFSET FOR TRPMIN,00 -MT8KTF51264HZ-1G6E1,38,DDR3-FINE OFFSET FOR TRCMIN,00 -MT8KTF51264HZ-1G6E1,39,DDR3-BYTE 39 RESERVED,00 -MT8KTF51264HZ-1G6E1,40,DDR3-BYTE 40 RESERVED,00 -MT8KTF51264HZ-1G6E1,41,DDR3-PTRR TMAW MAC,84 -MT8KTF51264HZ-1G6E1,42-59,DDR3-RESERVED BYTES 42-59,000000000000000000000000000000000000 -MT8KTF51264HZ-1G6E1,60,DDR3-RC REV NOM MODULE HEIGHT,0F -MT8KTF51264HZ-1G6E1,61,DDR3-MODULE THICKNESS (MAX),11 -MT8KTF51264HZ-1G6E1,62,DDR3-REFERENCE RAW CARD ID,41 -MT8KTF51264HZ-1G6E1,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT8KTF51264HZ-1G6E1,64,DDR3-HEATSPREADER SOLUTION,00 -MT8KTF51264HZ-1G6E1,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT8KTF51264HZ-1G6E1,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT8KTF51264HZ-1G6E1,67,DDR3-REGISTER REVISON NUMBER,00 -MT8KTF51264HZ-1G6E1,68,DDR3-REGISTER TYPE,00 -MT8KTF51264HZ-1G6E1,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT8KTF51264HZ-1G6E1,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT8KTF51264HZ-1G6E1,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT8KTF51264HZ-1G6E1,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT8KTF51264HZ-1G6E1,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT8KTF51264HZ-1G6E1,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT8KTF51264HZ-1G6E1,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT8KTF51264HZ-1G6E1,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT8KTF51264HZ-1G6E1,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT8KTF51264HZ-1G6E1,117,DDR3-MODULE MFR ID (LSB),80 -MT8KTF51264HZ-1G6E1,118,DDR3-MODULE MFR ID (MSB),2C -MT8KTF51264HZ-1G6E1,119,DDR3-MODULE MFR LOCATION ID,00 -MT8KTF51264HZ-1G6E1,120,DDR3-MODULE MFR YEAR,00 -MT8KTF51264HZ-1G6E1,121,DDR3-MODULE MFR WEEK,00 -MT8KTF51264HZ-1G6E1,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT8KTF51264HZ-1G6E1,126-127,DDR3-CRC,E8C9 -MT8KTF51264HZ-1G6E1,128-145,DDR3-MODULE PART NUMBER,8KTF51264HZ-1G6E1 -MT8KTF51264HZ-1G6E1,146,DDR3-MODULE DIE REV,45 -MT8KTF51264HZ-1G6E1,147,DDR3-MODULE PCB REV,31 -MT8KTF51264HZ-1G6E1,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT8KTF51264HZ-1G6E1,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT8KTF51264HZ-1G6E1,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT8KTF51264HZ-1G6E1,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/spd_data/MT8KTF51264HZ-1G9P1.csv b/test/spd_data/MT8KTF51264HZ-1G9P1.csv deleted file mode 100644 index cd7a7ef..0000000 --- a/test/spd_data/MT8KTF51264HZ-1G9P1.csv +++ /dev/null @@ -1,76 +0,0 @@ -Part Number,Byte Number,Byte Description,Byte Value -MT8KTF51264HZ-1G9P1,0,DDR3-CRC RANGE; EEPROM BYTES; BYTES USED,92 -MT8KTF51264HZ-1G9P1,1,DDR3-SPD REVISON,13 -MT8KTF51264HZ-1G9P1,2,DDR3-DRAM DEVICE TYPE,0B -MT8KTF51264HZ-1G9P1,3,DDR3-MODULE TYPE (FORM FACTOR),03 -MT8KTF51264HZ-1G9P1,4,DDR3-SDRAM DEVICE DENSITY BANKS,04 -MT8KTF51264HZ-1G9P1,5,DDR3-SDRAM DEVICE ROW COLUMN COUNT,21 -MT8KTF51264HZ-1G9P1,6,DDR3-MODULE NOMINAL VDD,02 -MT8KTF51264HZ-1G9P1,7,DDR3-MODULE RANKS DEVICE DQ COUNT,01 -MT8KTF51264HZ-1G9P1,8,DDR3-ECC TAG MODULE MEMORY BUS WIDTH,03 -MT8KTF51264HZ-1G9P1,9,DDR3-FINE TIMEBASE DIVIDEND/DIVISOR,11 -MT8KTF51264HZ-1G9P1,10,DDR3-MEDIUM TIMEBASE DIVIDEND,01 -MT8KTF51264HZ-1G9P1,11,DDR3-MEDIUM TIMEBASE DIVISOR,08 -MT8KTF51264HZ-1G9P1,12,DDR3-MIN SDRAM CYCLE TIME (TCKMIN),09 -MT8KTF51264HZ-1G9P1,13,DDR3-BYTE 13 RESERVED,00 -MT8KTF51264HZ-1G9P1,14,DDR3-CAS LATENCIES SUPPORTED (CL4 => CL11),FE -MT8KTF51264HZ-1G9P1,15,DDR3-CAS LATENCIES SUPPORTED (CL12 => CL18),02 -MT8KTF51264HZ-1G9P1,16,DDR3-MIN CAS LATENCY TIME (TAAMIN),69 -MT8KTF51264HZ-1G9P1,17,DDR3-MIN WRITE RECOVERY TIME (TWRMIN),78 -MT8KTF51264HZ-1G9P1,18,DDR3-MIN RAS# TO CAS# DELAY (TRCDMIN),69 -MT8KTF51264HZ-1G9P1,19,DDR3-MIN ROW ACTIVE TO ROW ACTIVE DELAY (TRRDMIN),28 -MT8KTF51264HZ-1G9P1,20,DDR3-MIN ROW PRECHARGE DELAY (TRPMIN),69 -MT8KTF51264HZ-1G9P1,21,DDR3-UPPER NIBBLE FOR TRAS TRC,11 -MT8KTF51264HZ-1G9P1,22,DDR3-MIN ACTIVE TO PRECHARGE DELAY (TRASMIN),10 -MT8KTF51264HZ-1G9P1,23,DDR3-MIN ACTIVE TO ACTIVE/REFRESH DELAY (TRCMIN),79 -MT8KTF51264HZ-1G9P1,24,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) LSB,20 -MT8KTF51264HZ-1G9P1,25,DDR3-MIN REFRESH RECOVERY DELAY (TRFCMIN) MSB,08 -MT8KTF51264HZ-1G9P1,26,DDR3-MIN INTERNAL WRITE TO READ CMD DELAY (TWTRMIN),3C -MT8KTF51264HZ-1G9P1,27,DDR3-MIN INTERNAL READ TO PRECHARGE CMD DELAY (TRTPMIN),3C -MT8KTF51264HZ-1G9P1,28,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) MSB,00 -MT8KTF51264HZ-1G9P1,29,DDR3-MIN FOUR ACTIVE WINDOW DELAY (TFAWMIN) LSB,D8 -MT8KTF51264HZ-1G9P1,30,DDR3-SDRAM DEVICE OUTPUT DRIVERS SUPPORTED,83 -MT8KTF51264HZ-1G9P1,31,DDR3-SDRAM DEVICE THERMAL REFRESH OPTIONS,05 -MT8KTF51264HZ-1G9P1,32,DDR3-MODULE THERMAL SENSOR,00 -MT8KTF51264HZ-1G9P1,33,DDR3-SDRAM DEVICE TYPE,00 -MT8KTF51264HZ-1G9P1,34,DDR3-FINE OFFSET FOR TCKMIN,CA -MT8KTF51264HZ-1G9P1,35,DDR3-FINE OFFSET FOR TAAMIN,00 -MT8KTF51264HZ-1G9P1,36,DDR3-FINE OFFSET FOR TRCDMIN,00 -MT8KTF51264HZ-1G9P1,37,DDR3-FINE OFFSET FOR TRPMIN,00 -MT8KTF51264HZ-1G9P1,38,DDR3-FINE OFFSET FOR TRCMIN,00 -MT8KTF51264HZ-1G9P1,39,DDR3-BYTE 39 RESERVED,00 -MT8KTF51264HZ-1G9P1,40,DDR3-BYTE 40 RESERVED,00 -MT8KTF51264HZ-1G9P1,41,DDR3-PTRR TMAW MAC,88 -MT8KTF51264HZ-1G9P1,42-59,DDR3-RESERVED BYTES 42-59,000000000000000000000000000000000000 -MT8KTF51264HZ-1G9P1,60,DDR3-RC REV NOM MODULE HEIGHT,0F -MT8KTF51264HZ-1G9P1,61,DDR3-MODULE THICKNESS (MAX),11 -MT8KTF51264HZ-1G9P1,62,DDR3-REFERENCE RAW CARD ID,01 -MT8KTF51264HZ-1G9P1,63,DDR3 - ADDRESS MAPPING/MODULE ATTRIBUTES,00 -MT8KTF51264HZ-1G9P1,64,DDR3-HEATSPREADER SOLUTION,00 -MT8KTF51264HZ-1G9P1,65,DDR3-REGISTER VENDOR ID (LSB),00 -MT8KTF51264HZ-1G9P1,66,DDR3-REGISTER VENDOR ID (MSB),00 -MT8KTF51264HZ-1G9P1,67,DDR3-REGISTER REVISON NUMBER,00 -MT8KTF51264HZ-1G9P1,68,DDR3-REGISTER TYPE,00 -MT8KTF51264HZ-1G9P1,69,DDR3-REG CTRL WORDS 1 AND ZERO,00 -MT8KTF51264HZ-1G9P1,70,DDR3-REG CTRL WORDS 3 AND 2,00 -MT8KTF51264HZ-1G9P1,71,DDR3-REG CTRL WORDS 5 AND 4,00 -MT8KTF51264HZ-1G9P1,72,DDR3-REG CTRL WORDS 7 AND 6,00 -MT8KTF51264HZ-1G9P1,73,DDR3-REG CTRL WORDS 9 AND 8,00 -MT8KTF51264HZ-1G9P1,74,DDR3-REG CTRL WORDS 11 AND 10,00 -MT8KTF51264HZ-1G9P1,75,DDR3-REG CTRL WORDS 13 AND 12,00 -MT8KTF51264HZ-1G9P1,76,DDR3-REG CTRL WORDS 15 AND 14,00 -MT8KTF51264HZ-1G9P1,77-116,DDR3-RESERVED BYTES 77-116,00000000000000000000000000000000000000000000000000000000000000000000000000000000 -MT8KTF51264HZ-1G9P1,117,DDR3-MODULE MFR ID (LSB),80 -MT8KTF51264HZ-1G9P1,118,DDR3-MODULE MFR ID (MSB),2C -MT8KTF51264HZ-1G9P1,119,DDR3-MODULE MFR LOCATION ID,00 -MT8KTF51264HZ-1G9P1,120,DDR3-MODULE MFR YEAR,00 -MT8KTF51264HZ-1G9P1,121,DDR3-MODULE MFR WEEK,00 -MT8KTF51264HZ-1G9P1,122-125,DDR3-MODULE SERIAL NUMBER,00000000 -MT8KTF51264HZ-1G9P1,126-127,DDR3-CRC,46D3 -MT8KTF51264HZ-1G9P1,128-145,DDR3-MODULE PART NUMBER,8KTF51264HZ-1G9P1 -MT8KTF51264HZ-1G9P1,146,DDR3-MODULE DIE REV,50 -MT8KTF51264HZ-1G9P1,147,DDR3-MODULE PCB REV,31 -MT8KTF51264HZ-1G9P1,148,DDR3-DRAM DEVICE MFR ID (LSB),80 -MT8KTF51264HZ-1G9P1,149,DDR3-DRAM DEVICE MFR (MSB),2C -MT8KTF51264HZ-1G9P1,150-175,DDR3-MFR RESERVED BYTES 150-175,0000000000000000000000000000000000000000000000000000 -MT8KTF51264HZ-1G9P1,176-255,DDR3-CUSTOMER RESERVED BYTES 176-255,FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF \ No newline at end of file diff --git a/test/summary/summary.css b/test/summary/summary.css deleted file mode 100644 index 400225f..0000000 --- a/test/summary/summary.css +++ /dev/null @@ -1,100 +0,0 @@ -body { - font-family: 'Roboto', sans-serif; -} - -footer { - text-align: center; - font-size: 10px; - padding: 20px; -} - -.dataTables_filter { - margin: 15px 50px 10px 50px; -} - -.dataTables_filter input { - width: 400px; -} - -.table-select { - width: 100%; - margin: 0 auto; -} - -.table-select ul { - list-style-type: none; - margin: 0; - padding: 0; - overflow: hidden; -} - -.table-select li { - float: left; -} - -.table-select li a { - display: block; - padding: 10px 0px; - margin: 0px 20px; - text-align: center; - text-decoration: none; - font-size: 18px; - color:inherit; - border-bottom: 1px solid; - border-color: #ccc; - transition: 0.2s; -} - -.table-select li a:hover { - border-color: #111; -} - -/* did not work, .focus() couldn't turn it on */ -/* .table-select li a:focus { */ -/* border-color: #222; */ -/* } */ -.table-select-active { - border-color: #111 !important; -} - -.tables-wrapper { - width: 100%; - margin: auto; -} - -.loading { - z-index: 999; - position: absolute; - top: 50%; - left: 50%; - margin-right: -50%; - transform: translate(-50%, -50%); -} - -/* Loading animation */ -.lds-dual-ring { - display: inline-block; - width: 80px; - height: 80px; -} -.lds-dual-ring:after { - content: " "; - display: block; - width: 64px; - height: 64px; - margin: 8px; - border-radius: 50%; - border: 6px solid #fff; - border-color: #aaa transparent #aaa transparent; - animation: lds-dual-ring 1.2s linear infinite; -} -@keyframes lds-dual-ring { - 0% { - transform: rotate(0deg); - } - 100% { - transform: rotate(360deg); - } -} - -/* vim: set ts=2 sw=2: */ diff --git a/test/summary/summary.html.jinja2 b/test/summary/summary.html.jinja2 deleted file mode 100644 index 4480e6c..0000000 --- a/test/summary/summary.html.jinja2 +++ /dev/null @@ -1,160 +0,0 @@ - - - - - - {{ title }} - - - - - - - - - - - - {# Loading symbol that gets hidden after initialisation of all tables #} -
- - {# Bar for selecting the current data table #} -
-
    - {% for id, name in names.items() %} -
  • {{ name }}
  • - {% endfor %} -
- {#
#} -
- - {# Display of the current data table #} -
- {% for id, table in tables.items() %} - {# Hide tables not to show them before all DataTables are loaded #} - - {% endfor %} -
- - - - - {# Script last, so that for large tables we get some content on the page before loading tables #} - - -{# vim: set ts=2 sts=2 sw=2 et: #} diff --git a/test/test_adaptation.py b/test/test_adaptation.py deleted file mode 100644 index e407d4c..0000000 --- a/test/test_adaptation.py +++ /dev/null @@ -1,283 +0,0 @@ -# This file is Copyright (c) 2017-2019 Florent Kermarrec -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest - -from migen import * - -from litex.soc.interconnect.stream import * - -from litedram.common import LiteDRAMNativeWritePort, LiteDRAMNativeReadPort -from litedram.frontend.adaptation import LiteDRAMNativePortConverter, LiteDRAMNativePortCDC - -from test.common import * - -from litex.gen.sim import * - - -class ConverterDUT(Module): - def __init__(self, user_data_width, native_data_width, mem_depth): - self.write_user_port = LiteDRAMNativeWritePort(address_width=32, data_width=user_data_width) - self.write_crossbar_port = LiteDRAMNativeWritePort(address_width=32, data_width=native_data_width) - self.read_user_port = LiteDRAMNativeReadPort( address_width=32, data_width=user_data_width) - self.read_crossbar_port = LiteDRAMNativeReadPort( address_width=32, data_width=native_data_width) - - # Memory - self.memory = DRAMMemory(native_data_width, mem_depth) - - def do_finalize(self): - self.submodules.write_converter = LiteDRAMNativePortConverter( - self.write_user_port, self.write_crossbar_port) - self.submodules.read_converter = LiteDRAMNativePortConverter( - self.read_user_port, self.read_crossbar_port) - - def read(self, address, read_data=True): - port = self.read_user_port - yield port.cmd.valid.eq(1) - yield port.cmd.we.eq(0) - yield port.cmd.addr.eq(address) - yield - while (yield port.cmd.ready) == 0: - yield - yield port.cmd.valid.eq(0) - yield - if read_data: - while (yield port.rdata.valid) == 0: - yield - data = (yield port.rdata.data) - yield port.rdata.ready.eq(1) - yield - yield port.rdata.ready.eq(0) - yield - return data - - def write(self, address, data, we=None): - if we is None: - we = 2**self.write_user_port.wdata.we.nbits - 1 - if self.write_user_port.data_width > self.write_crossbar_port.data_width: - yield from self._write_down(address, data, we) - else: - yield from self._write_up(address, data, we) - - def _write_up(self, address, data, we): - port = self.write_user_port - yield port.cmd.valid.eq(1) - yield port.cmd.we.eq(1) - yield port.cmd.addr.eq(address) - yield - while (yield port.cmd.ready) == 0: - yield - yield port.cmd.valid.eq(0) - yield - yield port.wdata.valid.eq(1) - yield port.wdata.data.eq(data) - yield port.wdata.we.eq(we) - yield - while (yield port.wdata.ready) == 0: - yield - yield port.wdata.valid.eq(0) - yield - - def _write_down(self, address, data, we): - # Down converter must have all the data available along with cmd, it will set - # user_port.cmd.ready only when it sends all input words. - port = self.write_user_port - yield port.cmd.valid.eq(1) - yield port.cmd.we.eq(1) - yield port.cmd.addr.eq(address) - yield port.wdata.valid.eq(1) - yield port.wdata.data.eq(data) - yield port.wdata.we.eq(we) - yield - # Ready goes up only after StrideConverter copied all words - while (yield port.cmd.ready) == 0: - yield - yield port.cmd.valid.eq(0) - yield - while (yield port.wdata.ready) == 0: - yield - yield port.wdata.valid.eq(0) - yield - - -class CDCDUT(ConverterDUT): - def do_finalize(self): - # Change clock domains - self.write_user_port.clock_domain = "user" - self.read_user_port.clock_domain = "user" - self.write_crossbar_port.clock_domain = "native" - self.read_crossbar_port.clock_domain = "native" - - # Add CDC - self.submodules.write_converter = LiteDRAMNativePortCDC( - port_from = self.write_user_port, - port_to = self.write_crossbar_port) - self.submodules.read_converter = LiteDRAMNativePortCDC( - port_from = self.read_user_port, - port_to = self.read_crossbar_port) - - -class TestAdaptation(MemoryTestDataMixin, unittest.TestCase): - def test_converter_down_ratio_must_be_integer(self): - with self.assertRaises(ValueError) as cm: - dut = ConverterDUT(user_data_width=64, native_data_width=24, mem_depth=128) - dut.finalize() - self.assertIn("ratio must be an int", str(cm.exception).lower()) - - def test_converter_up_ratio_must_be_integer(self): - with self.assertRaises(ValueError) as cm: - dut = ConverterDUT(user_data_width=32, native_data_width=48, mem_depth=128) - dut.finalize() - self.assertIn("ratio must be an int", str(cm.exception).lower()) - - def converter_readback_test(self, dut, pattern, mem_expected): - assert len(set(adr for adr, _ in pattern)) == len(pattern), "Pattern has duplicates!" - read_data = [] - - @passive - def read_handler(read_port): - yield read_port.rdata.ready.eq(1) - while True: - if (yield read_port.rdata.valid): - read_data.append((yield read_port.rdata.data)) - yield - - def main_generator(dut, pattern): - for adr, data in pattern: - yield from dut.write(adr, data) - - for adr, _ in pattern: - yield from dut.read(adr, read_data=False) - - # Latency delay - for _ in range(32): - yield - - generators = [ - main_generator(dut, pattern), - read_handler(dut.read_user_port), - dut.memory.write_handler(dut.write_crossbar_port), - dut.memory.read_handler(dut.read_crossbar_port), - timeout_generator(5000), - ] - run_simulation(dut, generators) - self.assertEqual(dut.memory.mem, mem_expected) - self.assertEqual(read_data, [data for adr, data in pattern]) - - def test_converter_1to1(self): - # Verify 64-bit to 64-bit identify-conversion. - data = self.pattern_test_data["64bit"] - dut = ConverterDUT(user_data_width=64, native_data_width=64, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - def test_converter_2to1(self): - # Verify 64-bit to 32-bit down-conversion. - data = self.pattern_test_data["64bit_to_32bit"] - dut = ConverterDUT(user_data_width=64, native_data_width=32, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - def test_converter_4to1(self): - # Verify 32-bit to 8-bit down-conversion. - data = self.pattern_test_data["32bit_to_8bit"] - dut = ConverterDUT(user_data_width=32, native_data_width=8, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - def test_converter_8to1(self): - # Verify 64-bit to 8-bit down-conversion. - data = self.pattern_test_data["64bit_to_8bit"] - dut = ConverterDUT(user_data_width=64, native_data_width=8, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - def test_converter_1to2(self): - # Verify 8-bit to 16-bit up-conversion. - data = self.pattern_test_data["8bit_to_16bit"] - dut = ConverterDUT(user_data_width=8, native_data_width=16, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - def test_converter_1to4(self): - # Verify 32-bit to 128-bit up-conversion. - data = self.pattern_test_data["32bit_to_128bit"] - dut = ConverterDUT(user_data_width=32, native_data_width=128, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - def test_converter_1to8(self): - # Verify 32-bit to 256-bit up-conversion. - data = self.pattern_test_data["32bit_to_256bit"] - dut = ConverterDUT(user_data_width=32, native_data_width=256, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - # TODO: implement case when user does not write all words (LiteDRAMNativeWritePortUpConverter) - @unittest.skip("Only full-burst writes currently supported") - def test_converter_up_not_aligned(self): - data = self.pattern_test_data["8bit_to_32bit_not_aligned"] - dut = ConverterDUT(user_data_width=8, native_data_width=32, mem_depth=len(data["expected"])) - self.converter_readback_test(dut, data["pattern"], data["expected"]) - - def cdc_readback_test(self, dut, pattern, mem_expected, clocks): - assert len(set(adr for adr, _ in pattern)) == len(pattern), "Pattern has duplicates!" - read_data = [] - - @passive - def read_handler(read_port): - yield read_port.rdata.ready.eq(1) - while True: - if (yield read_port.rdata.valid): - read_data.append((yield read_port.rdata.data)) - yield - - def main_generator(dut, pattern): - for adr, data in pattern: - yield from dut.write(adr, data) - - for adr, _ in pattern: - yield from dut.read(adr, read_data=False) - - # Latency delay - for _ in range(32): - yield - - generators = { - "user": [ - main_generator(dut, pattern), - read_handler(dut.read_user_port), - timeout_generator(5000), - ], - "native": [ - dut.memory.write_handler(dut.write_crossbar_port), - dut.memory.read_handler(dut.read_crossbar_port), - ], - } - run_simulation(dut, generators, clocks) - self.assertEqual(dut.memory.mem, mem_expected) - self.assertEqual(read_data, [data for adr, data in pattern]) - - def test_port_cdc_same_clocks(self): - # Verify CDC with same clocks (frequency and phase). - data = self.pattern_test_data["32bit"] - dut = CDCDUT(user_data_width=32, native_data_width=32, mem_depth=len(data["expected"])) - clocks = { - "user": 10, - "native": (7, 3), - } - self.cdc_readback_test(dut, data["pattern"], data["expected"], clocks=clocks) - - def test_port_cdc_different_period(self): - # Verify CDC with different clock frequencies. - data = self.pattern_test_data["32bit"] - dut = CDCDUT(user_data_width=32, native_data_width=32, mem_depth=len(data["expected"])) - clocks = { - "user": 10, - "native": 7, - } - self.cdc_readback_test(dut, data["pattern"], data["expected"], clocks=clocks) - - def test_port_cdc_out_of_phase(self): - # Verify CDC with different clock phases. - data = self.pattern_test_data["32bit"] - dut = CDCDUT(user_data_width=32, native_data_width=32, mem_depth=len(data["expected"])) - clocks = { - "user": 10, - "native": (7, 3), - } - self.cdc_readback_test(dut, data["pattern"], data["expected"], clocks=clocks) diff --git a/test/test_axi.py b/test/test_axi.py deleted file mode 100644 index df9eb1d..0000000 --- a/test/test_axi.py +++ /dev/null @@ -1,275 +0,0 @@ -# This file is Copyright (c) 2018-2019 Florent Kermarrec -# License: BSD - -import unittest -import random - -from migen import * - -from litedram.common import * -from litedram.frontend.axi import * - -from test.common import * - -from litex.gen.sim import * - - -class Burst: - def __init__(self, addr, type=BURST_FIXED, len=0, size=0): - self.addr = addr - self.type = type - self.len = len - self.size = size - - def to_beats(self): - r = [] - for i in range(self.len + 1): - if self.type == BURST_INCR: - offset = i*2**(self.size) - r += [Beat(self.addr + offset)] - elif self.type == BURST_WRAP: - offset = (i*2**(self.size))%((2**self.size)*(self.len)) - r += [Beat(self.addr + offset)] - else: - r += [Beat(self.addr)] - return r - - -class Beat: - def __init__(self, addr): - self.addr = addr - - -class Access(Burst): - def __init__(self, addr, data, id, **kwargs): - Burst.__init__(self, addr, **kwargs) - self.data = data - self.id = id - - -class Write(Access): - pass - - -class Read(Access): - pass - - -class TestAXI(unittest.TestCase): - def _test_axi2native(self, - naccesses=16, simultaneous_writes_reads=False, - # Random: 0: min (no random), 100: max. - # Burst randomness - id_rand_enable = False, - len_rand_enable = False, - data_rand_enable = False, - # Flow valid randomness - aw_valid_random = 0, - w_valid_random = 0, - ar_valid_random = 0, - r_valid_random = 0, - # Flow ready randomness - w_ready_random = 0, - b_ready_random = 0, - r_ready_random = 0 - ): - - def writes_cmd_generator(axi_port, writes): - prng = random.Random(42) - for write in writes: - while prng.randrange(100) < aw_valid_random: - yield - # Send command - yield axi_port.aw.valid.eq(1) - yield axi_port.aw.addr.eq(write.addr<<2) - yield axi_port.aw.burst.eq(write.type) - yield axi_port.aw.len.eq(write.len) - yield axi_port.aw.size.eq(write.size) - yield axi_port.aw.id.eq(write.id) - yield - while (yield axi_port.aw.ready) == 0: - yield - yield axi_port.aw.valid.eq(0) - - def writes_data_generator(axi_port, writes): - prng = random.Random(42) - for write in writes: - for i, data in enumerate(write.data): - while prng.randrange(100) < w_valid_random: - yield - # Send data - yield axi_port.w.valid.eq(1) - if (i == (len(write.data) - 1)): - yield axi_port.w.last.eq(1) - else: - yield axi_port.w.last.eq(0) - yield axi_port.w.data.eq(data) - yield axi_port.w.strb.eq(2**axi_port.w.strb.nbits - 1) - yield - while (yield axi_port.w.ready) == 0: - yield - yield axi_port.w.valid.eq(0) - axi_port.reads_enable = True - - def writes_response_generator(axi_port, writes): - prng = random.Random(42) - self.writes_id_errors = 0 - for write in writes: - # Wait response - yield axi_port.b.ready.eq(0) - yield - while (yield axi_port.b.valid) == 0: - yield - while prng.randrange(100) < b_ready_random: - yield - yield axi_port.b.ready.eq(1) - yield - if (yield axi_port.b.id) != write.id: - self.writes_id_errors += 1 - - def reads_cmd_generator(axi_port, reads): - prng = random.Random(42) - while not axi_port.reads_enable: - yield - for read in reads: - while prng.randrange(100) < ar_valid_random: - yield - # Send command - yield axi_port.ar.valid.eq(1) - yield axi_port.ar.addr.eq(read.addr<<2) - yield axi_port.ar.burst.eq(read.type) - yield axi_port.ar.len.eq(read.len) - yield axi_port.ar.size.eq(read.size) - yield axi_port.ar.id.eq(read.id) - yield - while (yield axi_port.ar.ready) == 0: - yield - yield axi_port.ar.valid.eq(0) - - def reads_response_data_generator(axi_port, reads): - prng = random.Random(42) - self.reads_data_errors = 0 - self.reads_id_errors = 0 - self.reads_last_errors = 0 - while not axi_port.reads_enable: - yield - for read in reads: - for i, data in enumerate(read.data): - # Wait data / response - yield axi_port.r.ready.eq(0) - yield - while (yield axi_port.r.valid) == 0: - yield - while prng.randrange(100) < r_ready_random: - yield - yield axi_port.r.ready.eq(1) - yield - if (yield axi_port.r.data) != data: - self.reads_data_errors += 1 - if (yield axi_port.r.id) != read.id: - self.reads_id_errors += 1 - if i == (len(read.data) - 1): - if (yield axi_port.r.last) != 1: - self.reads_last_errors += 1 - else: - if (yield axi_port.r.last) != 0: - self.reads_last_errors += 1 - - # DUT - axi_port = LiteDRAMAXIPort(32, 32, 8) - dram_port = LiteDRAMNativePort("both", 32, 32) - dut = LiteDRAMAXI2Native(axi_port, dram_port) - mem = DRAMMemory(32, 1024) - - # Generate writes/reads - prng = random.Random(42) - writes = [] - offset = 1 - for i in range(naccesses): - _id = prng.randrange(2**8) if id_rand_enable else i - _len = prng.randrange(32) if len_rand_enable else i - _data = [prng.randrange(2**32) if data_rand_enable else j for j in range(_len + 1)] - writes.append(Write(offset, _data, _id, type=BURST_INCR, len=_len, size=log2_int(32//8))) - offset += _len + 1 - # Dummy reads to ensure datas have been written before the effective reads start. - dummy_reads = [Read(1023, [0], 0, type=BURST_FIXED, len=0, size=log2_int(32//8)) for _ in range(32)] - reads = dummy_reads + writes - - # Simulation - if simultaneous_writes_reads: - axi_port.reads_enable = True - else: - axi_port.reads_enable = False # Will be set by writes_data_generator - generators = [ - writes_cmd_generator(axi_port, writes), - writes_data_generator(axi_port, writes), - writes_response_generator(axi_port, writes), - reads_cmd_generator(axi_port, reads), - reads_response_data_generator(axi_port, reads), - mem.read_handler(dram_port, rdata_valid_random=r_valid_random), - mem.write_handler(dram_port, wdata_ready_random=w_ready_random) - ] - run_simulation(dut, generators) - #mem.show_content() - self.assertEqual(self.writes_id_errors, 0) - self.assertEqual(self.reads_data_errors, 0) - self.assertEqual(self.reads_id_errors, 0) - self.assertEqual(self.reads_last_errors, 0) - - # Test with no randomness - def test_axi2native_writes_then_reads_no_random(self): - self._test_axi2native(simultaneous_writes_reads=False) - - def test_axi2native_writes_and_reads_no_random(self): - self._test_axi2native(simultaneous_writes_reads=True) - - # Test randomness one parameter at a time - def test_axi2native_writes_then_reads_random_bursts(self): - self._test_axi2native( - simultaneous_writes_reads = False, - id_rand_enable = True, - len_rand_enable = True, - data_rand_enable = True) - - def test_axi2native_writes_and_reads_random_bursts(self): - self._test_axi2native( - simultaneous_writes_reads = True, - id_rand_enable = True, - len_rand_enable = True, - data_rand_enable = True) - - def test_axi2native_random_w_ready(self): - self._test_axi2native(w_ready_random=90) - - def test_axi2native_random_b_ready(self): - self._test_axi2native(b_ready_random=90) - - def test_axi2native_random_r_ready(self): - self._test_axi2native(r_ready_random=90) - - def test_axi2native_random_aw_valid(self): - self._test_axi2native(aw_valid_random=90) - - def test_axi2native_random_w_valid(self): - self._test_axi2native(w_valid_random=90) - - def test_axi2native_random_ar_valid(self): - self._test_axi2native(ar_valid_random=90) - - def test_axi2native_random_r_valid(self): - self._test_axi2native(r_valid_random=90) - - # Now let's stress things a bit... :) - def test_axi2native_random_all(self): - self._test_axi2native( - simultaneous_writes_reads=True, - id_rand_enable = True, - len_rand_enable = True, - aw_valid_random = 50, - w_ready_random = 50, - b_ready_random = 50, - w_valid_random = 50, - ar_valid_random = 90, - r_valid_random = 90, - r_ready_random = 90 - ) diff --git a/test/test_bandwidth.py b/test/test_bandwidth.py deleted file mode 100644 index adca81f..0000000 --- a/test/test_bandwidth.py +++ /dev/null @@ -1,242 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import random -import unittest -import itertools -import collections - -from migen import * - -from litex.soc.interconnect import stream - -from litedram.common import * -from litedram.core.bandwidth import Bandwidth - -from test.common import timeout_generator, CmdRequestRWDriver - - -class BandwidthDUT(Module): - def __init__(self, data_width=8, **kwargs): - a, ba = 13, 3 - self.cmd = stream.Endpoint(cmd_request_rw_layout(a, ba)) - self.submodules.bandwidth = Bandwidth(self.cmd, data_width, **kwargs) - - -class CommandDriver: - def __init__(self, cmd, cmd_options=None): - self.cmd = cmd - self.driver = CmdRequestRWDriver(cmd) - self.cmd_counts = collections.defaultdict(int) - - @passive - def random_generator(self, random_ready_max=20, commands=None): - commands = commands or ["read", "write"] - prng = random.Random(42) - - while True: - # Generate random command - command = prng.choice(commands) - yield from getattr(self.driver, command)() - yield - # Wait some times before it becomes ready - for _ in range(prng.randint(0, random_ready_max)): - yield - yield self.cmd.ready.eq(1) - yield - self.cmd_counts[command] += 1 - yield self.cmd.ready.eq(0) - # Disable command - yield from self.driver.nop() - yield - - @passive - def timeline_generator(self, timeline): - # Timeline: an iterator of tuples (cycle, command) - sim_cycle = 0 - for cycle, command in timeline: - assert cycle >= sim_cycle - while sim_cycle != cycle: - sim_cycle += 1 - yield - # Set the command - yield from getattr(self.driver, command)() - yield self.cmd.ready.eq(1) - self.cmd_counts[command] += 1 - # Advance 1 cycle - yield - sim_cycle += 1 - # Clear state - yield self.cmd.ready.eq(0) - yield from self.driver.nop() - - -class TestBandwidth(unittest.TestCase): - def test_can_read_status_data_width(self): - # Verify that data width can be read from a CSR. - def test(data_width): - def main_generator(dut): - yield - self.assertEqual((yield dut.bandwidth.data_width.status), data_width) - - dut = BandwidthDUT(data_width=data_width) - run_simulation(dut, main_generator(dut)) - - for data_width in [8, 16, 32, 64]: - with self.subTest(data_width=data_width): - test(data_width) - - def test_requires_update_to_copy_the_data(self): - # Verify that command counts are copied to CSRs only after `update`. - def main_generator(dut): - nreads = (yield from dut.bandwidth.nreads.read()) - nwrites = (yield from dut.bandwidth.nwrites.read()) - self.assertEqual(nreads, 0) - self.assertEqual(nwrites, 0) - - # Wait enough for the period to end - for _ in range(2**6): - yield - - nreads = (yield from dut.bandwidth.nreads.read()) - nwrites = (yield from dut.bandwidth.nwrites.read()) - self.assertEqual(nreads, 0) - self.assertEqual(nwrites, 0) - - # Update register values - yield from dut.bandwidth.update.write(1) - - nreads = (yield from dut.bandwidth.nreads.read()) - nwrites = (yield from dut.bandwidth.nwrites.read()) - self.assertNotEqual((nreads, nwrites), (0, 0)) - - dut = BandwidthDUT(period_bits=6) - cmd_driver = CommandDriver(dut.cmd) - generators = [ - main_generator(dut), - cmd_driver.random_generator(), - ] - run_simulation(dut, generators) - - def test_correct_read_write_counts(self): - # Verify that the number of registered READ/WRITE commands is correct. - results = {} - - def main_generator(dut): - # Wait for the first period to end - for _ in range(2**8): - yield - yield from dut.bandwidth.update.write(1) - yield - results["nreads"] = (yield from dut.bandwidth.nreads.read()) - results["nwrites"] = (yield from dut.bandwidth.nwrites.read()) - - dut = BandwidthDUT(period_bits=8) - cmd_driver = CommandDriver(dut.cmd) - generators = [ - main_generator(dut), - cmd_driver.random_generator(), - ] - run_simulation(dut, generators) - - self.assertEqual(results["nreads"], cmd_driver.cmd_counts["read"]) - - def test_counts_read_write_only(self): - # Verify that only READ and WRITE commands are registered. - results = {} - - def main_generator(dut): - # Wait for the first period to end - for _ in range(2**8): - yield - yield from dut.bandwidth.update.write(1) - yield - results["nreads"] = (yield from dut.bandwidth.nreads.read()) - results["nwrites"] = (yield from dut.bandwidth.nwrites.read()) - - dut = BandwidthDUT(period_bits=8) - cmd_driver = CommandDriver(dut.cmd) - commands = ["read", "write", "activate", "precharge", "refresh"] - generators = [ - main_generator(dut), - cmd_driver.random_generator(commands=commands), - ] - run_simulation(dut, generators) - - self.assertEqual(results["nreads"], cmd_driver.cmd_counts["read"]) - - def test_correct_period_length(self): - # Verify that period length is correct by measuring time between CSR changes. - period_bits = 5 - period = 2**period_bits - - n_per_period = {0: 3, 1: 6, 2: 9} - timeline = {} - for p, n in n_per_period.items(): - for i in range(n): - margin = 10 - timeline[period*p + margin + i] = "write" - - def main_generator(dut): - # Keep the values always up to date - yield dut.bandwidth.update.re.eq(1) - - # Wait until we have the data from 1st period - while (yield dut.bandwidth.nwrites.status) != 3: - yield - - # Count time to next period - cycles = 0 - while (yield dut.bandwidth.nwrites.status) != 6: - cycles += 1 - yield - - self.assertEqual(cycles, period) - - dut = BandwidthDUT(period_bits=period_bits) - cmd_driver = CommandDriver(dut.cmd) - generators = [ - main_generator(dut), - cmd_driver.timeline_generator(timeline.items()), - timeout_generator(period * 3), - ] - run_simulation(dut, generators) - - def test_not_missing_commands_on_period_boundary(self): - # Verify that no data is lost in the cycle when new period starts. - period_bits = 5 - period = 2**period_bits - - # Start 10 cycles before period ends, end 10 cycles after it ends - base = period - 10 - nwrites = 20 - timeline = {base + i: "write" for i in range(nwrites)} - - def main_generator(dut): - # Wait until 1st period ends (+ some margin) - for _ in range(period + 10): - yield - - # Read the count from 1st period - yield from dut.bandwidth.update.write(1) - yield - nwrites_registered = (yield from dut.bandwidth.nwrites.read()) - - # Wait until 2nd period ends - for _ in range(period): - yield - - # Read the count from 1st period - yield from dut.bandwidth.update.write(1) - yield - nwrites_registered += (yield from dut.bandwidth.nwrites.read()) - - self.assertEqual(nwrites_registered, nwrites) - - dut = BandwidthDUT(period_bits=period_bits) - cmd_driver = CommandDriver(dut.cmd) - generators = [ - main_generator(dut), - cmd_driver.timeline_generator(timeline.items()), - ] - run_simulation(dut, generators) diff --git a/test/test_bankmachine.py b/test/test_bankmachine.py deleted file mode 100644 index f676d0d..0000000 --- a/test/test_bankmachine.py +++ /dev/null @@ -1,427 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import math -import unittest - -from migen import * - -from litedram.common import * -from litedram.core.bankmachine import BankMachine - -from test.common import timeout_generator - - -class BankMachineDUT(Module): - # Fill only settings needed by BankMachine - default_controller_settings = dict( - cmd_buffer_depth = 8, - cmd_buffer_buffered = False, - with_auto_precharge = True, - ) - default_phy_settings = dict( - cwl = 2, - nphases = 2, - nranks = 1, - # indirectly - memtype = "DDR2", - dfi_databits = 2*16, - ) - default_geom_settings = dict( - bankbits = 3, - rowbits = 13, - colbits = 10, - ) - default_timing_settings = dict( - tRAS = None, - tRC = None, - tCCD = 1, - tRCD = 2, - tRP = 2, - tWR = 2, - ) - - def __init__(self, n, - controller_settings = None, - phy_settings = None, - geom_settings = None, - timing_settings = None): - # Update settings if provided - def updated(settings, update): - copy = settings.copy() - copy.update(update or {}) - return copy - - controller_settings = updated(self.default_controller_settings, controller_settings) - phy_settings = updated(self.default_phy_settings, phy_settings) - geom_settings = updated(self.default_geom_settings, geom_settings) - timing_settings = updated(self.default_timing_settings, timing_settings) - - class SimpleSettings(Settings): - def __init__(self, **kwargs): - self.set_attributes(kwargs) - - settings = SimpleSettings(**controller_settings) - settings.phy = SimpleSettings(**phy_settings) - settings.geom = SimpleSettings(**geom_settings) - settings.timing = SimpleSettings(**timing_settings) - settings.geom.addressbits = max(settings.geom.rowbits, settings.geom.colbits) - self.settings = settings - - self.address_align = log2_int(burst_lengths[settings.phy.memtype]) - self.address_width = LiteDRAMInterface(self.address_align, settings).address_width - - bankmachine = BankMachine(n=n, - address_width = self.address_width, - address_align = self.address_align, - nranks = settings.phy.nranks, - settings = settings) - self.submodules.bankmachine = bankmachine - - def get_cmd(self): - # cmd_request_rw_layout -> name - layout = [name for name, _ in cmd_request_rw_layout( - a = self.settings.geom.addressbits, - ba = self.settings.geom.bankbits)] - request = {} - for name in layout + ["valid", "ready", "first", "last"]: - request[name] = (yield getattr(self.bankmachine.cmd, name)) - request["type"] = { - (0, 0, 0): "nop", - (1, 0, 1): "write", - (1, 0, 0): "read", - (0, 1, 0): "activate", - (0, 1, 1): "precharge", - (1, 1, 0): "refresh", - }[(request["cas"], request["ras"], request["we"])] - return request - - def req_address(self, row, col): - col = col & (2**self.settings.geom.colbits - 1) - row = row & (2**self.settings.geom.rowbits - 1) - split = self.settings.geom.colbits - self.address_align - return (row << split) | col - - -class TestBankMachine(unittest.TestCase): - def test_init(self): - BankMachineDUT(1) - - def bankmachine_commands_test(self, dut, requests, generators=None): - # Perform a test by simulating requests producer and return registered commands - commands = [] - - def producer(dut): - for req in requests: - yield dut.bankmachine.req.addr.eq(req["addr"]) - yield dut.bankmachine.req.we.eq(req["we"]) - yield dut.bankmachine.req.valid.eq(1) - yield - while not (yield dut.bankmachine.req.ready): - yield - yield dut.bankmachine.req.valid.eq(0) - for _ in range(req.get("delay", 0)): - yield - - def req_consumer(dut): - for req in requests: - if req["we"]: - signal = dut.bankmachine.req.wdata_ready - else: - signal = dut.bankmachine.req.rdata_valid - while not (yield signal): - yield - yield - - @passive - def cmd_consumer(dut): - while True: - while not (yield dut.bankmachine.cmd.valid): - yield - yield dut.bankmachine.cmd.ready.eq(1) - yield - commands.append((yield from dut.get_cmd())) - yield dut.bankmachine.cmd.ready.eq(0) - yield - - all_generators = [ - producer(dut), - req_consumer(dut), - cmd_consumer(dut), - timeout_generator(50 * len(requests)), - ] - if generators is not None: - all_generators += [g(dut) for g in generators] - run_simulation(dut, all_generators) - return commands - - def test_opens_correct_row(self): - # Verify that the correct row is activated before read/write commands. - dut = BankMachineDUT(3) - requests = [ - dict(addr=dut.req_address(row=0xf0, col=0x0d), we=0), - dict(addr=dut.req_address(row=0xd0, col=0x0d), we=1), - ] - commands = self.bankmachine_commands_test(dut=dut, requests=requests) - # Commands: activate, read (auto-precharge), activate, write - self.assertEqual(commands[0]["type"], "activate") - self.assertEqual(commands[0]["a"], 0xf0) - self.assertEqual(commands[2]["type"], "activate") - self.assertEqual(commands[2]["a"], 0xd0) - - def test_correct_bank_address(self): - # Verify that `ba` always corresponds to the BankMachine number. - for bn in [0, 2, 7]: - with self.subTest(bn=bn): - dut = BankMachineDUT(bn, geom_settings=dict(bankbits=3)) - requests = [dict(addr=0, we=0)] - commands = self.bankmachine_commands_test(dut=dut, requests=requests) - for cmd in commands: - self.assertEqual(cmd["ba"], bn) - - def test_read_write_same_row(self): - # Verify that there is only one activate when working on single row. - dut = BankMachineDUT(1) - requests = [ - dict(addr=dut.req_address(row=0xba, col=0xad), we=0), - dict(addr=dut.req_address(row=0xba, col=0xad), we=1), - dict(addr=dut.req_address(row=0xba, col=0xbe), we=0), - dict(addr=dut.req_address(row=0xba, col=0xbe), we=1), - ] - commands = self.bankmachine_commands_test(dut=dut, requests=requests) - commands = [(cmd["type"], cmd["a"]) for cmd in commands] - expected = [ - ("activate", 0xba), - ("read", 0xad << dut.address_align), - ("write", 0xad << dut.address_align), - ("read", 0xbe << dut.address_align), - ("write", 0xbe << dut.address_align), - ] - self.assertEqual(commands, expected) - - def test_write_different_rows_with_delay(self): - # Verify that precharge is used when changing row with a delay this is independent form auto-precharge. - for auto_precharge in [False, True]: - with self.subTest(auto_precharge=auto_precharge): - settings = dict(with_auto_precharge=auto_precharge) - dut = BankMachineDUT(1, controller_settings=settings) - requests = [ - dict(addr=dut.req_address(row=0xba, col=0xad), we=1, delay=8), - dict(addr=dut.req_address(row=0xda, col=0xad), we=1), - ] - commands = self.bankmachine_commands_test(dut=dut, requests=requests) - commands = [(cmd["type"], cmd["a"]) for cmd in commands] - expected = [ - ("activate", 0xba), - ("write", 0xad << dut.address_align), - ("precharge", 0xad << dut.address_align), - ("activate", 0xda), - ("write", 0xad << dut.address_align), - ] - self.assertEqual(commands, expected) - - def test_write_different_rows_with_auto_precharge(self): - # Verify that auto-precharge is used when changing row without delay. - settings = dict(with_auto_precharge=True) - dut = BankMachineDUT(1, controller_settings=settings) - requests = [ - dict(addr=dut.req_address(row=0xba, col=0xad), we=1), - dict(addr=dut.req_address(row=0xda, col=0xad), we=1), - ] - commands = self.bankmachine_commands_test(dut=dut, requests=requests) - commands = [(cmd["type"], cmd["a"]) for cmd in commands] - expected = [ - ("activate", 0xba), - ("write", (0xad << dut.address_align) | (1 << 10)), - ("activate", 0xda), - ("write", 0xad << dut.address_align), - ] - self.assertEqual(commands, expected) - - def test_write_different_rows_without_auto_precharge(self): - # Verify that auto-precharge is used when changing row without delay. - settings = dict(with_auto_precharge=False) - dut = BankMachineDUT(1, controller_settings=settings) - requests = [ - dict(addr=dut.req_address(row=0xba, col=0xad), we=1), - dict(addr=dut.req_address(row=0xda, col=0xad), we=1), - ] - commands = self.bankmachine_commands_test(dut=dut, requests=requests) - commands = [(cmd["type"], cmd["a"]) for cmd in commands] - expected = [ - ("activate", 0xba), - ("write", 0xad << dut.address_align), - ("precharge", 0xad << dut.address_align), - ("activate", 0xda), - ("write", 0xad << dut.address_align), - ] - self.assertEqual(commands, expected) - - def test_burst_no_request_lost(self): - # Verify that no request is lost in fast bursts of requests regardless of cmd_buffer_depth. - for cmd_buffer_depth in [8, 1, 0]: - settings = dict(cmd_buffer_depth=cmd_buffer_depth) - with self.subTest(**settings): - dut = BankMachineDUT(1, controller_settings=settings) - # Long sequence of writes to the same row - requests = [dict(addr=dut.req_address(row=0xba, col=i), we=1) for i in range(32)] - expected = ([("activate", 0xba)] + - [("write", i << dut.address_align) for i in range(32)]) - commands = self.bankmachine_commands_test(dut=dut, requests=requests) - commands = [(cmd["type"], cmd["a"]) for cmd in commands] - self.assertEqual(commands, expected) - - def test_lock_until_requests_finished(self): - # Verify that lock is being held until all requests in FIFO are processed. - @passive - def lock_checker(dut): - req = dut.bankmachine.req - self.assertEqual((yield req.lock), 0) - - # Wait until first request becomes locked - while not (yield req.valid): - yield - - # Wait until lock should be released (all requests in queue gets processed) - # here it happens when the final wdata_ready ends - for _ in range(3): - while not (yield req.wdata_ready): - yield - self.assertEqual((yield req.lock), 1) - yield - - yield - self.assertEqual((yield req.lock), 0) - - dut = BankMachineDUT(1) - # Simple sequence with row change - requests = [ - dict(addr=dut.req_address(row=0x1a, col=0x01), we=1), - dict(addr=dut.req_address(row=0x1b, col=0x02), we=1), - dict(addr=dut.req_address(row=0x1c, col=0x04), we=1), - ] - self.bankmachine_commands_test(dut=dut, requests=requests, generators=[lock_checker]) - - def timing_test(self, from_cmd, to_cmd, time_expected, **dut_kwargs): - @passive - def timing_checker(dut): - def is_cmd(cmd_type, test_ready): - cmd = (yield from dut.get_cmd()) - ready = cmd["ready"] if test_ready else True - return cmd["valid"] and ready and cmd["type"] == cmd_type - - # Time between WRITE ends (ready and valid) and PRECHARGE becomes valid - while not (yield from is_cmd(from_cmd, test_ready=True)): - yield - yield # Wait until cmd deactivates in case the second cmd is the same as first - time = 1 - while not (yield from is_cmd(to_cmd, test_ready=False)): - yield - time += 1 - - self.assertEqual(time, time_expected) - - dut = BankMachineDUT(1, **dut_kwargs) - # Simple sequence with row change - requests = [ - dict(addr=dut.req_address(row=0xba, col=0xad), we=1), - dict(addr=dut.req_address(row=0xda, col=0xad), we=1), - ] - self.bankmachine_commands_test(dut=dut, requests=requests, generators=[timing_checker]) - - def test_timing_write_to_precharge(self): - controller_settings = dict(with_auto_precharge=False) - timing_settings = dict(tWR=6, tCCD=4) - phy_settings = dict(cwl=2, nphases=2) - write_latency = math.ceil(phy_settings["cwl"] / phy_settings["nphases"]) - precharge_time = write_latency + timing_settings["tWR"] + timing_settings["tCCD"] - self.timing_test("write", "precharge", precharge_time, - controller_settings = controller_settings, - phy_settings = phy_settings, - timing_settings = timing_settings) - - def test_timing_activate_to_activate(self): - timing_settings = dict(tRC=16) - self.timing_test("activate", "activate", - time_expected = 16, - timing_settings = timing_settings) - - def test_timing_activate_to_precharge(self): - timing_settings = dict(tRAS=32) - self.timing_test("activate", "precharge", - time_expected = 32, - timing_settings = timing_settings) - - def test_refresh(self): - # Verify that no commands are issued during refresh and after it the row is re-activated. - @passive - def refresh_generator(dut): - # Wait some time for the bankmachine to start - for _ in range(16): - yield - - # Request a refresh - yield dut.bankmachine.refresh_req.eq(1) - while not (yield dut.bankmachine.refresh_gnt): - yield - - # Wait when refresh is being performed - # Make sure no command is issued during refresh - for _ in range(32): - self.assertEqual((yield dut.bankmachine.cmd.valid), 0) - yield - - # Signalize refresh is ready - yield dut.bankmachine.refresh_req.eq(0) - - dut = BankMachineDUT(1) - requests = [dict(addr=dut.req_address(row=0xba, col=i), we=1) for i in range(16)] - commands = self.bankmachine_commands_test(dut=dut, requests=requests, - generators=[refresh_generator]) - commands = [(cmd["type"], cmd["a"]) for cmd in commands] - # Refresh will close row, so bankmachine should re-activate it after refresh - self.assertEqual(commands.count(("activate", 0xba)), 2) - # Verify that the write commands are correct - write_commands = [cmd for cmd in commands if cmd[0] == "write"] - expected_writes = [("write", i << dut.address_align) for i in range(16)] - self.assertEqual(write_commands, expected_writes) - - def test_output_annotations(self): - # Verify that all commands are annotated correctly using is_* signals. - checked = set() - - @passive - def cmd_checker(dut): - while True: - cmd = (yield from dut.get_cmd()) - if cmd["valid"]: - if cmd["type"] in ["activate", "precharge"]: - self.assertEqual(cmd["is_cmd"], 1) - self.assertEqual(cmd["is_write"], 0) - self.assertEqual(cmd["is_read"], 0) - elif cmd["type"] in ["write"]: - self.assertEqual(cmd["is_cmd"], 0) - self.assertEqual(cmd["is_write"], 1) - self.assertEqual(cmd["is_read"], 0) - elif cmd["type"] in ["read"]: - self.assertEqual(cmd["is_cmd"], 0) - self.assertEqual(cmd["is_write"], 0) - self.assertEqual(cmd["is_read"], 1) - else: - raise ValueError(cmd["type"]) - checked.add(cmd["type"]) - yield - - dut = BankMachineDUT(1) - requests = [ - dict(addr=dut.req_address(row=0xba, col=0xad), we=0), - dict(addr=dut.req_address(row=0xba, col=0xad), we=1), - dict(addr=dut.req_address(row=0xda, col=0xad), we=0), - # Wait enough time for regular (not auto) precharge to be used - dict(addr=dut.req_address(row=0xda, col=0xad), we=1, delay=32), - dict(addr=dut.req_address(row=0xba, col=0xad), we=0), - dict(addr=dut.req_address(row=0xba, col=0xad), we=1), - ] - self.bankmachine_commands_test(dut=dut, requests=requests, generators=[cmd_checker]) - # Bankmachine does not produce refresh commands - self.assertEqual(checked, {"activate", "precharge", "write", "read"}) diff --git a/test/test_bist.py b/test/test_bist.py deleted file mode 100644 index 3be4cd7..0000000 --- a/test/test_bist.py +++ /dev/null @@ -1,446 +0,0 @@ -# This file is Copyright (c) 2016-2018 Florent Kermarrec -# This file is Copyright (c) 2016 Tim 'mithro' Ansell -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest - -from migen import * - -from litex.gen.sim import * - -from litedram.common import * -from litedram.frontend.bist import * -from litedram.frontend.bist import _LiteDRAMBISTGenerator, _LiteDRAMBISTChecker, \ - _LiteDRAMPatternGenerator, _LiteDRAMPatternChecker - -from test.common import * - - -class GenCheckDriver: - def __init__(self, module): - self.module = module - - def reset(self): - yield self.module.reset.eq(1) - yield - yield self.module.reset.eq(0) - yield - - def configure(self, base, length, end=None, random_addr=None, random_data=None): - # For non-pattern generators/checkers - if end is None: - end = base + 0x100000 - yield self.module.base.eq(base) - yield self.module.end.eq(end) - yield self.module.length.eq(length) - if random_addr is not None: - yield self.module.random_addr.eq(random_addr) - if random_data is not None: - yield self.module.random_data.eq(random_data) - - def run(self): - yield self.module.start.eq(1) - yield - yield self.module.start.eq(0) - yield - while((yield self.module.done) == 0): - yield - if hasattr(self.module, "errors"): - self.errors = (yield self.module.errors) - - -class GenCheckCSRDriver: - def __init__(self, module): - self.module = module - - def reset(self): - yield from self.module.reset.write(1) - yield from self.module.reset.write(0) - - def configure(self, base, length, end=None, random_addr=None, random_data=None): - # For non-pattern generators/checkers - if end is None: - end = base + 0x100000 - yield from self.module.base.write(base) - yield from self.module.end.write(end) - yield from self.module.length.write(length) - if random_addr is not None: - yield from self.module.random.addr.write(random_addr) - if random_data is not None: - yield from self.module.random.data.write(random_data) - - def run(self): - yield from self.module.start.write(1) - yield - yield from self.module.start.write(0) - yield - while((yield from self.module.done.read()) == 0): - yield - if hasattr(self.module, "errors"): - self.errors = (yield from self.module.errors.read()) - - -class TestBIST(MemoryTestDataMixin, unittest.TestCase): - - # Generator ------------------------------------------------------------------------------------ - - def test_generator(self): - # Verify Generator is behaving correctly in the incr/random modes. - def main_generator(dut): - self.errors = 0 - - # Test incr - yield dut.ce.eq(1) - yield dut.random_enable.eq(0) - yield - for i in range(1024): - data = (yield dut.o) - if data != i: - self.errors += 1 - yield - - # Test random - datas = [] - yield dut.ce.eq(1) - yield dut.random_enable.eq(1) - for i in range(1024): - data = (yield dut.o) - if data in datas: - self.errors += 1 - datas.append(data) - yield - - # DUT - dut = Generator(23, n_state=23, taps=[17, 22]) - - # Simulation - generators = [main_generator(dut)] - run_simulation(dut, generators) - self.assertEqual(self.errors, 0) - - def generator_test(self, mem_expected, data_width, pattern=None, config_args=None, - check_mem=True): - assert pattern is None or config_args is None, \ - "_LiteDRAMBISTGenerator xor _LiteDRAMPatternGenerator" - - class DUT(Module): - def __init__(self): - self.write_port = LiteDRAMNativeWritePort(address_width=32, data_width=data_width) - if pattern is not None: - self.submodules.generator = _LiteDRAMPatternGenerator(self.write_port, pattern) - else: - self.submodules.generator = _LiteDRAMBISTGenerator(self.write_port) - self.mem = DRAMMemory(data_width, len(mem_expected)) - - def main_generator(driver): - yield from driver.reset() - if pattern is None: - yield from driver.configure(**config_args) - yield from driver.run() - yield - - dut = DUT() - generators = [ - main_generator(GenCheckDriver(dut.generator)), - dut.mem.write_handler(dut.write_port), - ] - run_simulation(dut, generators) - if check_mem: - self.assertEqual(dut.mem.mem, mem_expected) - return dut - - # _LiteDRAMBISTGenerator ----------------------------------------------------------------------- - - def test_bist_generator_8bit(self): - # Verify BISTGenerator with a 8-bit datapath. - data = self.bist_test_data["8bit"] - self.generator_test(data.pop("expected"), data_width=8, config_args=data) - - def test_bist_generator_range_must_be_pow2(self): - # NOTE: - # in the current implementation (end - start) must be a power of 2, - # but it would be better if this restriction didn't hold, this test - # is here just to notice the change if it happens unintentionally - # and may be removed if we start supporting arbitrary ranges - data = self.bist_test_data["8bit"] - data["end"] += 1 - reference = data.pop("expected") - dut = self.generator_test(reference, data_width=8, config_args=data, check_mem=False) - self.assertNotEqual(dut.mem.mem, reference) - - def test_bist_generator_32bit(self): - # Verify BISTGenerator with a 32-bit datapath. - data = self.bist_test_data["32bit"] - self.generator_test(data.pop("expected"), data_width=32, config_args=data) - - def test_bist_generator_64bit(self): - # Verify BISTGenerator with a 64-bit datapath. - data = self.bist_test_data["64bit"] - self.generator_test(data.pop("expected"), data_width=64, config_args=data) - - def test_bist_generator_32bit_address_masked(self): - # Verify BISTGenerator with a 32-bit datapath and masked address. - data = self.bist_test_data["32bit_masked"] - self.generator_test(data.pop("expected"), data_width=32, config_args=data) - - def test_bist_generator_32bit_long_sequential(self): - # Verify BISTGenerator with a 32-bit datapath and long sequential pattern. - data = self.bist_test_data["32bit_long_sequential"] - self.generator_test(data.pop("expected"), data_width=32, config_args=data) - - def test_bist_generator_random_data(self): - # Verify BISTGenerator with a 32-bit datapath and random pattern. - data = self.bist_test_data["32bit"] - data["random_data"] = True - dut = self.generator_test(data.pop("expected"), data_width=32, config_args=data, - check_mem=False) - # Only check that there are no duplicates and that data is not a simple sequence - mem = [val for val in dut.mem.mem if val != 0] - self.assertEqual(len(set(mem)), len(mem), msg="Duplicate values in memory") - self.assertNotEqual(mem, list(range(len(mem))), msg="Values are a sequence") - - def test_bist_generator_random_addr(self): - # Verify BISTGenerator with a 32-bit datapath and random address. - data = self.bist_test_data["32bit"] - data["random_addr"] = True - dut = self.generator_test(data.pop("expected"), data_width=32, config_args=data, - check_mem=False) - # With random address and address wrapping (generator.end) we _can_ have duplicates - # we can at least check that the values written are not an ordered sequence - mem = [val for val in dut.mem.mem if val != 0] - self.assertNotEqual(mem, list(range(len(mem))), msg="Values are a sequence") - self.assertLess(max(mem), data["length"], msg="Too big value found") - - # _LiteDRAMPatternGenerator -------------------------------------------------------------------- - - def test_pattern_generator_8bit(self): - # Verify PatternGenerator with a 8-bit datapath. - data = self.pattern_test_data["8bit"] - self.generator_test(data["expected"], data_width=8, pattern=data["pattern"]) - - def test_pattern_generator_32bit(self): - # Verify PatternGenerator with a 32-bit datapath. - data = self.pattern_test_data["32bit"] - self.generator_test(data["expected"], data_width=32, pattern=data["pattern"]) - - def test_pattern_generator_64bit(self): - # Verify PatternGenerator with a 64-bit datapath. - data = self.pattern_test_data["64bit"] - self.generator_test(data["expected"], data_width=64, pattern=data["pattern"]) - - def test_pattern_generator_32bit_not_aligned(self): - # Verify PatternGenerator with a 32-bit datapath and un-aligned addresses. - data = self.pattern_test_data["32bit_not_aligned"] - self.generator_test(data["expected"], data_width=32, pattern=data["pattern"]) - - def test_pattern_generator_32bit_duplicates(self): - # Verify PatternGenerator with a 32-bit datapath and duplicate addresses. - data = self.pattern_test_data["32bit_duplicates"] - self.generator_test(data["expected"], data_width=32, pattern=data["pattern"]) - - def test_pattern_generator_32bit_sequential(self): - # Verify PatternGenerator with a 32-bit datapath and sequential pattern. - data = self.pattern_test_data["32bit_sequential"] - self.generator_test(data["expected"], data_width=32, pattern=data["pattern"]) - - # _LiteDRAMBISTChecker ------------------------------------------------------------------------- - - def checker_test(self, memory, data_width, pattern=None, config_args=None, check_errors=False): - assert pattern is None or config_args is None, \ - "_LiteDRAMBISTChecker xor _LiteDRAMPatternChecker" - - class DUT(Module): - def __init__(self): - self.read_port = LiteDRAMNativeReadPort(address_width=32, data_width=data_width) - if pattern is not None: - self.submodules.checker = _LiteDRAMPatternChecker(self.read_port, init=pattern) - else: - self.submodules.checker = _LiteDRAMBISTChecker(self.read_port) - self.mem = DRAMMemory(data_width, len(memory), init=memory) - - def main_generator(driver): - yield from driver.reset() - if pattern is None: - yield from driver.configure(**config_args) - yield from driver.run() - yield - - dut = DUT() - checker = GenCheckDriver(dut.checker) - generators = [ - main_generator(checker), - dut.mem.read_handler(dut.read_port), - ] - run_simulation(dut, generators) - if check_errors: - self.assertEqual(checker.errors, 0) - return dut, checker - - def test_bist_checker_8bit(self): - # Verify BISTChecker with a 8-bit datapath. - data = self.bist_test_data["8bit"] - memory = data.pop("expected") - self.checker_test(memory, data_width=8, config_args=data) - - def test_bist_checker_32bit(self): - # Verify BISTChecker with a 32-bit datapath. - data = self.bist_test_data["32bit"] - memory = data.pop("expected") - self.checker_test(memory, data_width=32, config_args=data) - - def test_bist_checker_64bit(self): - # Verify BISTChecker with a 64-bit datapath. - data = self.bist_test_data["64bit"] - memory = data.pop("expected") - self.checker_test(memory, data_width=64, config_args=data) - - # _LiteDRAMPatternChecker ---------------------------------------------------------------------- - - def test_pattern_checker_8bit(self): - # Verify PatternChecker with a 8-bit datapath. - data = self.pattern_test_data["8bit"] - self.checker_test(memory=data["expected"], data_width=8, pattern=data["pattern"]) - - def test_pattern_checker_32bit(self): - # Verify PatternChecker with a 32-bit datapath. - data = self.pattern_test_data["32bit"] - self.checker_test(memory=data["expected"], data_width=32, pattern=data["pattern"]) - - def test_pattern_checker_64bit(self): - # Verify PatternChecker with a 64-bit datapath. - data = self.pattern_test_data["64bit"] - self.checker_test(memory=data["expected"], data_width=64, pattern=data["pattern"]) - - def test_pattern_checker_32bit_not_aligned(self): - # Verify PatternChecker with a 32-bit datapath and un-aligned addresses. - data = self.pattern_test_data["32bit_not_aligned"] - self.checker_test(memory=data["expected"], data_width=32, pattern=data["pattern"]) - - def test_pattern_checker_32bit_duplicates(self): - # Verify PatternChecker with a 32-bit datapath and duplicate addresses. - data = self.pattern_test_data["32bit_duplicates"] - num_duplicates = len(data["pattern"]) - len(set(adr for adr, _ in data["pattern"])) - dut, checker = self.checker_test( - memory=data["expected"], data_width=32, pattern=data["pattern"], check_errors=False) - self.assertEqual(checker.errors, num_duplicates) - - # LiteDRAMBISTGenerator and LiteDRAMBISTChecker ------------------------------------------------ - - def bist_test(self, generator, checker, mem): - # write - yield from generator.reset() - yield from generator.configure(base=16, length=64) - yield from generator.run() - - # Read (no errors) - yield from checker.reset() - yield from checker.configure(base=16, length=64) - yield from checker.run() - self.assertEqual(checker.errors, 0) - - # Corrupt memory (using generator) - yield from generator.reset() - yield from generator.configure(base=16 + 48, length=64) - yield from generator.run() - - # Read (errors) - yield from checker.reset() - yield from checker.configure(base=16, length=64) - yield from checker.run() - # Errors for words: - # from (16 + 48) / 4 = 16 (corrupting generator start) - # to (16 + 64) / 4 = 20 (first generator end) - self.assertEqual(checker.errors, 4) - - # Read (no errors) - yield from checker.reset() - yield from checker.configure(base=16 + 48, length=64) - yield from checker.run() - self.assertEqual(checker.errors, 0) - - def test_bist_base(self): - # Verify BIST (Generator and Checker) with control from the logic. - class DUT(Module): - def __init__(self): - self.write_port = LiteDRAMNativeWritePort(address_width=32, data_width=32) - self.read_port = LiteDRAMNativeReadPort(address_width=32, data_width=32) - self.submodules.generator = _LiteDRAMBISTGenerator(self.write_port) - self.submodules.checker = _LiteDRAMBISTChecker(self.read_port) - - def main_generator(dut, mem): - generator = GenCheckDriver(dut.generator) - checker = GenCheckDriver(dut.checker) - yield from self.bist_test(generator, checker, mem) - - # DUT - dut = DUT() - mem = DRAMMemory(32, 48) - - # Simulation - generators = [ - main_generator(dut, mem), - mem.write_handler(dut.write_port), - mem.read_handler(dut.read_port) - ] - run_simulation(dut, generators) - - def test_bist_csr(self): - # Verify BIST (Generator and Checker) with control from CSRs. - class DUT(Module): - def __init__(self): - self.write_port = LiteDRAMNativeWritePort(address_width=32, data_width=32) - self.read_port = LiteDRAMNativeReadPort(address_width=32, data_width=32) - self.submodules.generator = LiteDRAMBISTGenerator(self.write_port) - self.submodules.checker = LiteDRAMBISTChecker(self.read_port) - - def main_generator(dut, mem): - generator = GenCheckCSRDriver(dut.generator) - checker = GenCheckCSRDriver(dut.checker) - yield from self.bist_test(generator, checker, mem) - - # DUT - dut = DUT() - mem = DRAMMemory(32, 48) - - # Simulation - generators = [ - main_generator(dut, mem), - mem.write_handler(dut.write_port), - mem.read_handler(dut.read_port) - ] - run_simulation(dut, generators) - - def test_bist_csr_cdc(self): - # Verify BIST (Generator and Checker) with control from CSRs in a different clock domain. - class DUT(Module): - def __init__(self): - port_kwargs = dict(address_width=32, data_width=32, clock_domain="async") - self.write_port = LiteDRAMNativeWritePort(**port_kwargs) - self.read_port = LiteDRAMNativeReadPort(**port_kwargs) - self.submodules.generator = LiteDRAMBISTGenerator(self.write_port) - self.submodules.checker = LiteDRAMBISTChecker(self.read_port) - - def main_generator(dut, mem): - generator = GenCheckCSRDriver(dut.generator) - checker = GenCheckCSRDriver(dut.checker) - yield from self.bist_test(generator, checker, mem) - - # DUT - dut = DUT() - mem = DRAMMemory(32, 48) - - generators = { - "sys": [ - main_generator(dut, mem), - ], - "async": [ - mem.write_handler(dut.write_port), - mem.read_handler(dut.read_port) - ] - } - clocks = { - "sys": 10, - "async": (7, 3), - } - run_simulation(dut, generators, clocks) diff --git a/test/test_command_chooser.py b/test/test_command_chooser.py deleted file mode 100644 index b34323d..0000000 --- a/test/test_command_chooser.py +++ /dev/null @@ -1,223 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest - -from migen import * -from litex.soc.interconnect import stream - -from litedram.common import * -from litedram.core.multiplexer import _CommandChooser - -from test.common import CmdRequestRWDriver - - -class CommandChooserDUT(Module): - def __init__(self, n_requests, addressbits, bankbits): - self.requests = [stream.Endpoint(cmd_request_rw_layout(a=addressbits, ba=bankbits)) - for _ in range(n_requests)] - self.submodules.chooser = _CommandChooser(self.requests) - - self.drivers = [CmdRequestRWDriver(req, i) for i, req in enumerate(self.requests)] - - def set_requests(self, description): - assert len(description) == len(self.drivers) - for driver, char in zip(self.drivers, description): - yield from driver.request(char) - - -class TestCommandChooser(unittest.TestCase): - def test_helper_methods_correct(self): - # Verify that helper methods return correct values. - def main_generator(dut): - possible_cmds = "_rwap" - expected_read = "01000" - expected_write = "00100" - expected_activate = "00010" - helper_methods = { - "write": expected_write, - "read": expected_read, - "activate": expected_activate, - } - - # Create a subTest for each method - for method, expected_values in helper_methods.items(): - with self.subTest(method=method): - # Set each available command as the first request and verify - # that the helper method returns the correct value. We can - # safely use only the first request because no requests are - # valid as all the want_* signals are 0. - for cmd, expected in zip(possible_cmds, expected_values): - yield from dut.set_requests(f"{cmd}___") - yield - method_value = (yield getattr(dut.chooser, method)()) - self.assertEqual(method_value, int(expected)) - - # Test accept helper - with self.subTest(method="accept"): - yield dut.chooser.want_writes.eq(1) - yield - - yield from dut.set_requests("____") - yield - self.assertEqual((yield dut.chooser.accept()), 0) - - # Set write request, this sets request.valid=1 - yield from dut.set_requests("w___") - yield - self.assertEqual((yield dut.chooser.accept()), 0) - self.assertEqual((yield dut.chooser.cmd.valid), 1) - - # Accept() is only on after we set cmd.ready=1 - yield dut.chooser.cmd.ready.eq(1) - yield - self.assertEqual((yield dut.chooser.accept()), 1) - - dut = CommandChooserDUT(n_requests=4, bankbits=3, addressbits=13) - run_simulation(dut, main_generator(dut)) - - def test_selects_next_when_request_not_valid(self): - # Verify that arbiter moves to next request when valid goes inactive. - def main_generator(dut): - yield dut.chooser.want_cmds.eq(1) - yield from dut.set_requests("pppp") - yield - - # Advance to next request - def invalidate(i): - yield dut.requests[i].valid.eq(0) - yield - yield dut.requests[i].valid.eq(1) - yield - - # First request is selected as it is valid and ~ready - self.assertEqual((yield dut.chooser.cmd.ba), 0) - yield - self.assertEqual((yield dut.chooser.cmd.ba), 0) - - # After deactivating `valid`, arbiter should choose next request - yield from invalidate(0) - self.assertEqual((yield dut.chooser.cmd.ba), 1) - yield from invalidate(1) - self.assertEqual((yield dut.chooser.cmd.ba), 2) - yield from invalidate(2) - self.assertEqual((yield dut.chooser.cmd.ba), 3) - yield from invalidate(3) - self.assertEqual((yield dut.chooser.cmd.ba), 0) - - dut = CommandChooserDUT(n_requests=4, bankbits=3, addressbits=13) - run_simulation(dut, main_generator(dut)) - - def test_selects_next_when_cmd_ready(self): - # Verify that next request is chosen when the current one becomes ready. - def main_generator(dut): - yield dut.chooser.want_cmds.eq(1) - yield from dut.set_requests("pppp") - yield - - # Advance to next request - def cmd_ready(): - yield dut.chooser.cmd.ready.eq(1) - yield - yield dut.chooser.cmd.ready.eq(0) - yield - - # First request is selected as it is valid and ~ready - self.assertEqual((yield dut.chooser.cmd.ba), 0) - yield - self.assertEqual((yield dut.chooser.cmd.ba), 0) - - # After deactivating valid arbiter should choose next request - yield from cmd_ready() - self.assertEqual((yield dut.chooser.cmd.ba), 1) - yield from cmd_ready() - self.assertEqual((yield dut.chooser.cmd.ba), 2) - yield from cmd_ready() - self.assertEqual((yield dut.chooser.cmd.ba), 3) - yield from cmd_ready() - self.assertEqual((yield dut.chooser.cmd.ba), 0) - - dut = CommandChooserDUT(n_requests=4, bankbits=3, addressbits=13) - run_simulation(dut, main_generator(dut)) - - def selection_test(self, requests, expected_order, wants): - # Set requests to given states and tests whether they are being connected - # to chooser.cmd in the expected order. Using `ba` value to distinguish - # requests (as initialised in CommandChooserDUT). - # "_" means no valid request. - def main_generator(dut): - for want in wants: - yield getattr(dut.chooser, want).eq(1) - - yield from dut.set_requests(requests) - yield - - for i, expected_index in enumerate(expected_order): - error_msg = f"requests={requests}, expected_order={expected_order}, i={i}" - if expected_index == "_": # not valid - cas/ras/we should be 0 - cas = (yield dut.chooser.cmd.cas) - ras = (yield dut.chooser.cmd.ras) - we = (yield dut.chooser.cmd.we) - self.assertEqual((cas, ras, we), (0, 0, 0), msg=error_msg) - else: - # Check that ba is as expected - selected_request_index = (yield dut.chooser.cmd.ba) - self.assertEqual(selected_request_index, int(expected_index), msg=error_msg) - - # Advance to next request - yield dut.chooser.cmd.ready.eq(1) - yield - yield dut.chooser.cmd.ready.eq(0) - yield - - assert len(requests) == 8 - dut = CommandChooserDUT(n_requests=8, bankbits=3, addressbits=13) - run_simulation(dut, main_generator(dut)) - - @unittest.skip("Issue #174") - def test_selects_nothing(self): - # When want_* = 0, chooser should set cas/ras/we = 0, which means not valid request - requests = "w_rawpwr" - order = "____" # cas/ras/we are never set - self.selection_test(requests, order, wants=[]) - - def test_selects_writes(self): - requests = "w_rawpwr" - order = "0460460" - self.selection_test(requests, order, wants=["want_writes"]) - - def test_selects_reads(self): - requests = "rp_awrrw" - order = "0560560" - self.selection_test(requests, order, wants=["want_reads"]) - - @unittest.skip("Issue #174") - def test_selects_writes_and_reads(self): - requests = "rp_awrrw" - order = "04567045670" - self.selection_test(requests, order, wants=["want_reads", "want_writes"]) - - @unittest.skip("Issue #174") - def test_selects_cmds_without_act(self): - # When want_cmds = 1, but want_activates = 0, activate commands should not be selected - requests = "pr_aa_pw" - order = "06060" - self.selection_test(requests, order, wants=["want_cmds"]) - - def test_selects_cmds_with_act(self): - # When want_cmds/activates = 1, both activate and precharge should be selected - requests = "pr_aa_pw" - order = "034603460" - self.selection_test(requests, order, wants=["want_cmds", "want_activates"]) - - @unittest.skip("Issue #174") - def test_selects_nothing_when_want_activates_only(self): - # When only want_activates = 1, nothing will be selected - requests = "pr_aa_pw" - order = "____" - self.selection_test(requests, order, wants=["want_activates"]) - - def test_selects_cmds_and_writes(self): - requests = "pr_aa_pw" - order = "0670670" - self.selection_test(requests, order, wants=["want_cmds", "want_writes"]) diff --git a/test/test_crossbar.py b/test/test_crossbar.py deleted file mode 100644 index 53d8886..0000000 --- a/test/test_crossbar.py +++ /dev/null @@ -1,511 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import random -import unittest -import functools -import itertools -from collections import namedtuple, defaultdict - -from migen import * - -from litedram.common import * -from litedram.core.crossbar import LiteDRAMCrossbar - -from test.common import timeout_generator, NativePortDriver - - -class ControllerStub: - """Simplified simulation of LiteDRAMController as seen by LiteDRAMCrossbar - - This is a simplified implementation of LiteDRAMController suitable for - testing the crossbar. It consisits of bankmachine handlers that try to mimic - behaviour of real BankMachines. They also simulate data transmission by - scheduling it to appear on data interface (data_handler sets it). - """ - W = namedtuple("WriteData", ["bank", "addr", "data", "we"]) - R = namedtuple("ReadData", ["bank", "addr", "data"]) - WaitingData = namedtuple("WaitingData", ["delay", "data"]) - - def __init__(self, controller_interface, write_latency, read_latency, cmd_delay=None): - self.interface = controller_interface - self.write_latency = write_latency - self.read_latency = read_latency - self.data = [] # data registered on datapath (W/R) - self._waiting = [] # data waiting to be set on datapath - # Incremental generator of artificial read data - self._read_data = itertools.count(0x10) - # Simulated dealy of command processing, by default just constant - self._cmd_delay = cmd_delay or (lambda: 6) - # Minimal logic required so that no two banks will become ready at the same moment - self._multiplexer_lock = None - - def generators(self): - bank_handlers = [self.bankmachine_handler(bn) for bn in range(self.interface.nbanks)] - return [self.data_handler(), *bank_handlers] - - @passive - def data_handler(self): - # Responsible for passing data over datapath with requested latency - while True: - # Examine requests to find if there is any for that cycle - available = [w for w in self._waiting if w.delay == 0] - # Make sure that it is never the case that we have more then 1 - # operation of the same type - type_counts = defaultdict(int) - for a in available: - type_counts[type(a.data)] += 1 - for t, count in type_counts.items(): - assert count == 1, \ - "%d data operations of type %s at the same time!" % (count, t.__name__) - for a in available: - # Remove it from the list and get the data - current = self._waiting.pop(self._waiting.index(a)).data - # If this was a write, then fill it with data from this cycle - if isinstance(current, self.W): - current = current._replace( - data=(yield self.interface.wdata), - we=(yield self.interface.wdata_we), - ) - # If this was a read, then assert the data now - elif isinstance(current, self.R): - yield self.interface.rdata.eq(current.data) - else: - raise TypeError(current) - # Add it to the data that appeared on the datapath - self.data.append(current) - # Advance simulation time by 1 cycle - for i, w in enumerate(self._waiting): - self._waiting[i] = w._replace(delay=w.delay - 1) - yield - - @passive - def bankmachine_handler(self, n): - # Simplified simulation of a bank machine. - # Uses a single buffer (no input fifo). Generates random read data. - bank = getattr(self.interface, "bank%d" % n) - while True: - # Wait for a valid bank command - while not (yield bank.valid): - # The lock is being held as long as there is a valid command - # in the buffer or there is a valid command on the interface. - # As at this point we have nothing in the buffer, we unlock - # the lock only if the command on the interface is not valid. - yield bank.lock.eq(0) - yield - # Latch the command to the internal buffer - cmd_addr = (yield bank.addr) - cmd_we = (yield bank.we) - # Lock the buffer as soon as command is valid on the interface. - # We do this 1 cycle after we see the command, but BankMachine - # also has latency, because cmd_buffer_lookahead.source must - # become valid. - yield bank.lock.eq(1) - yield bank.ready.eq(1) - yield - yield bank.ready.eq(0) - # Simulate that we are processing the command - for _ in range(self._cmd_delay()): - yield - # Avoid situation that can happen due to the lack of multiplexer, - # where more than one bank would send data at the same moment - while self._multiplexer_lock is not None: - yield - self._multiplexer_lock = n - yield - # After READ/WRITE has been issued, this is signalized by using - # rdata_valid/wdata_ready. The actual data will appear with latency. - if cmd_we: # WRITE - yield bank.wdata_ready.eq(1) - yield - yield bank.wdata_ready.eq(0) - # Send a request to the data_handler, it will check what - # has been sent from the crossbar port. - wdata = self.W(bank=n, addr=cmd_addr, - data=None, we=None) # to be filled in callback - self._waiting.append(self.WaitingData(data=wdata, delay=self.write_latency)) - else: # READ - yield bank.rdata_valid.eq(1) - yield - yield bank.rdata_valid.eq(0) - # Send a request with "data from memory" to the data_handler - rdata = self.R(bank=n, addr=cmd_addr, data=next(self._read_data)) - # Decrease latecy, as data_handler sets data with 1 cycle delay - self._waiting.append(self.WaitingData(data=rdata, delay=self.read_latency - 1)) - # At this point cmd_buffer.source.ready has been activated and the - # command in internal buffer has been discarded. The lock will be - self._multiplexer_lock = None - # removed in next loop if there is no other command pending. - yield - - -class CrossbarDUT(Module): - default_controller_settings = dict( - cmd_buffer_depth = 8, - address_mapping = "ROW_BANK_COL", - ) - default_phy_settings = dict( - cwl = 2, - nphases = 2, - nranks = 1, - memtype = "DDR2", - dfi_databits = 2*16, - read_latency = 5, - write_latency = 1, - ) - default_geom_settings = dict( - bankbits = 3, - rowbits = 13, - colbits = 10, - ) - - def __init__(self, controller_settings=None, phy_settings=None, geom_settings=None): - # update settings if provided - def updated(settings, update): - copy = settings.copy() - copy.update(update or {}) - return copy - - controller_settings = updated(self.default_controller_settings, controller_settings) - phy_settings = updated(self.default_phy_settings, phy_settings) - geom_settings = updated(self.default_geom_settings, geom_settings) - - class SimpleSettings(Settings): - def __init__(self, **kwargs): - self.set_attributes(kwargs) - - settings = SimpleSettings(**controller_settings) - settings.phy = SimpleSettings(**phy_settings) - settings.geom = SimpleSettings(**geom_settings) - self.settings = settings - - self.address_align = log2_int(burst_lengths[settings.phy.memtype]) - self.interface = LiteDRAMInterface(self.address_align, settings) - self.submodules.crossbar = LiteDRAMCrossbar(self.interface) - - def addr_port(self, bank, row, col): - # construct an address the way port master would do it - assert self.settings.address_mapping == "ROW_BANK_COL" - aa = self.address_align - cb = self.settings.geom.colbits - rb = self.settings.geom.rowbits - bb = self.settings.geom.bankbits - col = (col & (2**cb - 1)) >> aa - bank = (bank & (2**bb - 1)) << (cb - aa) - row = (row & (2**rb - 1)) << (cb + bb - aa) - return row | bank | col - - def addr_iface(self, row, col): - # construct address the way bankmachine should receive it - aa = self.address_align - cb = self.settings.geom.colbits - rb = self.settings.geom.rowbits - col = (col & (2**cb - 1)) >> aa - row = (row & (2**rb - 1)) << (cb - aa) - return row | col - - -class TestCrossbar(unittest.TestCase): - W = ControllerStub.W - R = ControllerStub.R - - def test_init(self): - dut = CrossbarDUT() - dut.crossbar.get_port() - dut.finalize() - - def crossbar_test(self, dut, generators, timeout=100, **kwargs): - # Runs simulation with a controller stub (passive generators) and user generators - if not isinstance(generators, list): - generators = [generators] - controller = ControllerStub(dut.interface, - write_latency=dut.settings.phy.write_latency, - read_latency=dut.settings.phy.read_latency, - **kwargs) - generators += [*controller.generators(), timeout_generator(timeout)] - run_simulation(dut, generators) - return controller.data - - def test_available_address_mappings(self): - # Check that the only supported address mapping is ROW_BANK_COL (if we start supporting new - # mappings, then update these tests to also test these other mappings). - def finalize_crossbar(mapping): - dut = CrossbarDUT(controller_settings=dict(address_mapping=mapping)) - dut.crossbar.get_port() - dut.crossbar.finalize() - - for mapping in ["ROW_BANK_COL", "BANK_ROW_COL"]: - if mapping in ["ROW_BANK_COL"]: - finalize_crossbar(mapping) - else: - with self.assertRaises(KeyError): - finalize_crossbar(mapping) - - def test_address_mappings(self): - # Verify that address is translated correctly. - reads = [] - - def producer(dut, port): - driver = NativePortDriver(port) - for t in transfers: - addr = dut.addr_port(bank=t["bank"], row=t["row"], col=t["col"]) - if t["rw"] == self.W: - yield from driver.write(addr, data=t["data"], we=t.get("we", None)) - elif t["rw"] == self.R: - data = (yield from driver.read(addr)) - reads.append(data) - else: - raise TypeError(t["rw"]) - - geom_settings = dict(colbits=10, rowbits=13, bankbits=2) - dut = CrossbarDUT(geom_settings=geom_settings) - port = dut.crossbar.get_port() - transfers = [ - dict(rw=self.W, bank=2, row=0x30, col=0x03, data=0x20), - dict(rw=self.W, bank=3, row=0x30, col=0x03, data=0x21), - dict(rw=self.W, bank=2, row=0xab, col=0x03, data=0x22), - dict(rw=self.W, bank=2, row=0x30, col=0x13, data=0x23), - dict(rw=self.R, bank=1, row=0x10, col=0x99), - dict(rw=self.R, bank=0, row=0x10, col=0x99), - dict(rw=self.R, bank=1, row=0xcd, col=0x99), - dict(rw=self.R, bank=1, row=0x10, col=0x77), - ] - expected = [] - for i, t in enumerate(transfers): - cls = t["rw"] - addr = dut.addr_iface(row=t["row"], col=t["col"]) - if cls == self.W: - kwargs = dict(data=t["data"], we=0xff) - elif cls == self.R: - kwargs = dict(data=0x10 + i) - return cls(bank=t["bank"], addr=addr, **kwargs) - - data = self.crossbar_test(dut, producer(port)) - self.assertEqual(data, expected) - - def test_arbitration(self): - # Create multiple masters that write to the same bank at the same time and verify that all - # the requests have been sent correctly. - def producer(dut, port, num): - driver = NativePortDriver(port) - addr = dut.addr_port(bank=3, row=0x10 + num, col=0x20 + num) - yield from driver.write(addr, data=0x30 + num) - - dut = CrossbarDUT() - ports = [dut.crossbar.get_port() for _ in range(4)] - masters = [producer(dut, port, i) for i, port in enumerate(ports)] - data = self.crossbar_test(dut, masters) - expected = { - self.W(bank=3, addr=dut.addr_iface(row=0x10, col=0x20), data=0x30, we=0xff), - self.W(bank=3, addr=dut.addr_iface(row=0x11, col=0x21), data=0x31, we=0xff), - self.W(bank=3, addr=dut.addr_iface(row=0x12, col=0x22), data=0x32, we=0xff), - self.W(bank=3, addr=dut.addr_iface(row=0x13, col=0x23), data=0x33, we=0xff), - } - self.assertEqual(set(data), expected) - - def test_lock_write(self): - # Verify that the locking mechanism works - # Create a situation when one master A wants to write to banks 0 then 1, but master B is - # continuously writing to bank 1 (bank is locked) so that master A is blocked. We use - # wait_data=False because we are only concerned about sending commands fast enough for - # the lock to be held continuously. - def master_a(dut, port): - driver = NativePortDriver(port) - adr = functools.partial(dut.addr_port, row=1, col=1) - write = functools.partial(driver.write, wait_data=False) - yield from write(adr(bank=0), data=0x10) - yield from write(adr(bank=1), data=0x11) - yield from write(adr(bank=0), data=0x12, wait_data=True) - - def master_b(dut, port): - driver = NativePortDriver(port) - adr = functools.partial(dut.addr_port, row=2, col=2) - write = functools.partial(driver.write, wait_data=False) - yield from write(adr(bank=1), data=0x20) - yield from write(adr(bank=1), data=0x21) - yield from write(adr(bank=1), data=0x22) - yield from write(adr(bank=1), data=0x23) - yield from write(adr(bank=1), data=0x24) - - dut = CrossbarDUT() - ports = [dut.crossbar.get_port() for _ in range(2)] - data = self.crossbar_test(dut, [master_a(dut, ports[0]), master_b(dut, ports[1])]) - expected = [ - self.W(bank=0, addr=dut.addr_iface(row=1, col=1), data=0x10, we=0xff), # A - self.W(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x20, we=0xff), # B - self.W(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x21, we=0xff), # B - self.W(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x22, we=0xff), # B - self.W(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x23, we=0xff), # B - self.W(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x24, we=0xff), # B - self.W(bank=1, addr=dut.addr_iface(row=1, col=1), data=0x11, we=0xff), # A - self.W(bank=0, addr=dut.addr_iface(row=1, col=1), data=0x12, we=0xff), # A - ] - self.assertEqual(data, expected) - - def test_lock_read(self): - # Verify that the locking mechanism works. - def master_a(dut, port): - driver = NativePortDriver(port) - adr = functools.partial(dut.addr_port, row=1, col=1) - read = functools.partial(driver.read, wait_data=False) - yield from read(adr(bank=0)) - yield from read(adr(bank=1)) - yield from read(adr(bank=0)) - # Wait for read data to show up - for _ in range(16): - yield - - def master_b(dut, port): - driver = NativePortDriver(port) - adr = functools.partial(dut.addr_port, row=2, col=2) - read = functools.partial(driver.read, wait_data=False) - yield from read(adr(bank=1)) - yield from read(adr(bank=1)) - yield from read(adr(bank=1)) - yield from read(adr(bank=1)) - yield from read(adr(bank=1)) - - dut = CrossbarDUT() - ports = [dut.crossbar.get_port() for _ in range(2)] - data = self.crossbar_test(dut, [master_a(dut, ports[0]), master_b(dut, ports[1])]) - expected = [ - self.R(bank=0, addr=dut.addr_iface(row=1, col=1), data=0x10), # A - self.R(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x11), # B - self.R(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x12), # B - self.R(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x13), # B - self.R(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x14), # B - self.R(bank=1, addr=dut.addr_iface(row=2, col=2), data=0x15), # B - self.R(bank=1, addr=dut.addr_iface(row=1, col=1), data=0x16), # A - self.R(bank=0, addr=dut.addr_iface(row=1, col=1), data=0x17), # A - ] - self.assertEqual(data, expected) - - def crossbar_stress_test(self, dut, ports, n_banks, n_ops, clocks=None): - # Runs simulation with multiple masters writing and reading to multiple banks - controller = ControllerStub(dut.interface, - write_latency=dut.settings.phy.write_latency, - read_latency=dut.settings.phy.read_latency) - # Store data produced per master - produced = defaultdict(list) - prng = random.Random(42) - - def master(dut, port, num): - # Choose operation types based on port mode - ops_choice = { - "both": ["w", "r"], - "write": ["w"], - "read": ["r"], - }[port.mode] - driver = NativePortDriver(port) - - for i in range(n_ops): - bank = prng.randrange(n_banks) - # We will later distinguish data by its row address - row = num - col = 0x20 * num + i - addr = dut.addr_port(bank=bank, row=row, col=col) - addr_iface = dut.addr_iface(row=row, col=col) - if prng.choice(ops_choice) == "w": - yield from driver.write(addr, data=i) - produced[num].append(self.W(bank, addr_iface, data=i, we=0xff)) - else: - yield from driver.read(addr) - produced[num].append(self.R(bank, addr_iface, data=None)) - - for _ in range(8): - yield - - generators = defaultdict(list) - for i, port in enumerate(ports): - generators[port.clock_domain].append(master(dut, port, i)) - generators["sys"] += controller.generators() - generators["sys"].append(timeout_generator(80 * n_ops)) - - sim_kwargs = {} - if clocks is not None: - sim_kwargs["clocks"] = clocks - run_simulation(dut, generators, **sim_kwargs) - - # Split controller data by master, as this is what we want to compare - consumed = defaultdict(list) - for data in controller.data: - master = data.addr >> (dut.settings.geom.colbits - dut.address_align) - if isinstance(data, self.R): - # Master couldn't know the data when it was sending - data = data._replace(data=None) - consumed[master].append(data) - - return produced, consumed, controller.data - - def test_stress(self): - # Test communication in complex scenarios. - dut = CrossbarDUT() - ports = [dut.crossbar.get_port() for _ in range(8)] - produced, consumed, consumed_all = self.crossbar_stress_test(dut, ports, n_banks=4, n_ops=8) - for master in produced.keys(): - self.assertEqual(consumed[master], produced[master], msg="master = %d" % master) - - def test_stress_single_bank(self): - # Test communication in complex scenarios - dut = CrossbarDUT() - ports = [dut.crossbar.get_port() for _ in range(4)] - produced, consumed, consumed_all = self.crossbar_stress_test(dut, ports, n_banks=1, n_ops=8) - for master in produced.keys(): - self.assertEqual(consumed[master], produced[master], msg="master = %d" % master) - - def test_stress_single_master(self): - # Test communication in complex scenarios. - dut = CrossbarDUT() - ports = [dut.crossbar.get_port() for _ in range(1)] - produced, consumed, consumed_all = self.crossbar_stress_test(dut, ports, n_banks=4, n_ops=8) - for master in produced.keys(): - self.assertEqual(consumed[master], produced[master], msg="master = %d" % master) - - def test_port_cdc(self): - # Verify that correct clock domain is being used. - dut = CrossbarDUT() - port = dut.crossbar.get_port(clock_domain="other") - self.assertEqual(port.clock_domain, "other") - - def test_stress_cdc(self): - # Verify communication when ports are in different clock domains. - dut = CrossbarDUT() - clocks = { - "sys": 10, - "clk1": (7, 4), - "clk2": 12, - } - master_clocks = ["sys", "clk1", "clk2"] - ports = [dut.crossbar.get_port(clock_domain=clk) for clk in master_clocks] - produced, consumed, consumed_all = self.crossbar_stress_test( - dut, ports, n_banks=4, n_ops=6, clocks=clocks) - for master in produced.keys(): - self.assertEqual(consumed[master], produced[master], msg="master = %d" % master) - - def test_port_mode(self): - # Verify that ports in different modes can be requested. - dut = CrossbarDUT() - for mode in ["both", "write", "read"]: - port = dut.crossbar.get_port(mode=mode) - self.assertEqual(port.mode, mode) - - # NOTE: Stress testing with different data widths would require complicating - # the logic a lot to support registering data comming in multiple words (in - # data_handler), address shifting and recreation of packets. Because of this, - # and because data width converters are tested separately in test_adaptation, - # here we only test if ports report correct data widths. - def test_port_data_width_conversion(self): - # Verify that correct port data widths are being used. - dut = CrossbarDUT() - dw = dut.interface.data_width - data_widths = [dw*2, dw, dw//2] - modes = ["both", "write", "read"] - for mode, data_width in itertools.product(modes, data_widths): - with self.subTest(mode=mode, data_width=data_width): - # Up conversion is supported only for single direction ports - if mode == "both" and data_width < dut.interface.data_width: - with self.assertRaises(NotImplementedError): - dut.crossbar.get_port(mode=mode, data_width=data_width) - else: - port = dut.crossbar.get_port(mode=mode, data_width=data_width) - self.assertEqual(port.data_width, data_width) diff --git a/test/test_dma.py b/test/test_dma.py deleted file mode 100644 index 138a13a..0000000 --- a/test/test_dma.py +++ /dev/null @@ -1,174 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest - -from migen import * - -from litex.gen.sim import * - -from litedram.common import * -from litedram.frontend.dma import * - -from test.common import * - - -class DMAWriterDriver: - def __init__(self, dma): - self.dma = dma - - def write(self, pattern): - yield self.dma.sink.valid.eq(1) - for adr, data in pattern: - yield self.dma.sink.address.eq(adr) - yield self.dma.sink.data.eq(data) - while not (yield self.dma.sink.ready): - yield - yield - yield self.dma.sink.valid.eq(0) - - @staticmethod - def wait_complete(port, n): - for _ in range(n): - while not (yield port.wdata.ready): - yield - yield - - -class DMAReaderDriver: - def __init__(self, dma): - self.dma = dma - self.data = [] - - def read(self, address_list): - n_last = len(self.data) - yield self.dma.sink.valid.eq(1) - for adr in address_list: - yield self.dma.sink.address.eq(adr) - while not (yield self.dma.sink.ready): - yield - while (yield self.dma.sink.ready): - yield - yield self.dma.sink.valid.eq(0) - while len(self.data) < n_last + len(address_list): - yield - - @passive - def read_handler(self): - yield self.dma.source.ready.eq(1) - while True: - if (yield self.dma.source.valid): - self.data.append((yield self.dma.source.data)) - yield - - -class TestDMA(MemoryTestDataMixin, unittest.TestCase): - - # LiteDRAMDMAWriter ---------------------------------------------------------------------------- - - def dma_writer_test(self, pattern, mem_expected, data_width, **kwargs): - class DUT(Module): - def __init__(self): - self.port = LiteDRAMNativeWritePort(address_width=32, data_width=data_width) - self.submodules.dma = LiteDRAMDMAWriter(self.port, **kwargs) - - dut = DUT() - driver = DMAWriterDriver(dut.dma) - mem = DRAMMemory(data_width, len(mem_expected)) - - generators = [ - driver.write(pattern), - driver.wait_complete(dut.port, len(pattern)), - mem.write_handler(dut.port), - ] - run_simulation(dut, generators) - self.assertEqual(mem.mem, mem_expected) - - def test_dma_writer_single(self): - # Verify DMAWriter with a single 32-bit data. - pattern = [(0x04, 0xdeadc0de)] - mem_expected = [0] * 32 - mem_expected[0x04] = 0xdeadc0de - self.dma_writer_test(pattern, mem_expected, data_width=32) - - def test_dma_writer_multiple(self): - # Verify DMAWriter with multiple 32-bit datas. - data = self.pattern_test_data["32bit"] - self.dma_writer_test(data["pattern"], data["expected"], data_width=32) - - def test_dma_writer_sequential(self): - # Verify DMAWriter with sequential 32-bit datas. - data = self.pattern_test_data["32bit_sequential"] - self.dma_writer_test(data["pattern"], data["expected"], data_width=32) - - def test_dma_writer_long_sequential(self): - # Verify DMAWriter with long sequential 32-bit datas. - data = self.pattern_test_data["32bit_long_sequential"] - self.dma_writer_test(data["pattern"], data["expected"], data_width=32) - - def test_dma_writer_no_fifo(self): - # Verify DMAWriter without FIFO. - data = self.pattern_test_data["32bit_long_sequential"] - self.dma_writer_test(data["pattern"], data["expected"], data_width=32, fifo_depth=1) - - def test_dma_writer_fifo_buffered(self): - # Verify DMAWriter with a buffered FIFO. - data = self.pattern_test_data["32bit_long_sequential"] - self.dma_writer_test(data["pattern"], data["expected"], data_width=32, fifo_buffered=True) - - def test_dma_writer_duplicates(self): - # Verify DMAWriter with a duplicate addresses. - data = self.pattern_test_data["32bit_duplicates"] - self.dma_writer_test(data["pattern"], data["expected"], data_width=32) - - # LiteDRAMDMAReader ---------------------------------------------------------------------------- - - def dma_reader_test(self, pattern, mem_expected, data_width, **kwargs): - class DUT(Module): - def __init__(self): - self.port = LiteDRAMNativeReadPort(address_width=32, data_width=data_width) - self.submodules.dma = LiteDRAMDMAReader(self.port, **kwargs) - - dut = DUT() - driver = DMAReaderDriver(dut.dma) - mem = DRAMMemory(data_width, len(mem_expected), init=mem_expected) - - generators = [ - driver.read([adr for adr, data in pattern]), - driver.read_handler(), - mem.read_handler(dut.port), - ] - run_simulation(dut, generators) - self.assertEqual(driver.data, [data for adr, data in pattern]) - - def test_dma_reader_single(self): - # Verify DMAReader with a single 32-bit data. - pattern = [(0x04, 0xdeadc0de)] - mem_expected = [0] * 32 - mem_expected[0x04] = 0xdeadc0de - self.dma_reader_test(pattern, mem_expected, data_width=32) - - def test_dma_reader_multiple(self): - # Verify DMAReader with multiple 32-bit datas. - data = self.pattern_test_data["32bit"] - self.dma_reader_test(data["pattern"], data["expected"], data_width=32) - - def test_dma_reader_sequential(self): - # Verify DMAReader with sequential 32-bit datas. - data = self.pattern_test_data["32bit_sequential"] - self.dma_reader_test(data["pattern"], data["expected"], data_width=32) - - def test_dma_reader_long_sequential(self): - # Verify DMAReader with long sequential 32-bit datas. - data = self.pattern_test_data["32bit_long_sequential"] - self.dma_reader_test(data["pattern"], data["expected"], data_width=32) - - def test_dma_reader_no_fifo(self): - # Verify DMAReader without FIFO. - data = self.pattern_test_data["32bit_long_sequential"] - self.dma_reader_test(data["pattern"], data["expected"], data_width=32, fifo_depth=1) - - def test_dma_reader_fifo_buffered(self): - # Verify DMAReader with a buffered FIFO. - data = self.pattern_test_data["32bit_long_sequential"] - self.dma_reader_test(data["pattern"], data["expected"], data_width=32, fifo_buffered=True) diff --git a/test/test_ecc.py b/test/test_ecc.py deleted file mode 100644 index 2da84da..0000000 --- a/test/test_ecc.py +++ /dev/null @@ -1,321 +0,0 @@ -# This file is Copyright (c) 2018-2019 Florent Kermarrec -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest -import random - -from migen import * - -from litedram.common import * -from litedram.frontend.ecc import * - -from litex.gen.sim import * -from litex.soc.cores.ecc import * - -from test.common import * - -# Helpers ------------------------------------------------------------------------------------------ - -def bits(value, width=32): - # Convert int to a string representing binary value and reverse it so that we can index bits - # easily with s[0] being LSB - return f"{value:0{width}b}"[::-1] - -def frombits(bits): - # Reverse of bits() - return int(bits[::-1], 2) - -def bits_pp(value, width=32): - # Pretty print binary value, groupped by bytes - if isinstance(value, str): - value = frombits(value) - s = f"{value:0{width}b}" - byte_chunks = [s[i:i+8] for i in range(0, len(s), 8)] - return "0b " + " ".join(byte_chunks) - -def extract_ecc_data(data_width, codeword_width, codeword_bits): - extracted = "" - for i in range(8): - word = codeword_bits[codeword_width*i:codeword_width*(i+1)] - # Remove parity bit - word = word[1:] - data_pos = compute_data_positions(codeword_width - 1) # -1 for parity - # Extract data bits - word_ex = list(bits(0, 32)) - for j, d in enumerate(data_pos): - word_ex[j] = word[d-1] - word_ex = "".join(word_ex) - extracted += word_ex - return extracted - -# TestECC ------------------------------------------------------------------------------------------ - -class TestECC(unittest.TestCase): - def test_eccw_connected(self): - # Verify LiteDRAMNativePortECCW ECC encoding. - class DUT(Module): - def __init__(self): - eccw = LiteDRAMNativePortECCW(data_width_from=32*8, data_width_to=39*8) - self.submodules.eccw = eccw - - def main_generator(dut): - sink_data = seed_to_data(0, nbits=32*8) - yield dut.eccw.sink.data.eq(sink_data) - yield - source_data = (yield dut.eccw.source.data) - - sink_data_bits = bits(sink_data, 32*8) - source_data_bits = bits(source_data, 39*8) - self.assertNotEqual(sink_data_bits, source_data_bits[:len(sink_data_bits)]) - - source_extracted = extract_ecc_data(32, 39, source_data_bits) - # Assert each word separately for more readable assert messages - for i in range(8): - word = slice(32*i, 32*(i+1)) - self.assertEqual(bits_pp(source_extracted[word]), bits_pp(sink_data_bits[word]), - msg=f"Mismatch at i = {i}") - - dut = DUT() - run_simulation(dut, main_generator(dut)) - - def test_eccw_we_enabled(self): - # Verify LiteDRAMNativePortECCW always set bytes enable. - class DUT(Module): - def __init__(self): - eccw = LiteDRAMNativePortECCW(data_width_from=32*8, data_width_to=39*8) - self.submodules.eccw = eccw - - def main_generator(dut): - yield - source_we = (yield dut.eccw.source.we) - - self.assertEqual(bits_pp(source_we, 39//8), bits_pp(2**len(dut.eccw.source.we) - 1)) - - dut = DUT() - run_simulation(dut, main_generator(dut)) - - def test_eccr_connected(self): - # Verify LiteDRAMNativePortECCR ECC decoding. - class DUT(Module): - def __init__(self): - eccr = LiteDRAMNativePortECCR(data_width_from=32*8, data_width_to=39*8) - self.submodules.eccr = eccr - - def main_generator(dut): - sink_data = seed_to_data(0, nbits=(39*8 // 32 + 1) * 32) - - yield dut.eccr.sink.data.eq(sink_data) - yield - source_data = (yield dut.eccr.source.data) - - sink_data_bits = bits(sink_data, 39*8) - source_data_bits = bits(source_data, 32*8) - self.assertNotEqual(sink_data_bits[:len(source_data_bits)], source_data_bits) - - sink_extracted = extract_ecc_data(32, 39, sink_data_bits) - self.assertEqual(bits_pp(sink_extracted), bits_pp(source_data_bits)) - # Assert each word separately for more readable assert messages - for i in range(8): - word = slice(32*i, 32*(i+1)) - self.assertEqual(bits_pp(sink_extracted[word]), bits_pp(source_data_bits[word]), - msg=f"Mismatch at i = {i}") - - dut = DUT() - run_simulation(dut, main_generator(dut)) - - def test_eccr_errors_connected_when_sink_valid(self): - # Verify LiteDRAMNativePortECCR Error detection. - class DUT(Module): - def __init__(self): - eccr = LiteDRAMNativePortECCR(data_width_from=32*8, data_width_to=39*8) - self.submodules.eccr = eccr - - def main_generator(dut): - yield dut.eccr.enable.eq(1) - yield dut.eccr.sink.data.eq(0b10) # Wrong parity bit - yield - # Verify no errors are detected - self.assertEqual((yield dut.eccr.sec), 0) - self.assertEqual((yield dut.eccr.ded), 0) - # Set sink.valid and verify errors parity error is detected - yield dut.eccr.sink.valid.eq(1) - yield - self.assertEqual((yield dut.eccr.sec), 1) - self.assertEqual((yield dut.eccr.ded), 0) - - dut = DUT() - run_simulation(dut, main_generator(dut)) - - def ecc_encode_decode_test(self, from_width, to_width, n, pre=None, post=None, **kwargs): - """ECC encoding/decoding generic test.""" - class DUT(Module): - def __init__(self): - self.port_from = LiteDRAMNativePort("both", 24, from_width) - self.port_to = LiteDRAMNativePort("both", 24, to_width) - self.submodules.ecc = LiteDRAMNativePortECC(self.port_from, self.port_to, **kwargs) - self.mem = DRAMMemory(to_width, n) - - self.wdata = [seed_to_data(i, nbits=from_width) for i in range(n)] - self.rdata = [] - - def main_generator(dut): - if pre is not None: - yield from pre(dut) - - port = dut.port_from - - # Write - for i in range(n): - yield port.cmd.valid.eq(1) - yield port.cmd.we.eq(1) - yield port.cmd.addr.eq(i) - yield - while (yield port.cmd.ready) == 0: - yield - yield port.cmd.valid.eq(0) - yield - yield port.wdata.valid.eq(1) - yield port.wdata.data.eq(dut.wdata[i]) - yield - while (yield port.wdata.ready) == 0: - yield - yield port.wdata.valid.eq(0) - yield - - # Read - for i in range(n): - yield port.cmd.valid.eq(1) - yield port.cmd.we.eq(0) - yield port.cmd.addr.eq(i) - yield - while (yield port.cmd.ready) == 0: - yield - yield port.cmd.valid.eq(0) - yield - while (yield port.rdata.valid) == 0: - yield - dut.rdata.append((yield port.rdata.data)) - yield port.rdata.ready.eq(1) - yield - yield port.rdata.ready.eq(0) - yield - - if post is not None: - yield from post(dut) - - dut = DUT() - generators = [ - main_generator(dut), - dut.mem.write_handler(dut.port_to), - dut.mem.read_handler(dut.port_to), - ] - run_simulation(dut, generators) - return dut - - def test_ecc_32_7(self): - # Verify encoding/decoding on 32 data bits + 6 code bits + parity bit. - dut = self.ecc_encode_decode_test(32*8, 39*8, 2) - self.assertEqual(dut.wdata, dut.rdata) - - def test_ecc_64_8(self): - # Verify encoding/decoding on 64 data bits + 7 code bits + parity bit. - dut = self.ecc_encode_decode_test(64*8, 72*8, 2) - self.assertEqual(dut.wdata, dut.rdata) - - def test_ecc_sec_errors(self): - # Verify SEC errors detection/correction with 1-bit flip. - def pre(dut): - yield from dut.ecc.flip.write(0b00000100) - - def post(dut): - dut.sec_errors = (yield from dut.ecc.sec_errors.read()) - dut.ded_errors = (yield from dut.ecc.ded_errors.read()) - - dut = self.ecc_encode_decode_test(8*8, 13*8, 4, pre, post, with_error_injection=True) - self.assertEqual(dut.wdata, dut.rdata) - self.assertEqual(dut.sec_errors, 4) - self.assertEqual(dut.ded_errors, 0) - - def test_ecc_ded_errors(self): - # Verify DED errors detection with 2-bit flip. - def pre(dut): - yield from dut.ecc.flip.write(0b00001100) - - def post(dut): - dut.sec_errors = (yield from dut.ecc.sec_errors.read()) - dut.ded_errors = (yield from dut.ecc.ded_errors.read()) - - dut = self.ecc_encode_decode_test(8*8, 13*8, 4, pre, post, with_error_injection=True) - self.assertNotEqual(dut.wdata, dut.rdata) - self.assertEqual(dut.sec_errors, 0) - self.assertEqual(dut.ded_errors, 4) - - def test_ecc_decoder_disable(self): - # Verify enable control. - def pre(dut): - yield from dut.ecc.flip.write(0b10101100) - yield from dut.ecc.enable.write(0) - - def post(dut): - dut.sec_errors = (yield from dut.ecc.sec_errors.read()) - dut.ded_errors = (yield from dut.ecc.ded_errors.read()) - - dut = self.ecc_encode_decode_test(8*8, 13*8, 4, pre, post, with_error_injection=True) - self.assertNotEqual(dut.wdata, dut.rdata) - self.assertEqual(dut.sec_errors, 0) - self.assertEqual(dut.ded_errors, 0) - - def test_ecc_clear_sec_errors(self): - # Verify SEC errors clear. - def pre(dut): - yield from dut.ecc.flip.write(0b00000100) - - def post(dut): - # Read errors after test (SEC errors expected) - dut.sec_errors = (yield from dut.ecc.sec_errors.read()) - dut.ded_errors = (yield from dut.ecc.ded_errors.read()) - - # Clear errors counters - yield from dut.ecc.clear.write(1) - yield - - # Re-Read errors to verify clear - dut.sec_errors_c = (yield from dut.ecc.sec_errors.read()) - dut.ded_errors_c = (yield from dut.ecc.ded_errors.read()) - - dut = self.ecc_encode_decode_test(8*8, 13*8, 4, pre, post, with_error_injection=True) - self.assertEqual(dut.wdata, dut.rdata) - self.assertNotEqual(dut.sec_errors, 0) - self.assertEqual(dut.ded_errors, 0) - self.assertEqual(dut.sec_errors_c, 0) - self.assertEqual(dut.ded_errors_c, 0) - - def test_ecc_clear_ded_errors(self): - # Verify DED errors clear. - def pre(dut): - yield from dut.ecc.flip.write(0b10101100) - - def post(dut): - # Read errors after test (DED errors expected) - dut.sec_errors = (yield from dut.ecc.sec_errors.read()) - dut.ded_errors = (yield from dut.ecc.ded_errors.read()) - - # Clear errors counters - yield from dut.ecc.clear.write(1) - yield - - # Re-Read errors to verify clear - dut.sec_errors_c = (yield from dut.ecc.sec_errors.read()) - dut.ded_errors_c = (yield from dut.ecc.ded_errors.read()) - - dut = self.ecc_encode_decode_test(8*8, 13*8, 4, pre, post, with_error_injection=True) - self.assertNotEqual(dut.wdata, dut.rdata) - self.assertEqual(dut.sec_errors, 0) - self.assertNotEqual(dut.ded_errors, 0) - self.assertEqual(dut.sec_errors_c, 0) - self.assertEqual(dut.ded_errors_c, 0) - - -if __name__ == "__main__": - unittest.main() diff --git a/test/test_examples.py b/test/test_examples.py deleted file mode 100644 index 54cba0f..0000000 --- a/test/test_examples.py +++ /dev/null @@ -1,28 +0,0 @@ -# This file is Copyright (c) 2018-2019 Florent Kermarrec -# License: BSD - -import unittest -import os - - -def build_config(name): - errors = 0 - os.system("rm -rf examples/build") - os.system("cd examples && python3 ../litedram/gen.py {}.yml".format(name)) - errors += not os.path.isfile("examples/build/gateware/litedram_core.v") - os.system("rm -rf examples/build") - return errors - - -class TestExamples(unittest.TestCase): - def test_arty(self): - errors = build_config("arty") - self.assertEqual(errors, 0) - - def test_nexys4ddr(self): - errors = build_config("nexys4ddr") - self.assertEqual(errors, 0) - - def test_genesys2(self): - errors = build_config("genesys2") - self.assertEqual(errors, 0) diff --git a/test/test_fifo.py b/test/test_fifo.py deleted file mode 100644 index 94ef92b..0000000 --- a/test/test_fifo.py +++ /dev/null @@ -1,304 +0,0 @@ -# This file is Copyright (c) 2019 Florent Kermarrec -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest -import random - -from migen import * - -from litex.soc.interconnect.stream import * - -from litedram.common import LiteDRAMNativeWritePort -from litedram.common import LiteDRAMNativeReadPort -from litedram.frontend.fifo import LiteDRAMFIFO, _LiteDRAMFIFOCtrl -from litedram.frontend.fifo import _LiteDRAMFIFOWriter, _LiteDRAMFIFOReader - -from test.common import * - -class TestFIFO(unittest.TestCase): - @passive - def fifo_ctrl_flag_checker(self, fifo_ctrl, write_threshold, read_threshold): - # Checks the combinational logic - while True: - level = (yield fifo_ctrl.level) - self.assertEqual((yield fifo_ctrl.writable), level < write_threshold) - self.assertEqual((yield fifo_ctrl.readable), level > read_threshold) - yield - - # _LiteDRAMFIFOCtrl ---------------------------------------------------------------------------- - - def test_fifo_ctrl_address_changes(self): - # Verify FIFOCtrl address changes. - # We are ignoring thresholds (so readable/writable signals) - dut = _LiteDRAMFIFOCtrl(base=0, depth=16, read_threshold=0, write_threshold=16) - - def main_generator(): - self.assertEqual((yield dut.write_address), 0) - self.assertEqual((yield dut.read_address), 0) - - # Write address - yield dut.write.eq(1) - yield - # Write_address gets updated 1 cycle later - for i in range(24 - 1): - self.assertEqual((yield dut.write_address), i % 16) - yield - yield dut.write.eq(0) - yield - self.assertEqual((yield dut.write_address), 24 % 16) - - # Read address - yield dut.read.eq(1) - yield - for i in range(24 - 1): - self.assertEqual((yield dut.read_address), i % 16) - yield - yield dut.read.eq(0) - yield - self.assertEqual((yield dut.read_address), 24 % 16) - - generators = [ - main_generator(), - self.fifo_ctrl_flag_checker(dut, write_threshold=16, read_threshold=0), - ] - run_simulation(dut, generators) - - def test_fifo_ctrl_level_changes(self): - # Verify FIFOCtrl level changes. - dut = _LiteDRAMFIFOCtrl(base=0, depth=16, read_threshold=0, write_threshold=16) - - def main_generator(): - self.assertEqual((yield dut.level), 0) - - # Level - def check_level_diff(write, read, diff): - level = (yield dut.level) - yield dut.write.eq(write) - yield dut.read.eq(read) - yield - yield dut.write.eq(0) - yield dut.read.eq(0) - yield - self.assertEqual((yield dut.level), level + diff) - - check_level_diff(write=1, read=0, diff=+1) - check_level_diff(write=1, read=0, diff=+1) - check_level_diff(write=1, read=1, diff=+0) - check_level_diff(write=1, read=1, diff=+0) - check_level_diff(write=0, read=1, diff=-1) - check_level_diff(write=0, read=1, diff=-1) - - generators = [ - main_generator(), - self.fifo_ctrl_flag_checker(dut, write_threshold=16, read_threshold=0), - ] - run_simulation(dut, generators) - - # _LiteDRAMFIFOWriter -------------------------------------------------------------------------- - - def fifo_writer_test(self, depth, sequence_len, write_threshold): - class DUT(Module): - def __init__(self): - self.port = LiteDRAMNativeWritePort(address_width=32, data_width=32) - ctrl = _LiteDRAMFIFOCtrl(base=8, depth=depth, - read_threshold = 0, - write_threshold = write_threshold) - self.submodules.ctrl = ctrl - writer = _LiteDRAMFIFOWriter(data_width=32, port=self.port, ctrl=ctrl) - self.submodules.writer = writer - - self.memory = DRAMMemory(32, 128) - assert 8 + sequence_len <= len(self.memory.mem) - - write_data = [seed_to_data(i) for i in range(sequence_len)] - - def generator(dut): - for data in write_data: - yield dut.writer.sink.valid.eq(1) - yield dut.writer.sink.data.eq(data) - yield - while (yield dut.writer.sink.ready) == 0: - yield - yield dut.writer.sink.valid.eq(0) - - for _ in range(16): - yield - - dut = DUT() - generators = [ - generator(dut), - dut.memory.write_handler(dut.port), - self.fifo_ctrl_flag_checker(dut.ctrl, - write_threshold = write_threshold, - read_threshold = 0), - timeout_generator(1500), - ] - run_simulation(dut, generators) - - mem_expected = [0] * len(dut.memory.mem) - for i, data in enumerate(write_data): - mem_expected[8 + i%depth] = data - self.assertEqual(dut.memory.mem, mem_expected) - - def test_fifo_writer_sequence(self): - # Verify simple FIFOWriter sequence. - self.fifo_writer_test(sequence_len=48, depth=64, write_threshold=64) - - def test_fifo_writer_address_wraps(self): - # Verify FIFOWriter sequence with address wraps. - self.fifo_writer_test(sequence_len=48, depth=32, write_threshold=64) - - def test_fifo_writer_stops_after_threshold(self): - # Verify FIFOWriter sequence with stop after threshold is reached. - with self.assertRaises(TimeoutError): - self.fifo_writer_test(sequence_len=48, depth=32, write_threshold=32) - - # _LiteDRAMFIFOReader -------------------------------------------------------------------------- - - def fifo_reader_test(self, depth, sequence_len, read_threshold, inital_writes=0): - memory_data = [seed_to_data(i) for i in range(128)] - read_data = [] - - class DUT(Module): - def __init__(self): - self.port = LiteDRAMNativeReadPort(address_width=32, data_width=32) - ctrl = _LiteDRAMFIFOCtrl(base=8, depth=depth, - read_threshold = read_threshold, - write_threshold = depth) - reader = _LiteDRAMFIFOReader(data_width=32, port=self.port, ctrl=ctrl) - self.submodules.ctrl = ctrl - self.submodules.reader = reader - - self.memory = DRAMMemory(32, len(memory_data), init=memory_data) - assert 8 + sequence_len <= len(self.memory.mem) - - def reader(dut): - # Fake writing to fifo - yield dut.ctrl.write.eq(1) - for _ in range(inital_writes): - yield - yield dut.ctrl.write.eq(0) - yield - - for _ in range(sequence_len): - # Fake single write - yield dut.ctrl.write.eq(1) - yield - yield dut.ctrl.write.eq(0) - - while (yield dut.reader.source.valid) == 0: - yield - read_data.append((yield dut.reader.source.data)) - yield dut.reader.source.ready.eq(1) - yield - yield dut.reader.source.ready.eq(0) - yield - - dut = DUT() - generators = [ - reader(dut), - dut.memory.read_handler(dut.port), - self.fifo_ctrl_flag_checker(dut.ctrl, - write_threshold = depth, - read_threshold = read_threshold), - timeout_generator(1500), - ] - run_simulation(dut, generators) - - read_data_expected = [memory_data[8 + i%depth] for i in range(sequence_len)] - self.assertEqual(read_data, read_data_expected) - - def test_fifo_reader_sequence(self): - # Verify simple FIFOReader sequence. - self.fifo_reader_test(sequence_len=48, depth=64, read_threshold=0) - - def test_fifo_reader_address_wraps(self): - # Verify FIFOReader sequence with address wraps. - self.fifo_reader_test(sequence_len=48, depth=32, read_threshold=0) - - def test_fifo_reader_requires_threshold(self): - # Verify FIFOReader sequence with start after threshold is reached. - with self.assertRaises(TimeoutError): - self.fifo_reader_test(sequence_len=48, depth=32, read_threshold=8) - # Will work after we perform the initial writes - self.fifo_reader_test(sequence_len=48, depth=32, read_threshold=8, inital_writes=8) - - # LiteDRAMFIFO --------------------------------------------------------------------------------- - - def test_fifo_default_thresholds(self): - # Verify FIFO with default threshold. - # Defaults: read_threshold=0, write_threshold=depth - read_threshold, write_threshold = (0, 128) - write_port = LiteDRAMNativeWritePort(address_width=32, data_width=32) - read_port = LiteDRAMNativeReadPort(address_width=32, data_width=32) - fifo = LiteDRAMFIFO(data_width=32, base=0, depth=write_threshold, - write_port = write_port, - read_port = read_port) - - def generator(): - yield write_port.cmd.ready.eq(1) - yield write_port.wdata.ready.eq(1) - for i in range(write_threshold): - yield fifo.sink.valid.eq(1) - yield fifo.sink.data.eq(0) - yield - while (yield fifo.sink.ready) == 0: - yield - yield - - checker = self.fifo_ctrl_flag_checker(fifo.ctrl, write_threshold, read_threshold) - run_simulation(fifo, [generator(), checker]) - - def test_fifo(self): - # Verify FIFO. - class DUT(Module): - def __init__(self): - self.write_port = LiteDRAMNativeWritePort(address_width=32, data_width=32) - self.read_port = LiteDRAMNativeReadPort(address_width=32, data_width=32) - self.submodules.fifo = LiteDRAMFIFO( - data_width = 32, - depth = 32, - base = 16, - write_port = self.write_port, - read_port = self.read_port, - read_threshold = 8, - write_threshold = 32 - 8 - ) - - self.memory = DRAMMemory(32, 128) - - def generator(dut, valid_random=90): - prng = random.Random(42) - # We need 8 more writes to account for read_threshold=8 - for i in range(64 + 8): - while prng.randrange(100) < valid_random: - yield - yield dut.fifo.sink.valid.eq(1) - yield dut.fifo.sink.data.eq(i) - yield - while (yield dut.fifo.sink.ready) != 1: - yield - yield dut.fifo.sink.valid.eq(0) - - def checker(dut, ready_random=90): - prng = random.Random(42) - for i in range(64): - yield dut.fifo.source.ready.eq(0) - yield - while (yield dut.fifo.source.valid) != 1: - yield - while prng.randrange(100) < ready_random: - yield - yield dut.fifo.source.ready.eq(1) - self.assertEqual((yield dut.fifo.source.data), i) - yield - - dut = DUT() - generators = [ - generator(dut), - checker(dut), - dut.memory.write_handler(dut.write_port), - dut.memory.read_handler(dut.read_port) - ] - run_simulation(dut, generators) diff --git a/test/test_init.py b/test/test_init.py deleted file mode 100644 index c956871..0000000 --- a/test/test_init.py +++ /dev/null @@ -1,43 +0,0 @@ -# This file is Copyright (c) 2019 Florent Kermarrec -# License: BSD - -import os -import filecmp -import unittest - -from litex.build.tools import write_to_file - -from litedram.init import get_sdram_phy_c_header, get_sdram_phy_py_header - - -def compare_with_reference(content, filename): - write_to_file(filename, content) - r = filecmp.cmp(filename, os.path.join("test", "reference", filename)) - os.remove(filename) - return r - - -class TestInit(unittest.TestCase): - def test_sdr(self): - from litex.boards.targets.minispartan6 import BaseSoC - soc = BaseSoC() - c_header = get_sdram_phy_c_header(soc.sdram.controller.settings.phy, soc.sdram.controller.settings.timing) - py_header = get_sdram_phy_py_header(soc.sdram.controller.settings.phy, soc.sdram.controller.settings.timing) - self.assertEqual(compare_with_reference(c_header, "sdr_init.h"), True) - self.assertEqual(compare_with_reference(py_header, "sdr_init.py"), True) - - def test_ddr3(self): - from litex.boards.targets.kc705 import BaseSoC - soc = BaseSoC() - c_header = get_sdram_phy_c_header(soc.sdram.controller.settings.phy, soc.sdram.controller.settings.timing) - py_header = get_sdram_phy_py_header(soc.sdram.controller.settings.phy, soc.sdram.controller.settings.timing) - self.assertEqual(compare_with_reference(c_header, "ddr3_init.h"), True) - self.assertEqual(compare_with_reference(py_header, "ddr3_init.py"), True) - - def test_ddr4(self): - from litex.boards.targets.kcu105 import BaseSoC - soc = BaseSoC(max_sdram_size=0x4000000) - c_header = get_sdram_phy_c_header(soc.sdram.controller.settings.phy, soc.sdram.controller.settings.timing) - py_header = get_sdram_phy_py_header(soc.sdram.controller.settings.phy, soc.sdram.controller.settings.timing) - self.assertEqual(compare_with_reference(c_header, "ddr4_init.h"), True) - self.assertEqual(compare_with_reference(py_header, "ddr4_init.py"), True) diff --git a/test/test_modules.py b/test/test_modules.py deleted file mode 100644 index df37734..0000000 --- a/test/test_modules.py +++ /dev/null @@ -1,170 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import os -import csv -import unittest - -import litedram.modules -from litedram.modules import SDRAMModule, DDR3SPDData - - -def load_spd_reference(filename): - """Load reference SPD data from a CSV file - - Micron reference SPD data can be obtained from: - https://www.micron.com/support/tools-and-utilities/serial-presence-detect - """ - script_dir = os.path.dirname(os.path.realpath(__file__)) - path = os.path.join(script_dir, "spd_data", filename) - data = [0] * 256 - with open(path) as f: - reader = csv.DictReader(f) - for row in reader: - address = row["Byte Number"] - value = row["Byte Value"] - # Ignore ranges (data we care about is specified per byte anyway) - if len(address.split("-")) == 1: - data[int(address)] = int(value, 16) - return data - - -class TestSPD(unittest.TestCase): - def test_tck_to_speedgrade(self): - # Verify that speedgrade transfer rates are calculated correctly from tck - tck_to_speedgrade = { - 2.5: 800, - 1.875: 1066, - 1.5: 1333, - 1.25: 1600, - 1.071: 1866, - 0.938: 2133, - } - for tck, speedgrade in tck_to_speedgrade.items(): - self.assertEqual(speedgrade, DDR3SPDData.speedgrade_freq(tck)) - - def compare_geometry(self, module, module_ref): - self.assertEqual(module.nbanks, module_ref.nbanks) - self.assertEqual(module.nrows, module_ref.nrows) - self.assertEqual(module.ncols, module_ref.ncols) - - def compare_technology_timings(self, module, module_ref, omit=None): - timings = {"tREFI", "tWTR", "tCCD", "tRRD", "tZQCS"} - if omit is not None: - timings -= omit - for timing in timings: - txx = getattr(module.technology_timings, timing) - txx_ref = getattr(module_ref.technology_timings, timing) - with self.subTest(txx=timing): - self.assertEqual(txx, txx_ref) - - def compare_speedgrade_timings(self, module, module_ref, omit=None): - timings = {"tRP", "tRCD", "tWR", "tRFC", "tFAW", "tRAS"} - if omit is not None: - timings -= omit - for freq, speedgrade_timings in module.speedgrade_timings.items(): - if freq == "default": - continue - for timing in timings: - txx = getattr(speedgrade_timings, timing) - txx_ref = getattr(module_ref.speedgrade_timings[freq], timing) - with self.subTest(freq=freq, txx=timing): - self.assertEqual(txx, txx_ref) - - def compare_modules(self, module, module_ref, omit=None): - self.assertEqual(module.memtype, module_ref.memtype) - self.assertEqual(module.rate, module_ref.rate) - self.compare_geometry(module, module_ref) - self.compare_technology_timings(module, module_ref, omit=omit) - self.compare_speedgrade_timings(module, module_ref, omit=omit) - - def test_MT16KTF1G64HZ(self): - kwargs = dict(clk_freq=125e6, rate="1:4") - module_ref = litedram.modules.MT16KTF1G64HZ(**kwargs) - - with self.subTest(speedgrade="-1G6"): - data = load_spd_reference("MT16KTF1G64HZ-1G6P1.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - self.compare_modules(module, module_ref) - sgt = module.speedgrade_timings["1600"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 48.125) - - with self.subTest(speedgrade="-1G9"): - data = load_spd_reference("MT16KTF1G64HZ-1G9E1.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - # tRRD it different for this speedgrade - self.compare_modules(module, module_ref, omit={"tRRD"}) - self.assertEqual(module.technology_timings.tRRD, (4, 5)) - sgt = module.speedgrade_timings["1866"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 47.125) - - def test_MT18KSF1G72HZ(self): - kwargs = dict(clk_freq=125e6, rate="1:4") - module_ref = litedram.modules.MT18KSF1G72HZ(**kwargs) - - with self.subTest(speedgrade="-1G6"): - data = load_spd_reference("MT18KSF1G72HZ-1G6E2.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - self.compare_modules(module, module_ref) - sgt = module.speedgrade_timings["1600"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 48.125) - - with self.subTest(speedgrade="-1G4"): - data = load_spd_reference("MT18KSF1G72HZ-1G4E2.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - self.compare_modules(module, module_ref) - sgt = module.speedgrade_timings["1333"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 49.125) - - def test_MT8JTF12864(self): - kwargs = dict(clk_freq=125e6, rate="1:4") - module_ref = litedram.modules.MT8JTF12864(**kwargs) - - data = load_spd_reference("MT8JTF12864AZ-1G4G1.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - self.compare_modules(module, module_ref) - sgt = module.speedgrade_timings["1333"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 49.125) - - def test_MT8KTF51264(self): - kwargs = dict(clk_freq=100e6, rate="1:4") - module_ref = litedram.modules.MT8KTF51264(**kwargs) - - with self.subTest(speedgrade="-1G4"): - data = load_spd_reference("MT8KTF51264HZ-1G4E1.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - self.compare_modules(module, module_ref) - sgt = module.speedgrade_timings["1333"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 49.125) - - with self.subTest(speedgrade="-1G6"): - data = load_spd_reference("MT8KTF51264HZ-1G6E1.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - self.compare_modules(module, module_ref) - sgt = module.speedgrade_timings["1600"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 48.125) - - with self.subTest(speedgrade="-1G9"): - data = load_spd_reference("MT8KTF51264HZ-1G9P1.csv") - module = SDRAMModule.from_spd_data(data, kwargs["clk_freq"]) - # tRRD different for this timing - self.compare_modules(module, module_ref, omit={"tRRD"}) - self.assertEqual(module.technology_timings.tRRD, (4, 5)) - sgt = module.speedgrade_timings["1866"] - self.assertEqual(sgt.tRP, 13.125) - self.assertEqual(sgt.tRCD, 13.125) - self.assertEqual(sgt.tRP + sgt.tRAS, 47.125) diff --git a/test/test_multiplexer.py b/test/test_multiplexer.py deleted file mode 100644 index 41816af..0000000 --- a/test/test_multiplexer.py +++ /dev/null @@ -1,580 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import copy -import random -import unittest -from collections import namedtuple - -from migen import * - -from litex.soc.interconnect import stream - -from litedram.common import * -from litedram.phy import dfi -from litedram.core.multiplexer import Multiplexer - -# load after "* imports" to avoid using Migen version of vcd.py -from litex.gen.sim import run_simulation - -from test.common import timeout_generator, CmdRequestRWDriver - - -def dfi_cmd_to_char(cas_n, ras_n, we_n): - return { - (1, 1, 1): "_", - (0, 1, 0): "w", - (0, 1, 1): "r", - (1, 0, 1): "a", - (1, 0, 0): "p", - (0, 0, 1): "f", - }[(cas_n, ras_n, we_n)] - - -class BankMachineStub: - def __init__(self, babits, abits): - self.cmd = stream.Endpoint(cmd_request_rw_layout(a=abits, ba=babits)) - self.refresh_req = Signal() - self.refresh_gnt = Signal() - - -class RefresherStub: - def __init__(self, babits, abits): - self.cmd = stream.Endpoint(cmd_request_rw_layout(a=abits, ba=babits)) - - -class MultiplexerDUT(Module): - # Define default settings that can be overwritten in specific tests use only these settings - # that we actually need for Multiplexer. - default_controller_settings = dict( - read_time = 32, - write_time = 16, - with_bandwidth = False, - ) - default_phy_settings = dict( - nphases = 2, - rdphase = 0, - wrphase = 1, - rdcmdphase = 1, - wrcmdphase = 0, - read_latency = 5, - cwl = 3, - # Indirectly - nranks = 1, - databits = 16, - dfi_databits = 2*16, - memtype = "DDR2", - ) - default_geom_settings = dict( - bankbits = 3, - rowbits = 13, - colbits = 10, - ) - default_timing_settings = dict( - tWTR = 2, - tFAW = None, - tCCD = 1, - tRRD = None, - ) - - def __init__(self, - controller_settings = None, - phy_settings = None, - geom_settings = None, - timing_settings = None): - # Update settings if provided - def updated(settings, update): - copy = settings.copy() - copy.update(update or {}) - return copy - - controller_settings = updated(self.default_controller_settings, controller_settings) - phy_settings = updated(self.default_phy_settings, phy_settings) - geom_settings = updated(self.default_geom_settings, geom_settings) - timing_settings = updated(self.default_timing_settings, timing_settings) - - # Use simpler settigns to include only Multiplexer-specific members - class SimpleSettings(Settings): - def __init__(self, **kwargs): - self.set_attributes(kwargs) - - settings = SimpleSettings(**controller_settings) - settings.phy = SimpleSettings(**phy_settings) - settings.geom = SimpleSettings(**geom_settings) - settings.timing = SimpleSettings(**timing_settings) - settings.geom.addressbits = max(settings.geom.rowbits, settings.geom.colbits) - self.settings = settings - - # Create interfaces and stubs required to instantiate Multiplexer - abits = settings.geom.addressbits - babits = settings.geom.bankbits - nbanks = 2**babits - nranks = settings.phy.nranks - self.bank_machines = [BankMachineStub(abits=abits, babits=babits) - for _ in range(nbanks*nranks)] - self.refresher = RefresherStub(abits=abits, babits=babits) - self.dfi = dfi.Interface( - addressbits = abits, - bankbits = babits, - nranks = settings.phy.nranks, - databits = settings.phy.dfi_databits, - nphases = settings.phy.nphases) - address_align = log2_int(burst_lengths[settings.phy.memtype]) - self.interface = LiteDRAMInterface(address_align=address_align, settings=settings) - - # Add Multiplexer - self.submodules.multiplexer = Multiplexer(settings, self.bank_machines, self.refresher, - self.dfi, self.interface) - - # Add helpers for driving bank machines/refresher - self.bm_drivers = [CmdRequestRWDriver(bm.cmd, i) for i, bm in enumerate(self.bank_machines)] - self.refresh_driver = CmdRequestRWDriver(self.refresher.cmd, i=1) - - def fsm_state(self): - # Return name of current state of Multiplexer's FSM - return self.multiplexer.fsm.decoding[(yield self.multiplexer.fsm.state)] - - -class TestMultiplexer(unittest.TestCase): - def test_init(self): - # Verify that instantiation of Multiplexer in MultiplexerDUT is correct. This will fail if - # Multiplexer starts using any new setting from controller.settings. - MultiplexerDUT() - - def test_fsm_start_at_read(self): - # FSM should start at READ state (assumed in some other tests). - def main_generator(dut): - self.assertEqual((yield from dut.fsm_state()), "READ") - - dut = MultiplexerDUT() - run_simulation(dut, main_generator(dut)) - - def test_fsm_read_to_write_latency(self): - # Verify the timing of READ to WRITE transition. - def main_generator(dut): - rtw = dut.settings.phy.read_latency - expected = "r" + (rtw - 1) * ">" + "w" - states = "" - - # Set write_available=1 - yield from dut.bm_drivers[0].write() - yield - - for _ in range(len(expected)): - state = (yield from dut.fsm_state()) - # Use ">" for all other states, as FSM.delayed_enter uses anonymous states instead - # of staying in RTW - states += { - "READ": "r", - "WRITE": "w", - }.get(state, ">") - yield - - self.assertEqual(states, expected) - - dut = MultiplexerDUT() - run_simulation(dut, main_generator(dut)) - - def test_fsm_write_to_read_latency(self): - # Verify the timing of WRITE to READ transition. - def main_generator(dut): - write_latency = math.ceil(dut.settings.phy.cwl / dut.settings.phy.nphases) - wtr = dut.settings.timing.tWTR + write_latency + dut.settings.timing.tCCD or 0 - - expected = "w" + (wtr - 1) * ">" + "r" - states = "" - - # Simulate until we are in WRITE - yield from dut.bm_drivers[0].write() - while (yield from dut.fsm_state()) != "WRITE": - yield - - # Set read_available=1 - yield from dut.bm_drivers[0].read() - yield - - for _ in range(len(expected)): - state = (yield from dut.fsm_state()) - states += { - "READ": "r", - "WRITE": "w", - }.get(state, ">") - yield - - self.assertEqual(states, expected) - - dut = MultiplexerDUT() - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_steer_read_correct_phases(self): - # Check that correct phases are being used during READ. - def main_generator(dut): - yield from dut.bm_drivers[2].read() - yield from dut.bm_drivers[3].activate() - - while not (yield dut.bank_machines[2].cmd.ready): - yield - yield - - # fsm starts in READ - for phase in range(dut.settings.phy.nphases): - if phase == dut.settings.phy.rdphase: - self.assertEqual((yield dut.dfi.phases[phase].bank), 2) - elif phase == dut.settings.phy.rdcmdphase: - self.assertEqual((yield dut.dfi.phases[phase].bank), 3) - else: - self.assertEqual((yield dut.dfi.phases[phase].bank), 0) - - dut = MultiplexerDUT() - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_steer_write_correct_phases(self): - # Check that correct phases are being used during WRITE. - def main_generator(dut): - yield from dut.bm_drivers[2].write() - yield from dut.bm_drivers[3].activate() - - while not (yield dut.bank_machines[2].cmd.ready): - yield - yield - - # fsm starts in READ - for phase in range(dut.settings.phy.nphases): - if phase == dut.settings.phy.wrphase: - self.assertEqual((yield dut.dfi.phases[phase].bank), 2) - elif phase == dut.settings.phy.wrcmdphase: - self.assertEqual((yield dut.dfi.phases[phase].bank), 3) - else: - self.assertEqual((yield dut.dfi.phases[phase].bank), 0) - - dut = MultiplexerDUT() - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_single_phase_cmd_req(self): - # Verify that, for a single phase, commands are sent sequentially. - def main_generator(dut): - yield from dut.bm_drivers[2].write() - yield from dut.bm_drivers[3].activate() - ready = {2: dut.bank_machines[2].cmd.ready, 3: dut.bank_machines[3].cmd.ready} - - # Activate should appear first - while not ((yield ready[2]) or (yield ready[3])): - yield - yield from dut.bm_drivers[3].nop() - yield - self.assertEqual((yield dut.dfi.phases[0].bank), 3) - - # Then write - while not (yield ready[2]): - yield - yield from dut.bm_drivers[2].nop() - yield - self.assertEqual((yield dut.dfi.phases[0].bank), 2) - - dut = MultiplexerDUT(phy_settings=dict(nphases=1)) - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_ras_trrd(self): - # Verify tRRD. - def main_generator(dut): - yield from dut.bm_drivers[2].activate() - yield from dut.bm_drivers[3].activate() - ready = {2: dut.bank_machines[2].cmd.ready, 3: dut.bank_machines[3].cmd.ready} - - # Wait for activate - while not ((yield ready[2]) or (yield ready[3])): - yield - # Invalidate command that was ready - if (yield ready[2]): - yield from dut.bm_drivers[2].nop() - else: - yield from dut.bm_drivers[3].nop() - yield - - # Wait for the second activate; start from 1 for the previous cycle - ras_time = 1 - while not ((yield ready[2]) or (yield ready[3])): - ras_time += 1 - yield - - self.assertEqual(ras_time, 6) - - dut = MultiplexerDUT(timing_settings=dict(tRRD=6)) - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_cas_tccd(self): - # Verify tCCD. - def main_generator(dut): - yield from dut.bm_drivers[2].read() - yield from dut.bm_drivers[3].read() - ready = {2: dut.bank_machines[2].cmd.ready, 3: dut.bank_machines[3].cmd.ready} - - # Wait for activate - while not ((yield ready[2]) or (yield ready[3])): - yield - # Invalidate command that was ready - if (yield ready[2]): - yield from dut.bm_drivers[2].nop() - else: - yield from dut.bm_drivers[3].nop() - yield - - # Wait for the second activate; start from 1 for the previous cycle - cas_time = 1 - while not ((yield ready[2]) or (yield ready[3])): - cas_time += 1 - yield - - self.assertEqual(cas_time, 3) - - dut = MultiplexerDUT(timing_settings=dict(tCCD=3)) - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_fsm_anti_starvation(self): - # Check that anti-starvation works according to controller settings. - def main_generator(dut): - yield from dut.bm_drivers[2].read() - yield from dut.bm_drivers[3].write() - - # Go to WRITE - # anti starvation does not work for 1st read, as read_time_en already starts as 1 - # READ -> RTW -> WRITE - while (yield from dut.fsm_state()) != "WRITE": - yield - - # wait for write anti starvation - for _ in range(dut.settings.write_time): - self.assertEqual((yield from dut.fsm_state()), "WRITE") - yield - self.assertEqual((yield from dut.fsm_state()), "WTR") - - # WRITE -> WTR -> READ - while (yield from dut.fsm_state()) != "READ": - yield - - # Wait for read anti starvation - for _ in range(dut.settings.read_time): - self.assertEqual((yield from dut.fsm_state()), "READ") - yield - self.assertEqual((yield from dut.fsm_state()), "RTW") - - dut = MultiplexerDUT() - generators = [ - main_generator(dut), - timeout_generator(100), - ] - run_simulation(dut, generators) - - def test_write_datapath(self): - # Verify that data is transmitted from native interface to DFI. - def main_generator(dut): - yield from dut.bm_drivers[2].write() - # 16bits * 2 (DDR) * 1 (phases) - yield dut.interface.wdata.eq(0xbaadf00d) - yield dut.interface.wdata_we.eq(0xf) - - while not (yield dut.bank_machines[2].cmd.ready): - yield - yield - - self.assertEqual((yield dut.dfi.phases[0].wrdata), 0xbaadf00d) - self.assertEqual((yield dut.dfi.phases[0].wrdata_en), 1) - self.assertEqual((yield dut.dfi.phases[0].address), 2) - self.assertEqual((yield dut.dfi.phases[0].bank), 2) - - dut = MultiplexerDUT(phy_settings=dict(nphases=1)) - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_read_datapath(self): - # Verify that data is transmitted from DFI to native interface. - def main_generator(dut): - yield from dut.bm_drivers[2].write() - # 16bits * 2 (DDR) * 1 (phases) - yield dut.dfi.phases[0].rddata.eq(0xbaadf00d) - yield dut.dfi.phases[0].rddata_en.eq(1) - yield - - while not (yield dut.bank_machines[2].cmd.ready): - yield - yield - - self.assertEqual((yield dut.interface.rdata), 0xbaadf00d) - self.assertEqual((yield dut.interface.wdata_we), 0) - self.assertEqual((yield dut.dfi.phases[0].address), 2) - self.assertEqual((yield dut.dfi.phases[0].bank), 2) - - dut = MultiplexerDUT(phy_settings=dict(nphases=1)) - generators = [ - main_generator(dut), - timeout_generator(50), - ] - run_simulation(dut, generators) - - def test_refresh_requires_gnt(self): - # After refresher command request, multiplexer waits for permission from all bank machines. - def main_generator(dut): - def assert_dfi_cmd(cas, ras, we): - p = dut.dfi.phases[0] - cas_n, ras_n, we_n = (yield p.cas_n), (yield p.ras_n), (yield p.we_n) - self.assertEqual((cas_n, ras_n, we_n), (1 - cas, 1 - ras, 1 - we)) - - for bm in dut.bank_machines: - self.assertEqual((yield bm.refresh_req), 0) - - yield from dut.refresh_driver.refresh() - yield - - # Bank machines get the request - for bm in dut.bank_machines: - self.assertEqual((yield bm.refresh_req), 1) - # No command yet - yield from assert_dfi_cmd(cas=0, ras=0, we=0) - - # Grant permission for refresh - prng = random.Random(42) - delays = [prng.randrange(100) for _ in dut.bank_machines] - for t in range(max(delays) + 1): - # Grant permission - for delay, bm in zip(delays, dut.bank_machines): - if delay == t: - yield bm.refresh_gnt.eq(1) - yield - - # Make sure thare is no command yet - yield from assert_dfi_cmd(cas=0, ras=0, we=0) - yield - yield - - # Refresh command - yield from assert_dfi_cmd(cas=1, ras=1, we=0) - - dut = MultiplexerDUT() - run_simulation(dut, main_generator(dut)) - - def test_requests_from_multiple_bankmachines(self): - # Check complex communication scenario with requests from multiple bank machines - # The communication is greatly simplified - data path is completely ignored, no responses - # from PHY are simulated. Each bank machine performs a sequence of requests, bank machines - # are ordered randomly and the DFI command data is checked to verify if all the commands - # have been sent if correct per-bank order. - - # Tequests sequence on given bank machines - bm_sequences = { - 0: "awwwwwwp", - 1: "arrrrrrp", - 2: "arwrwrwp", - 3: "arrrwwwp", - 4: "awparpawp", - 5: "awwparrrrp", - } - # convert to lists to use .pop() - bm_sequences = {bm_num: list(seq) for bm_num, seq in bm_sequences.items()} - - def main_generator(bank_machines, drivers): - # work on a copy - bm_seq = copy.deepcopy(bm_sequences) - - def non_empty(): - return list(filter(lambda n: len(bm_seq[n]) > 0, bm_seq.keys())) - - # Artificially perform the work of LiteDRAMCrossbar by always picking only one request - prng = random.Random(42) - while len(non_empty()) > 0: - # Pick random bank machine - bm_num = prng.choice(non_empty()) - - # Set given request - request_char = bm_seq[bm_num].pop(0) - yield from drivers[bm_num].request(request_char) - yield - - # Wait for ready - while not (yield bank_machines[bm_num].cmd.ready): - yield - - # Disable it - yield from drivers[bm_num].nop() - - for _ in range(16): - yield - - # Gather data on DFI - DFISnapshot = namedtuple("DFICapture", - ["cmd", "bank", "address", "wrdata_en", "rddata_en"]) - dfi_snapshots = [] - - @passive - def dfi_monitor(dfi): - while True: - # Capture current state of DFI lines - phases = [] - for i, p in enumerate(dfi.phases): - # Transform cas/ras/we to command name - cas_n, ras_n, we_n = (yield p.cas_n), (yield p.ras_n), (yield p.we_n) - captured = {"cmd": dfi_cmd_to_char(cas_n, ras_n, we_n)} - - # Capture rest of fields - for field in DFISnapshot._fields: - if field != "cmd": - captured[field] = (yield getattr(p, field)) - - phases.append(DFISnapshot(**captured)) - dfi_snapshots.append(phases) - yield - - dut = MultiplexerDUT() - generators = [ - main_generator(dut.bank_machines, dut.bm_drivers), - dfi_monitor(dut.dfi), - timeout_generator(200), - ] - run_simulation(dut, generators) - - # Check captured DFI data with the description - for snap in dfi_snapshots: - for i, phase_snap in enumerate(snap): - if phase_snap.cmd == "_": - continue - - # Distinguish bank machines by the bank number - bank = phase_snap.bank - # Find next command for the given bank - cmd = bm_sequences[bank].pop(0) - - # Check if the captured data is correct - self.assertEqual(phase_snap.cmd, cmd) - if cmd in ["w", "r"]: - # Addresses are artificially forced to bank numbers in drivers - self.assertEqual(phase_snap.address, bank) - if cmd == "w": - self.assertEqual(phase_snap.wrdata_en, 1) - if cmd == "r": - self.assertEqual(phase_snap.rddata_en, 1) diff --git a/test/test_refresh.py b/test/test_refresh.py deleted file mode 100644 index 0046ae8..0000000 --- a/test/test_refresh.py +++ /dev/null @@ -1,110 +0,0 @@ -# This file is Copyright (c) 2019 Florent Kermarrec -# License: BSD - -import unittest - -from migen import * - -from litedram.core.multiplexer import cmd_request_rw_layout -from litedram.core.refresher import RefreshSequencer, RefreshTimer, Refresher - - -def c2bool(c): - return {"-": 1, "_": 0}[c] - -class TestRefresh(unittest.TestCase): - def refresh_sequencer_test(self, trp, trfc, starts, dones, cmds): - cmd = Record(cmd_request_rw_layout(a=16, ba=3)) - def generator(dut): - dut.errors = 0 - for start, done, cas, ras in zip(starts, dones, cmds.cas, cmds.ras): - yield dut.start.eq(c2bool(start)) - yield - if (yield dut.done) != c2bool(done): - dut.errors += 1 - if (yield cmd.cas) != c2bool(cas): - dut.errors += 1 - if (yield cmd.ras) != c2bool(ras): - dut.errors += 1 - dut = RefreshSequencer(cmd, trp, trfc) - run_simulation(dut, [generator(dut)]) - self.assertEqual(dut.errors, 0) - - def test_refresh_sequencer(self): - trp = 1 - trfc = 2 - class Obj: pass - cmds = Obj() - starts = "_-______________" - cmds.cas = "___-____________" - cmds.ras = "__--____________" - dones = "_____-__________" - self.refresh_sequencer_test(trp, trfc, starts, dones, cmds) - - def refresh_timer_test(self, trefi): - def generator(dut): - dut.errors = 0 - for i in range(16*trefi): - if i%trefi == (trefi - 1): - if (yield dut.refresh.done) != 1: - dut.errors += 1 - else: - if (yield dut.refresh.done) != 0: - dut.errors += 1 - yield - - class DUT(Module): - def __init__(self, trefi): - self.submodules.refresh = RefreshTimer(trefi) - self.comb += self.refresh.wait.eq(~self.refresh.done) - - dut = DUT(trefi) - run_simulation(dut, [generator(dut)]) - self.assertEqual(dut.errors, 0) - - def test_refresh_timer(self): - for trefi in range(1, 32): - with self.subTest(trefi=trefi): - self.refresh_timer_test(trefi) - - def refresher_test(self, postponing): - class Obj: pass - settings = Obj() - settings.with_refresh = True - settings.refresh_zqcs_freq = 1e0 - settings.timing = Obj() - settings.timing.tREFI = 64 - settings.timing.tRP = 1 - settings.timing.tRFC = 2 - settings.timing.tZQCS = 64 - settings.geom = Obj() - settings.geom.addressbits = 16 - settings.geom.bankbits = 3 - settings.phy = Obj() - settings.phy.nranks = 1 - - def generator(dut): - dut.errors = 0 - yield dut.cmd.ready.eq(1) - for i in range(16): - while (yield dut.cmd.valid) == 0: - yield - cmd_valid_gap = 0 - while (yield dut.cmd.valid) == 1: - cmd_valid_gap += 1 - yield - while (yield dut.cmd.valid) == 0: - cmd_valid_gap += 1 - yield - if cmd_valid_gap != postponing*settings.timing.tREFI: - print(cmd_valid_gap) - dut.errors += 1 - - dut = Refresher(settings, clk_freq=100e6, postponing=postponing) - run_simulation(dut, [generator(dut)]) - self.assertEqual(dut.errors, 0) - - def test_refresher(self): - for postponing in [1, 2, 4, 8]: - with self.subTest(postponing=postponing): - self.refresher_test(postponing) diff --git a/test/test_steerer.py b/test/test_steerer.py deleted file mode 100644 index a37fdf5..0000000 --- a/test/test_steerer.py +++ /dev/null @@ -1,238 +0,0 @@ -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest - -from migen import * -from litex.soc.interconnect import stream - -from litedram.common import * -from litedram.phy import dfi -from litedram.core.multiplexer import _Steerer -from litedram.core.multiplexer import STEER_NOP, STEER_CMD, STEER_REQ, STEER_REFRESH - -from test.common import CmdRequestRWDriver - - -class SteererDUT(Module): - def __init__(self, nranks, dfi_databits, nphases): - a, ba = 13, 3 - nop = Record(cmd_request_layout(a=a, ba=ba)) - choose_cmd = stream.Endpoint(cmd_request_rw_layout(a=a, ba=ba)) - choose_req = stream.Endpoint(cmd_request_rw_layout(a=a, ba=ba)) - refresher_cmd = stream.Endpoint(cmd_request_rw_layout(a=a, ba=ba)) - - self.commands = [nop, choose_cmd, choose_req, refresher_cmd] - self.dfi = dfi.Interface(addressbits=a, bankbits=ba, nranks=nranks, databits=dfi_databits, - nphases=nphases) - self.submodules.steerer = _Steerer(self.commands, self.dfi) - - # NOP is not an endpoint and does not have is_* signals - self.drivers = [CmdRequestRWDriver(req, i, ep_layout=i != 0, rw_layout=i != 0) - for i, req in enumerate(self.commands)] - - -class TestSteerer(unittest.TestCase): - def test_nop_not_valid(self): - # If NOP is selected then there should be no command selected on cas/ras/we. - def main_generator(dut): - # NOP on both phases - yield dut.steerer.sel[0].eq(STEER_NOP) - yield dut.steerer.sel[1].eq(STEER_NOP) - yield from dut.drivers[0].nop() - yield - - for i in range(2): - cas_n = (yield dut.dfi.phases[i].cas_n) - ras_n = (yield dut.dfi.phases[i].ras_n) - we_n = (yield dut.dfi.phases[i].we_n) - self.assertEqual((cas_n, ras_n, we_n), (1, 1, 1)) - - dut = SteererDUT(nranks=2, dfi_databits=16, nphases=2) - run_simulation(dut, main_generator(dut)) - - def test_connect_only_if_valid_and_ready(self): - # Commands should be connected to phases only if they are valid & ready. - def main_generator(dut): - # Set possible requests - yield from dut.drivers[STEER_NOP].nop() - yield from dut.drivers[STEER_CMD].activate() - yield from dut.drivers[STEER_REQ].write() - yield from dut.drivers[STEER_REFRESH].refresh() - # Set how phases are steered - yield dut.steerer.sel[0].eq(STEER_CMD) - yield dut.steerer.sel[1].eq(STEER_NOP) - yield - yield - - def check(is_ready): - # CMD on phase 0 should be STEER_CMD=activate - p = dut.dfi.phases[0] - self.assertEqual((yield p.bank), STEER_CMD) - self.assertEqual((yield p.address), STEER_CMD) - if is_ready: - self.assertEqual((yield p.cas_n), 1) - self.assertEqual((yield p.ras_n), 0) - self.assertEqual((yield p.we_n), 1) - else: # Not steered - self.assertEqual((yield p.cas_n), 1) - self.assertEqual((yield p.ras_n), 1) - self.assertEqual((yield p.we_n), 1) - - # Nop on phase 1 should be STEER_NOP - p = dut.dfi.phases[1] - self.assertEqual((yield p.cas_n), 1) - self.assertEqual((yield p.ras_n), 1) - self.assertEqual((yield p.we_n), 1) - - yield from check(is_ready=False) - yield dut.commands[STEER_CMD].ready.eq(1) - yield - yield - yield from check(is_ready=True) - - dut = SteererDUT(nranks=2, dfi_databits=16, nphases=2) - run_simulation(dut, main_generator(dut)) - - def test_no_decode_ba_signle_rank(self): - # With a single rank the whole `ba` signal is bank address. - def main_generator(dut): - yield from dut.drivers[STEER_NOP].nop() - yield from dut.drivers[STEER_REQ].write() - yield from dut.drivers[STEER_REFRESH].refresh() - # All the bits are for bank - dut.drivers[STEER_CMD].bank = 0b110 - yield from dut.drivers[STEER_CMD].activate() - yield dut.commands[STEER_CMD].ready.eq(1) - # Set how phases are steered - yield dut.steerer.sel[0].eq(STEER_NOP) - yield dut.steerer.sel[1].eq(STEER_CMD) - yield - yield - - p = dut.dfi.phases[1] - self.assertEqual((yield p.cas_n), 1) - self.assertEqual((yield p.ras_n), 0) - self.assertEqual((yield p.we_n), 1) - self.assertEqual((yield p.address), STEER_CMD) - self.assertEqual((yield p.bank), 0b110) - self.assertEqual((yield p.cs_n), 0) - - dut = SteererDUT(nranks=1, dfi_databits=16, nphases=2) - run_simulation(dut, main_generator(dut)) - - def test_decode_ba_multiple_ranks(self): - # With multiple ranks `ba` signal should be split into bank and chip select. - def main_generator(dut): - yield from dut.drivers[STEER_NOP].nop() - yield from dut.drivers[STEER_REQ].write() - yield from dut.drivers[STEER_REFRESH].refresh() - # Set how phases are steered - yield dut.steerer.sel[0].eq(STEER_NOP) - yield dut.steerer.sel[1].eq(STEER_CMD) - - variants = [ - # ba, phase.bank, phase.cs_n - (0b110, 0b10, 0b01), # rank=1 -> cs=0b10 -> cs_n=0b01 - (0b101, 0b01, 0b01), # rank=1 -> cs=0b10 -> cs_n=0b01 - (0b001, 0b01, 0b10), # rank=0 -> cs=0b01 -> cs_n=0b10 - ] - for ba, phase_bank, phase_cs_n in variants: - with self.subTest(ba=ba): - # 1 bit for rank, 2 bits for bank - dut.drivers[STEER_CMD].bank = ba - yield from dut.drivers[STEER_CMD].activate() - yield dut.commands[STEER_CMD].ready.eq(1) - yield - yield - - p = dut.dfi.phases[1] - self.assertEqual((yield p.cas_n), 1) - self.assertEqual((yield p.ras_n), 0) - self.assertEqual((yield p.we_n), 1) - self.assertEqual((yield p.bank), phase_bank) - self.assertEqual((yield p.cs_n), phase_cs_n) - - dut = SteererDUT(nranks=2, dfi_databits=16, nphases=2) - run_simulation(dut, main_generator(dut)) - - def test_select_all_ranks_on_refresh(self): - # When refresh command is on first phase, all ranks should be selected. - def main_generator(dut): - yield from dut.drivers[STEER_NOP].nop() - yield from dut.drivers[STEER_REQ].write() - yield from dut.drivers[STEER_CMD].activate() - # Set how phases are steered - yield dut.steerer.sel[0].eq(STEER_REFRESH) - yield dut.steerer.sel[1].eq(STEER_NOP) - - variants = [ - # ba, phase.bank, phase.cs_n (always all enabled) - (0b110, 0b10, 0b00), - (0b101, 0b01, 0b00), - (0b001, 0b01, 0b00), - ] - for ba, phase_bank, phase_cs_n in variants: - with self.subTest(ba=ba): - # 1 bit for rank, 2 bits for bank - dut.drivers[STEER_REFRESH].bank = ba - yield from dut.drivers[STEER_REFRESH].refresh() - yield dut.commands[STEER_REFRESH].ready.eq(1) - yield - yield - - p = dut.dfi.phases[0] - self.assertEqual((yield p.cas_n), 0) - self.assertEqual((yield p.ras_n), 0) - self.assertEqual((yield p.we_n), 1) - self.assertEqual((yield p.bank), phase_bank) - self.assertEqual((yield p.cs_n), phase_cs_n) - - dut = SteererDUT(nranks=2, dfi_databits=16, nphases=2) - run_simulation(dut, main_generator(dut)) - - def test_reset_n_high(self): - # Reset_n should be 1 for all phases at all times. - def main_generator(dut): - yield dut.steerer.sel[0].eq(STEER_CMD) - yield dut.steerer.sel[1].eq(STEER_NOP) - yield - - self.assertEqual((yield dut.dfi.phases[0].reset_n), 1) - self.assertEqual((yield dut.dfi.phases[1].reset_n), 1) - self.assertEqual((yield dut.dfi.phases[2].reset_n), 1) - self.assertEqual((yield dut.dfi.phases[3].reset_n), 1) - - dut = SteererDUT(nranks=2, dfi_databits=16, nphases=4) - run_simulation(dut, main_generator(dut)) - - def test_cke_high_all_ranks(self): - # CKE should be 1 for all phases and ranks at all times. - def main_generator(dut): - yield dut.steerer.sel[0].eq(STEER_CMD) - yield dut.steerer.sel[1].eq(STEER_NOP) - yield - - self.assertEqual((yield dut.dfi.phases[0].cke), 0b11) - self.assertEqual((yield dut.dfi.phases[1].cke), 0b11) - self.assertEqual((yield dut.dfi.phases[2].cke), 0b11) - self.assertEqual((yield dut.dfi.phases[3].cke), 0b11) - - dut = SteererDUT(nranks=2, dfi_databits=16, nphases=4) - run_simulation(dut, main_generator(dut)) - - def test_odt_high_all_ranks(self): - # ODT should be 1 for all phases and ranks at all times. - # NOTE: only until dynamic ODT is implemented. - def main_generator(dut): - yield dut.steerer.sel[0].eq(STEER_CMD) - yield dut.steerer.sel[1].eq(STEER_NOP) - yield - - self.assertEqual((yield dut.dfi.phases[0].odt), 0b11) - self.assertEqual((yield dut.dfi.phases[1].odt), 0b11) - self.assertEqual((yield dut.dfi.phases[2].odt), 0b11) - self.assertEqual((yield dut.dfi.phases[3].odt), 0b11) - - dut = SteererDUT(nranks=2, dfi_databits=16, nphases=4) - run_simulation(dut, main_generator(dut)) diff --git a/test/test_timing.py b/test/test_timing.py deleted file mode 100644 index 1fbc212..0000000 --- a/test/test_timing.py +++ /dev/null @@ -1,119 +0,0 @@ -# This file is Copyright (c) 2019 Florent Kermarrec -# License: BSD - -import unittest -import random - -from migen import * - -from litedram.common import tXXDController, tFAWController - - -def c2bool(c): - return {"-": 1, "_": 0}[c] - - -class TestTiming(unittest.TestCase): - def txxd_controller_test(self, txxd, valids, readys): - def generator(dut): - dut.errors = 0 - for valid, ready in zip(valids, readys): - yield dut.valid.eq(c2bool(valid)) - yield - if (yield dut.ready) != c2bool(ready): - dut.errors += 1 - - dut = tXXDController(txxd) - run_simulation(dut, [generator(dut)]) - self.assertEqual(dut.errors, 0) - - def test_txxd_controller(self): - txxd = 1 - valids = "__-______" - readys = "_--------" - self.txxd_controller_test(txxd, valids, readys) - - txxd = 2 - valids = "__-______" - readys = "_--_-----" - self.txxd_controller_test(txxd, valids, readys) - - txxd = 3 - valids = "____-______" - readys = "___--__----" - self.txxd_controller_test(txxd, valids, readys) - - txxd = 4 - valids = "____-______" - readys = "___--___---" - self.txxd_controller_test(txxd, valids, readys) - - def txxd_controller_random_test(self, txxd, loops): - def generator(dut, valid_rand): - prng = random.Random(42) - for l in range(loops): - while prng.randrange(100) < valid_rand: - yield - yield dut.valid.eq(1) - yield - yield dut.valid.eq(0) - - @passive - def checker(dut): - dut.ready_gaps = [] - while True: - while (yield dut.ready) != 0: - yield - ready_gap = 1 - while (yield dut.ready) != 1: - ready_gap += 1 - yield - dut.ready_gaps.append(ready_gap) - - dut = tXXDController(txxd) - run_simulation(dut, [generator(dut, valid_rand=90), checker(dut)]) - self.assertEqual(min(dut.ready_gaps), txxd) - - def test_txxd_controller_random(self): - for txxd in range(2, 32): - with self.subTest(txxd=txxd): - self.txxd_controller_random_test(txxd, 512) - - - def tfaw_controller_test(self, txxd, valids, readys): - def generator(dut): - dut.errors = 0 - for valid, ready in zip(valids, readys): - yield dut.valid.eq(c2bool(valid)) - yield - if (yield dut.ready) != c2bool(ready): - dut.errors += 1 - - dut = tFAWController(txxd) - run_simulation(dut, [generator(dut)]) - self.assertEqual(dut.errors, 0) - - def test_tfaw_controller(self): - tfaw = 8 - valids = "_----___________" - readys = "-----______-----" - with self.subTest(tfaw=tfaw, valids=valids, readys=readys): - self.tfaw_controller_test(tfaw, valids, readys) - - tfaw = 8 - valids = "_-_-_-_-________" - readys = "--------___-----" - with self.subTest(tfaw=tfaw, valids=valids, readys=readys): - self.tfaw_controller_test(tfaw, valids, readys) - - tfaw = 8 - valids = "_-_-___-_-______" - readys = "----------_-----" - with self.subTest(tfaw=tfaw, valids=valids, readys=readys): - self.tfaw_controller_test(tfaw, valids, readys) - - tfaw = 8 - valids = "_-_-____-_-______" - readys = "-----------------" - with self.subTest(tfaw=tfaw, valids=valids, readys=readys): - self.tfaw_controller_test(tfaw, valids, readys) diff --git a/test/test_wishbone.py b/test/test_wishbone.py deleted file mode 100644 index 9b2da86..0000000 --- a/test/test_wishbone.py +++ /dev/null @@ -1,111 +0,0 @@ -# This file is Copyright (c) 2018-2019 Florent Kermarrec -# This file is Copyright (c) 2020 Antmicro -# License: BSD - -import unittest - -from migen import * -from litex.gen.sim import run_simulation -from litex.soc.interconnect import wishbone - -from litedram.frontend.wishbone import LiteDRAMWishbone2Native -from litedram.common import LiteDRAMNativePort - -from test.common import DRAMMemory, MemoryTestDataMixin - - -class TestWishbone(MemoryTestDataMixin, unittest.TestCase): - def test_wishbone_data_width_not_smaller(self): - with self.assertRaises(AssertionError): - wb = wishbone.Interface(data_width=32) - port = LiteDRAMNativePort("both", address_width=32, data_width=wb.data_width * 2) - LiteDRAMWishbone2Native(wb, port) - - def wishbone_readback_test(self, pattern, mem_expected, wishbone, port, base_address=0): - class DUT(Module): - def __init__(self): - self.port = port - self.wb = wishbone - self.submodules += LiteDRAMWishbone2Native( - wishbone = self.wb, - port = self.port, - base_address = base_address) - self.mem = DRAMMemory(port.data_width, len(mem_expected)) - - def main_generator(dut): - for adr, data in pattern: - yield from dut.wb.write(adr, data) - data_r = (yield from dut.wb.read(adr)) - self.assertEqual(data_r, data) - - dut = DUT() - generators = [ - main_generator(dut), - dut.mem.write_handler(dut.port), - dut.mem.read_handler(dut.port), - ] - run_simulation(dut, generators) - self.assertEqual(dut.mem.mem, mem_expected) - - def test_wishbone_8bit(self): - # Verify Wishbone with 8-bit data width. - data = self.pattern_test_data["8bit"] - wb = wishbone.Interface(adr_width=30, data_width=8) - port = LiteDRAMNativePort("both", address_width=30, data_width=8) - self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) - - def test_wishbone_32bit(self): - # Verify Wishbone with 32-bit data width. - data = self.pattern_test_data["32bit"] - wb = wishbone.Interface(adr_width=30, data_width=32) - port = LiteDRAMNativePort("both", address_width=30, data_width=32) - self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) - - def test_wishbone_64bit(self): - # Verify Wishbone with 64-bit data width. - data = self.pattern_test_data["64bit"] - wb = wishbone.Interface(adr_width=30, data_width=64) - port = LiteDRAMNativePort("both", address_width=30, data_width=64) - self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) - - def test_wishbone_64bit_to_32bit(self): - # Verify Wishbone with 64-bit data width down-converted to 32-bit data width. - data = self.pattern_test_data["64bit_to_32bit"] - wb = wishbone.Interface(adr_width=30, data_width=64) - port = LiteDRAMNativePort("both", address_width=30, data_width=32) - self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) - - def test_wishbone_32bit_to_8bit(self): - # Verify Wishbone with 32-bit data width down-converted to 8-bit data width. - data = self.pattern_test_data["32bit_to_8bit"] - wb = wishbone.Interface(adr_width=30, data_width=32) - port = LiteDRAMNativePort("both", address_width=30, data_width=8) - self.wishbone_readback_test(data["pattern"], data["expected"], wb, port) - - def test_wishbone_32bit_base_address(self): - # Verify Wishbone with 32-bit data width and non-zero base address. - data = self.pattern_test_data["32bit"] - wb = wishbone.Interface(adr_width=30, data_width=32) - port = LiteDRAMNativePort("both", address_width=30, data_width=32) - origin = 0x10000000 - # add offset (in data words) - pattern = [(adr + origin//(32//8), data) for adr, data in data["pattern"]] - self.wishbone_readback_test(pattern, data["expected"], wb, port, base_address=origin) - - def test_wishbone_64bit_to_32bit_base_address(self): - # Verify Wishbone with 64-bit data width down-converted to 32-bit data width and non-zero base address. - data = self.pattern_test_data["64bit_to_32bit"] - wb = wishbone.Interface(adr_width=30, data_width=64) - port = LiteDRAMNativePort("both", address_width=30, data_width=32) - origin = 0x10000000 - pattern = [(adr + origin//(64//8), data) for adr, data in data["pattern"]] - self.wishbone_readback_test(pattern, data["expected"], wb, port, base_address=origin) - - def test_wishbone_32bit_to_8bit_base_address(self): - # Verify Wishbone with 32-bit data width down-converted to 8-bit data width and non-zero base address. - data = self.pattern_test_data["32bit_to_8bit"] - wb = wishbone.Interface(adr_width=30, data_width=32) - port = LiteDRAMNativePort("both", address_width=30, data_width=8) - origin = 0x10000000 - pattern = [(adr + origin//(32//8), data) for adr, data in data["pattern"]] - self.wishbone_readback_test(pattern, data["expected"], wb, port, base_address=origin) -- 2.30.2