From: Florent Kermarrec Date: Mon, 2 Mar 2015 07:42:55 +0000 (+0100) Subject: sdram: create test dir and move lasmicon/minicon tests to it X-Git-Tag: 24jan2021_ls180~2540 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=88e7fa21e4f708bd57e80d4268adad7895c2bfec;p=litex.git sdram: create test dir and move lasmicon/minicon tests to it --- diff --git a/misoclib/mem/sdram/lasmicon/test/abstract_transactions_lasmi.py b/misoclib/mem/sdram/lasmicon/test/abstract_transactions_lasmi.py deleted file mode 100644 index 6bfb1fdb..00000000 --- a/misoclib/mem/sdram/lasmicon/test/abstract_transactions_lasmi.py +++ /dev/null @@ -1,39 +0,0 @@ -from migen.fhdl.std import * -from migen.bus.transactions import * -from migen.sim.generic import run_simulation - -from misoclib.mem.sdram.bus import lasmibus - -def my_generator(n): - bank = n % 4 - for x in range(4): - t = TWrite(4*bank+x, 0x1000*bank + 0x100*x) - yield t - print("{0}: Wrote in {1} cycle(s)".format(n, t.latency)) - - for x in range(4): - t = TRead(4*bank+x) - yield t - print("{0}: Read {1:x} in {2} cycle(s)".format(n, t.data, t.latency)) - assert(t.data == 0x1000*bank + 0x100*x) - -class MyModel(lasmibus.TargetModel): - def read(self, bank, address): - r = 0x1000*bank + 0x100*address - #print("read from bank {0} address {1} -> {2:x}".format(bank, address, r)) - return r - - def write(self, bank, address, data, we): - print("write to bank {0} address {1:x} data {2:x}".format(bank, address, data)) - assert(data == 0x1000*bank + 0x100*address) - -class TB(Module): - def __init__(self): - self.submodules.controller = lasmibus.Target(MyModel(), aw=4, dw=32, nbanks=4, req_queue_size=4, - read_latency=4, write_latency=1) - self.submodules.xbar = lasmibus.Crossbar([self.controller.bus], 2) - self.initiators = [lasmibus.Initiator(my_generator(n), self.xbar.get_master()) for n in range(4)] - self.submodules += self.initiators - -if __name__ == "__main__": - run_simulation(TB()) diff --git a/misoclib/mem/sdram/lasmicon/test/bankmachine.py b/misoclib/mem/sdram/lasmicon/test/bankmachine.py deleted file mode 100644 index 12bdcd20..00000000 --- a/misoclib/mem/sdram/lasmicon/test/bankmachine.py +++ /dev/null @@ -1,41 +0,0 @@ -from migen.fhdl.std import * -from migen.sim.generic import run_simulation - -from misoclib.mem.sdram.bus import lasmibus -from misoclib.mem.sdram.lasmicon.bankmachine import * - -from common import sdram_phy, sdram_geom, sdram_timing, CommandLogger - -def my_generator(): - for x in range(10): - yield True, x - for x in range(10): - yield False, 128*x - -class TB(Module): - def __init__(self): - self.req = Interface(32, 32, 1, - sdram_timing.req_queue_size, sdram_phy.read_latency, sdram_phy.write_latency) - self.submodules.dut = BankMachine(sdram_geom, sdram_timing, 2, 0, self.req) - self.submodules.logger = CommandLogger(self.dut.cmd, True) - self.generator = my_generator() - self.dat_ack_cnt = 0 - - def do_simulation(self, selfp): - if selfp.req.dat_ack: - self.dat_ack_cnt += 1 - if selfp.req.req_ack: - try: - we, adr = next(self.generator) - except StopIteration: - selfp.req.stb = 0 - if not selfp.req.lock: - print("data ack count: {0}".format(self.dat_ack_cnt)) - raise StopSimulation - return - selfp.req.adr = adr - selfp.req.we = we - selfp.req.stb = 1 - -if __name__ == "__main__": - run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/lasmicon/test/common.py b/misoclib/mem/sdram/lasmicon/test/common.py deleted file mode 100644 index 3d60d704..00000000 --- a/misoclib/mem/sdram/lasmicon/test/common.py +++ /dev/null @@ -1,101 +0,0 @@ -from fractions import Fraction -from math import ceil - -from migen.fhdl.std import * - -from misoclib import sdram - -MHz = 1000000 -clk_freq = (83 + Fraction(1, 3))*MHz - -clk_period_ns = 1000000000/clk_freq -def ns(t, margin=True): - if margin: - t += clk_period_ns/2 - return ceil(t/clk_period_ns) - -sdram_phy = sdram.PhySettings( - memtype="DDR", - dfi_d=64, - nphases=2, - rdphase=0, - wrphase=1, - rdcmdphase=1, - wrcmdphase=0, - cl=3, - read_latency=5, - write_latency=0 -) - -sdram_geom = sdram.GeomSettings( - bank_a=2, - row_a=13, - col_a=10 -) -sdram_timing = sdram.TimingSettings( - tRP=ns(15), - tRCD=ns(15), - tWR=ns(15), - tWTR=2, - tREFI=ns(7800, False), - tRFC=ns(70), - - req_queue_size=8, - read_time=32, - write_time=16 -) - -def decode_sdram(ras_n, cas_n, we_n, bank, address): - elts = [] - if not ras_n and cas_n and we_n: - elts.append("ACTIVATE") - elts.append("BANK " + str(bank)) - elts.append("ROW " + str(address)) - elif ras_n and not cas_n and we_n: - elts.append("READ\t") - elts.append("BANK " + str(bank)) - elts.append("COL " + str(address)) - elif ras_n and not cas_n and not we_n: - elts.append("WRITE\t") - elts.append("BANK " + str(bank)) - elts.append("COL " + str(address)) - elif ras_n and cas_n and not we_n: - elts.append("BST") - elif not ras_n and not cas_n and we_n: - elts.append("AUTO REFRESH") - elif not ras_n and cas_n and not we_n: - elts.append("PRECHARGE") - if address & 2**10: - elts.append("ALL") - else: - elts.append("BANK " + str(bank)) - elif not ras_n and not cas_n and not we_n: - elts.append("LMR") - return elts - -class CommandLogger(Module): - def __init__(self, cmd, rw=False): - self.cmd = cmd - if rw: - self.comb += self.cmd.ack.eq(1) - - def do_simulation(self, selfp): - elts = ["@" + str(selfp.simulator.cycle_counter)] - cmdp = selfp.cmd - elts += decode_sdram(cmdp.ras_n, cmdp.cas_n, cmdp.we_n, cmdp.ba, cmdp.a) - if len(elts) > 1: - print("\t".join(elts)) - do_simulation.passive = True - -class DFILogger(Module): - def __init__(self, dfi): - self.dfi = dfi - - def do_simulation(self, selfp): - dfip = selfp.dfi - for i, p in enumerate(dfip.phases): - elts = ["@" + str(selfp.simulator.cycle_counter) + ":" + str(i)] - elts += decode_sdram(p.ras_n, p.cas_n, p.we_n, p.bank, p.address) - if len(elts) > 1: - print("\t".join(elts)) - do_simulation.passive = True diff --git a/misoclib/mem/sdram/lasmicon/test/lasmicon.py b/misoclib/mem/sdram/lasmicon/test/lasmicon.py deleted file mode 100644 index af792bbf..00000000 --- a/misoclib/mem/sdram/lasmicon/test/lasmicon.py +++ /dev/null @@ -1,39 +0,0 @@ -from migen.fhdl.std import * -from migen.sim.generic import run_simulation - -from misoclib.mem.sdram.bus import lasmibus -from misoclib.mem.sdram.lasmicon import * - -from common import sdram_phy, sdram_geom, sdram_timing, DFILogger - -def my_generator_r(n): - for x in range(10): - t = TRead(128*n + 48*n*x) - yield t - print("{0:3}: reads done".format(n)) - -def my_generator_w(n): - for x in range(10): - t = TWrite(128*n + 48*n*x, x) - yield t - print("{0:3}: writes done".format(n)) - -def my_generator(n): - if n % 2: - return my_generator_w(n // 2) - else: - return my_generator_r(n // 2) - -class TB(Module): - def __init__(self): - self.submodules.dut = LASMIcon(sdram_phy, sdram_geom, sdram_timing) - self.submodules.xbar = lasmibus.Crossbar([self.dut.lasmic], self.dut.nrowbits) - self.submodules.logger = DFILogger(self.dut.dfi) - - masters = [self.xbar.get_master() for i in range(6)] - self.initiators = [Initiator(my_generator(n), master) - for n, master in enumerate(masters)] - self.submodules += self.initiators - -if __name__ == "__main__": - run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/lasmicon/test/lasmicon_df.py b/misoclib/mem/sdram/lasmicon/test/lasmicon_df.py deleted file mode 100644 index 7f2f886b..00000000 --- a/misoclib/mem/sdram/lasmicon/test/lasmicon_df.py +++ /dev/null @@ -1,39 +0,0 @@ -from migen.fhdl.std import * -from migen.sim.generic import run_simulation - -from misoclib.mem.sdram.bus import lasmibus -from misoclib.mem.sdram.lasmicon import * -from misoclib.mem.sdram.frontend import dma_lasmi - -from common import sdram_phy, sdram_geom, sdram_timing, DFILogger - -class TB(Module): - def __init__(self): - self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) - self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) - self.submodules.logger = DFILogger(self.ctler.dfi) - self.submodules.writer = dma_lasmi.Writer(self.xbar.get_master()) - - self.comb += self.writer.address_data.stb.eq(1) - pl = self.writer.address_data.payload - pl.a.reset = 255 - pl.d.reset = pl.a.reset*2 - self.sync += If(self.writer.address_data.ack, - pl.a.eq(pl.a + 1), - pl.d.eq(pl.d + 2) - ) - self.open_row = None - - def do_simulation(self, selfp): - dfip = selfp.ctler.dfi - for p in dfip.phases: - if p.ras_n and not p.cas_n and not p.we_n: # write - d = dfip.phases[0].wrdata | (dfip.phases[1].wrdata << 64) - print(d) - if d != p.address//2 + p.bank*512 + self.open_row*2048: - print("**** ERROR ****") - elif not p.ras_n and p.cas_n and p.we_n: # activate - self.open_row = p.address - -if __name__ == "__main__": - run_simulation(TB(), ncycles=3500, vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/lasmicon/test/lasmicon_wb.py b/misoclib/mem/sdram/lasmicon/test/lasmicon_wb.py deleted file mode 100644 index 53fc7b87..00000000 --- a/misoclib/mem/sdram/lasmicon/test/lasmicon_wb.py +++ /dev/null @@ -1,38 +0,0 @@ -from migen.fhdl.std import * -from migen.bus import wishbone -from migen.bus.transactions import * -from migen.sim.generic import run_simulation - -from misoclib.mem.sdram.bus import lasmibus -from misoclib.mem.sdram.lasmicon import * -from misoclib.mem.sdram.frontend import wishbone2lasmi - -from common import sdram_phy, sdram_geom, sdram_timing, DFILogger - -l2_size = 8192 # in bytes - -def my_generator(): - for x in range(20): - t = TWrite(x, x) - yield t - print(str(t) + " delay=" + str(t.latency)) - for x in range(20): - t = TRead(x) - yield t - print(str(t) + " delay=" + str(t.latency)) - for x in range(20): - t = TRead(x+l2_size//4) - yield t - print(str(t) + " delay=" + str(t.latency)) - -class TB(Module): - def __init__(self): - self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) - self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) - self.submodules.logger = DFILogger(self.ctler.dfi) - self.submodules.bridge = wishbone2lasmi.WB2LASMI(l2_size//4, self.xbar.get_master()) - self.submodules.initiator = wishbone.Initiator(my_generator()) - self.submodules.conn = wishbone.InterconnectPointToPoint(self.initiator.bus, self.bridge.wishbone) - -if __name__ == "__main__": - run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/lasmicon/test/refresher.py b/misoclib/mem/sdram/lasmicon/test/refresher.py deleted file mode 100644 index 7845bf90..00000000 --- a/misoclib/mem/sdram/lasmicon/test/refresher.py +++ /dev/null @@ -1,45 +0,0 @@ -from random import Random - -from migen.fhdl.std import * -from migen.sim.generic import run_simulation - -from misoclib.mem.sdram.lasmicon.refresher import * - -from common import CommandLogger - -class Granter(Module): - def __init__(self, req, ack): - self.req = req - self.ack = ack - self.state = 0 - self.prng = Random(92837) - - def do_simulation(self, selfp): - elts = ["@" + str(selfp.simulator.cycle_counter)] - - if self.state == 0: - if selfp.req: - elts.append("Refresher requested access") - self.state = 1 - elif self.state == 1: - if self.prng.randrange(0, 5) == 0: - elts.append("Granted access to refresher") - selfp.ack = 1 - self.state = 2 - elif self.state == 2: - if not selfp.req: - elts.append("Refresher released access") - selfp.ack = 0 - self.state = 0 - - if len(elts) > 1: - print("\t".join(elts)) - -class TB(Module): - def __init__(self): - self.submodules.dut = Refresher(13, 2, tRP=3, tREFI=100, tRFC=5) - self.submodules.logger = CommandLogger(self.dut.cmd) - self.submodules.granter = Granter(self.dut.req, self.dut.ack) - -if __name__ == "__main__": - run_simulation(TB(), ncycles=400) diff --git a/misoclib/mem/sdram/minicon/tb/minicontb.py b/misoclib/mem/sdram/minicon/tb/minicontb.py deleted file mode 100644 index d1321393..00000000 --- a/misoclib/mem/sdram/minicon/tb/minicontb.py +++ /dev/null @@ -1,192 +0,0 @@ -from migen.fhdl.std import * -from migen.bus.transactions import TRead, TWrite -from migen.bus import wishbone -from migen.sim.generic import Simulator -from migen.sim import icarus -from mibuild.platforms import papilio_pro as board -from misoclib import sdram -from misoclib.mem.sdram.minicon import Minicon -from misoclib.mem.sdram.phy import gensdrphy -from itertools import chain -from os.path import isfile -import sys - -clk_freq = 80000000 - -from math import ceil - -def ns(t, margin=True): - clk_period_ns = 1000000000/clk_freq - if margin: - t += clk_period_ns/2 - return ceil(t/clk_period_ns) - -class MiniconTB(Module): - def __init__(self, sdrphy, dfi, sdram_geom, sdram_timing, pads, sdram_clk): - - self.clk_freq = 80000000 - phy_settings = sdrphy.phy_settings - rdphase = phy_settings.rdphase - self.submodules.slave = Minicon(phy_settings, sdram_geom, sdram_timing) - - self.submodules.tap = wishbone.Tap(self.slave.bus) - self.submodules.dc = dc = wishbone.DownConverter(32, phy_settings.nphases*flen(dfi.phases[rdphase].rddata)) - self.submodules.master = wishbone.Initiator(self.genxfers(), bus=dc.wishbone_i) - self.submodules.intercon = wishbone.InterconnectPointToPoint(dc.wishbone_o, self.slave.bus) - - self.submodules.sdrphy = self.sdrphy = sdrphy - self.dfi = dfi - self.pads = pads - - self.specials += Instance("mt48lc4m16a2", - io_Dq=pads.dq, - i_Addr=pads.a, - i_Ba=pads.ba, - i_Clk=ClockSignal(), - i_Cke=pads.cke, - i_Cs_n=pads.cs_n, - i_Ras_n=pads.ras_n, - i_Cas_n=pads.cas_n, - i_We_n=pads.we_n, - i_Dqm=pads.dm - ) - - def genxfers(self): - cycle = 0 - for a in chain(range(4),range(256,260),range(1024,1028)): - t = TRead(a) - yield t - print("read {} in {} cycles".format(t.data, t.latency)) - for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): - t = TWrite(a, 0xaa55aa55+cycle) - cycle += 1 - yield t - print("read {} in {} cycles".format(t.data, t.latency)) - for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): - t = TRead(a) - yield t - print("read {} in {} cycles".format(t.data, t.latency)) - - def gen_simulation(self, selfp): - dfi = selfp.dfi - phy = self.sdrphy - rdphase = phy.phy_settings.rdphase - cycle = 0 - - while True: - yield - -class MyTopLevel: - def __init__(self, vcd_name=None, vcd_level=1, - top_name="top", dut_type="dut", dut_name="dut", - cd_name="sys", clk_period=10): - self.vcd_name = vcd_name - self.vcd_level = vcd_level - self.top_name = top_name - self.dut_type = dut_type - self.dut_name = dut_name - - self._cd_name = cd_name - self._clk_period = clk_period - - cd = ClockDomain(self._cd_name) - cd_ps = ClockDomain("sys_ps") - self.clock_domains = [cd, cd_ps] - self.ios = {cd.clk, cd.rst, cd_ps.clk} - - def get(self, sockaddr): - template1 = """`timescale 1ns / 1ps - -module {top_name}(); - -reg {clk_name}; -reg {rst_name}; -reg sys_ps_clk; - -initial begin - {rst_name} <= 1'b1; - @(posedge {clk_name}); - {rst_name} <= 1'b0; -end - -always begin - {clk_name} <= 1'b0; - #{hclk_period}; - {clk_name} <= 1'b1; - #{hclk_period}; -end - -always @(posedge {clk_name} or negedge {clk_name}) - sys_ps_clk <= #({hclk_period}*2-3) {clk_name}; - -{dut_type} {dut_name}( - .{rst_name}({rst_name}), - .{clk_name}({clk_name}), - .sys_ps_clk(sys_ps_clk) -); - -initial $migensim_connect("{sockaddr}"); -always @(posedge {clk_name}) $migensim_tick; -""" - template2 = """ -initial begin - $dumpfile("{vcd_name}"); - $dumpvars({vcd_level}, {dut_name}); -end -""" - r = template1.format(top_name=self.top_name, - dut_type=self.dut_type, - dut_name=self.dut_name, - clk_name=self._cd_name + "_clk", - rst_name=self._cd_name + "_rst", - hclk_period=str(self._clk_period/2), - sockaddr=sockaddr) - if self.vcd_name is not None: - r += template2.format(vcd_name=self.vcd_name, - vcd_level=str(self.vcd_level), - dut_name=self.dut_name) - r += "\nendmodule" - return r - - -if __name__ == "__main__": - - plat = board.Platform() - - sdram_geom = sdram.GeomSettings( - bank_a=2, - row_a=12, - col_a=8 - ) - - sdram_timing = sdram.TimingSettings( - tRP=ns(15), - tRCD=ns(15), - tWR=ns(14), - tWTR=2, - tREFI=ns(64*1000*1000/4096, False), - tRFC=ns(66), - req_queue_size=8, - read_time=32, - write_time=16 - ) - - sdram_pads = plat.request("sdram") - sdram_clk = plat.request("sdram_clock") - - sdrphy = gensdrphy.GENSDRPHY(sdram_pads) - -# This sets CL to 2 during LMR done on 1st cycle - sdram_pads.a.reset = 1<<5 - - s = MiniconTB(sdrphy, sdrphy.dfi, sdram_geom, sdram_timing, pads=sdram_pads, sdram_clk=sdram_clk) - - extra_files = [ "sdram_model/mt48lc4m16a2.v" ] - - if not isfile(extra_files[0]): - print("ERROR: You need to download Micron Verilog simulation model for MT48LC4M16A2 and put it in sdram_model/mt48lc4m16a2.v") - print("File can be downloaded from this URL: http://www.micron.com/-/media/documents/products/sim%20model/dram/dram/4054mt48lc4m16a2.zip") - sys.exit(1) - - with Simulator(s, MyTopLevel("top.vcd", clk_period=int(1/0.08)), icarus.Runner(extra_files=extra_files, keep_files=True)) as sim: - sim.run(5000) diff --git a/misoclib/mem/sdram/test/abstract_transactions_lasmi.py b/misoclib/mem/sdram/test/abstract_transactions_lasmi.py new file mode 100644 index 00000000..6bfb1fdb --- /dev/null +++ b/misoclib/mem/sdram/test/abstract_transactions_lasmi.py @@ -0,0 +1,39 @@ +from migen.fhdl.std import * +from migen.bus.transactions import * +from migen.sim.generic import run_simulation + +from misoclib.mem.sdram.bus import lasmibus + +def my_generator(n): + bank = n % 4 + for x in range(4): + t = TWrite(4*bank+x, 0x1000*bank + 0x100*x) + yield t + print("{0}: Wrote in {1} cycle(s)".format(n, t.latency)) + + for x in range(4): + t = TRead(4*bank+x) + yield t + print("{0}: Read {1:x} in {2} cycle(s)".format(n, t.data, t.latency)) + assert(t.data == 0x1000*bank + 0x100*x) + +class MyModel(lasmibus.TargetModel): + def read(self, bank, address): + r = 0x1000*bank + 0x100*address + #print("read from bank {0} address {1} -> {2:x}".format(bank, address, r)) + return r + + def write(self, bank, address, data, we): + print("write to bank {0} address {1:x} data {2:x}".format(bank, address, data)) + assert(data == 0x1000*bank + 0x100*address) + +class TB(Module): + def __init__(self): + self.submodules.controller = lasmibus.Target(MyModel(), aw=4, dw=32, nbanks=4, req_queue_size=4, + read_latency=4, write_latency=1) + self.submodules.xbar = lasmibus.Crossbar([self.controller.bus], 2) + self.initiators = [lasmibus.Initiator(my_generator(n), self.xbar.get_master()) for n in range(4)] + self.submodules += self.initiators + +if __name__ == "__main__": + run_simulation(TB()) diff --git a/misoclib/mem/sdram/test/bankmachine_tb.py b/misoclib/mem/sdram/test/bankmachine_tb.py new file mode 100644 index 00000000..12bdcd20 --- /dev/null +++ b/misoclib/mem/sdram/test/bankmachine_tb.py @@ -0,0 +1,41 @@ +from migen.fhdl.std import * +from migen.sim.generic import run_simulation + +from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.lasmicon.bankmachine import * + +from common import sdram_phy, sdram_geom, sdram_timing, CommandLogger + +def my_generator(): + for x in range(10): + yield True, x + for x in range(10): + yield False, 128*x + +class TB(Module): + def __init__(self): + self.req = Interface(32, 32, 1, + sdram_timing.req_queue_size, sdram_phy.read_latency, sdram_phy.write_latency) + self.submodules.dut = BankMachine(sdram_geom, sdram_timing, 2, 0, self.req) + self.submodules.logger = CommandLogger(self.dut.cmd, True) + self.generator = my_generator() + self.dat_ack_cnt = 0 + + def do_simulation(self, selfp): + if selfp.req.dat_ack: + self.dat_ack_cnt += 1 + if selfp.req.req_ack: + try: + we, adr = next(self.generator) + except StopIteration: + selfp.req.stb = 0 + if not selfp.req.lock: + print("data ack count: {0}".format(self.dat_ack_cnt)) + raise StopSimulation + return + selfp.req.adr = adr + selfp.req.we = we + selfp.req.stb = 1 + +if __name__ == "__main__": + run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/common.py b/misoclib/mem/sdram/test/common.py new file mode 100644 index 00000000..3d60d704 --- /dev/null +++ b/misoclib/mem/sdram/test/common.py @@ -0,0 +1,101 @@ +from fractions import Fraction +from math import ceil + +from migen.fhdl.std import * + +from misoclib import sdram + +MHz = 1000000 +clk_freq = (83 + Fraction(1, 3))*MHz + +clk_period_ns = 1000000000/clk_freq +def ns(t, margin=True): + if margin: + t += clk_period_ns/2 + return ceil(t/clk_period_ns) + +sdram_phy = sdram.PhySettings( + memtype="DDR", + dfi_d=64, + nphases=2, + rdphase=0, + wrphase=1, + rdcmdphase=1, + wrcmdphase=0, + cl=3, + read_latency=5, + write_latency=0 +) + +sdram_geom = sdram.GeomSettings( + bank_a=2, + row_a=13, + col_a=10 +) +sdram_timing = sdram.TimingSettings( + tRP=ns(15), + tRCD=ns(15), + tWR=ns(15), + tWTR=2, + tREFI=ns(7800, False), + tRFC=ns(70), + + req_queue_size=8, + read_time=32, + write_time=16 +) + +def decode_sdram(ras_n, cas_n, we_n, bank, address): + elts = [] + if not ras_n and cas_n and we_n: + elts.append("ACTIVATE") + elts.append("BANK " + str(bank)) + elts.append("ROW " + str(address)) + elif ras_n and not cas_n and we_n: + elts.append("READ\t") + elts.append("BANK " + str(bank)) + elts.append("COL " + str(address)) + elif ras_n and not cas_n and not we_n: + elts.append("WRITE\t") + elts.append("BANK " + str(bank)) + elts.append("COL " + str(address)) + elif ras_n and cas_n and not we_n: + elts.append("BST") + elif not ras_n and not cas_n and we_n: + elts.append("AUTO REFRESH") + elif not ras_n and cas_n and not we_n: + elts.append("PRECHARGE") + if address & 2**10: + elts.append("ALL") + else: + elts.append("BANK " + str(bank)) + elif not ras_n and not cas_n and not we_n: + elts.append("LMR") + return elts + +class CommandLogger(Module): + def __init__(self, cmd, rw=False): + self.cmd = cmd + if rw: + self.comb += self.cmd.ack.eq(1) + + def do_simulation(self, selfp): + elts = ["@" + str(selfp.simulator.cycle_counter)] + cmdp = selfp.cmd + elts += decode_sdram(cmdp.ras_n, cmdp.cas_n, cmdp.we_n, cmdp.ba, cmdp.a) + if len(elts) > 1: + print("\t".join(elts)) + do_simulation.passive = True + +class DFILogger(Module): + def __init__(self, dfi): + self.dfi = dfi + + def do_simulation(self, selfp): + dfip = selfp.dfi + for i, p in enumerate(dfip.phases): + elts = ["@" + str(selfp.simulator.cycle_counter) + ":" + str(i)] + elts += decode_sdram(p.ras_n, p.cas_n, p.we_n, p.bank, p.address) + if len(elts) > 1: + print("\t".join(elts)) + do_simulation.passive = True diff --git a/misoclib/mem/sdram/test/lasmicon_df_tb.py b/misoclib/mem/sdram/test/lasmicon_df_tb.py new file mode 100644 index 00000000..7f2f886b --- /dev/null +++ b/misoclib/mem/sdram/test/lasmicon_df_tb.py @@ -0,0 +1,39 @@ +from migen.fhdl.std import * +from migen.sim.generic import run_simulation + +from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.lasmicon import * +from misoclib.mem.sdram.frontend import dma_lasmi + +from common import sdram_phy, sdram_geom, sdram_timing, DFILogger + +class TB(Module): + def __init__(self): + self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) + self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) + self.submodules.logger = DFILogger(self.ctler.dfi) + self.submodules.writer = dma_lasmi.Writer(self.xbar.get_master()) + + self.comb += self.writer.address_data.stb.eq(1) + pl = self.writer.address_data.payload + pl.a.reset = 255 + pl.d.reset = pl.a.reset*2 + self.sync += If(self.writer.address_data.ack, + pl.a.eq(pl.a + 1), + pl.d.eq(pl.d + 2) + ) + self.open_row = None + + def do_simulation(self, selfp): + dfip = selfp.ctler.dfi + for p in dfip.phases: + if p.ras_n and not p.cas_n and not p.we_n: # write + d = dfip.phases[0].wrdata | (dfip.phases[1].wrdata << 64) + print(d) + if d != p.address//2 + p.bank*512 + self.open_row*2048: + print("**** ERROR ****") + elif not p.ras_n and p.cas_n and p.we_n: # activate + self.open_row = p.address + +if __name__ == "__main__": + run_simulation(TB(), ncycles=3500, vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/lasmicon_tb.py b/misoclib/mem/sdram/test/lasmicon_tb.py new file mode 100644 index 00000000..af792bbf --- /dev/null +++ b/misoclib/mem/sdram/test/lasmicon_tb.py @@ -0,0 +1,39 @@ +from migen.fhdl.std import * +from migen.sim.generic import run_simulation + +from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.lasmicon import * + +from common import sdram_phy, sdram_geom, sdram_timing, DFILogger + +def my_generator_r(n): + for x in range(10): + t = TRead(128*n + 48*n*x) + yield t + print("{0:3}: reads done".format(n)) + +def my_generator_w(n): + for x in range(10): + t = TWrite(128*n + 48*n*x, x) + yield t + print("{0:3}: writes done".format(n)) + +def my_generator(n): + if n % 2: + return my_generator_w(n // 2) + else: + return my_generator_r(n // 2) + +class TB(Module): + def __init__(self): + self.submodules.dut = LASMIcon(sdram_phy, sdram_geom, sdram_timing) + self.submodules.xbar = lasmibus.Crossbar([self.dut.lasmic], self.dut.nrowbits) + self.submodules.logger = DFILogger(self.dut.dfi) + + masters = [self.xbar.get_master() for i in range(6)] + self.initiators = [Initiator(my_generator(n), master) + for n, master in enumerate(masters)] + self.submodules += self.initiators + +if __name__ == "__main__": + run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/lasmicon_wb.py b/misoclib/mem/sdram/test/lasmicon_wb.py new file mode 100644 index 00000000..53fc7b87 --- /dev/null +++ b/misoclib/mem/sdram/test/lasmicon_wb.py @@ -0,0 +1,38 @@ +from migen.fhdl.std import * +from migen.bus import wishbone +from migen.bus.transactions import * +from migen.sim.generic import run_simulation + +from misoclib.mem.sdram.bus import lasmibus +from misoclib.mem.sdram.lasmicon import * +from misoclib.mem.sdram.frontend import wishbone2lasmi + +from common import sdram_phy, sdram_geom, sdram_timing, DFILogger + +l2_size = 8192 # in bytes + +def my_generator(): + for x in range(20): + t = TWrite(x, x) + yield t + print(str(t) + " delay=" + str(t.latency)) + for x in range(20): + t = TRead(x) + yield t + print(str(t) + " delay=" + str(t.latency)) + for x in range(20): + t = TRead(x+l2_size//4) + yield t + print(str(t) + " delay=" + str(t.latency)) + +class TB(Module): + def __init__(self): + self.submodules.ctler = LASMIcon(sdram_phy, sdram_geom, sdram_timing) + self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], self.ctler.nrowbits) + self.submodules.logger = DFILogger(self.ctler.dfi) + self.submodules.bridge = wishbone2lasmi.WB2LASMI(l2_size//4, self.xbar.get_master()) + self.submodules.initiator = wishbone.Initiator(my_generator()) + self.submodules.conn = wishbone.InterconnectPointToPoint(self.initiator.bus, self.bridge.wishbone) + +if __name__ == "__main__": + run_simulation(TB(), vcd_name="my.vcd") diff --git a/misoclib/mem/sdram/test/minicon_tb.py b/misoclib/mem/sdram/test/minicon_tb.py new file mode 100644 index 00000000..d1321393 --- /dev/null +++ b/misoclib/mem/sdram/test/minicon_tb.py @@ -0,0 +1,192 @@ +from migen.fhdl.std import * +from migen.bus.transactions import TRead, TWrite +from migen.bus import wishbone +from migen.sim.generic import Simulator +from migen.sim import icarus +from mibuild.platforms import papilio_pro as board +from misoclib import sdram +from misoclib.mem.sdram.minicon import Minicon +from misoclib.mem.sdram.phy import gensdrphy +from itertools import chain +from os.path import isfile +import sys + +clk_freq = 80000000 + +from math import ceil + +def ns(t, margin=True): + clk_period_ns = 1000000000/clk_freq + if margin: + t += clk_period_ns/2 + return ceil(t/clk_period_ns) + +class MiniconTB(Module): + def __init__(self, sdrphy, dfi, sdram_geom, sdram_timing, pads, sdram_clk): + + self.clk_freq = 80000000 + phy_settings = sdrphy.phy_settings + rdphase = phy_settings.rdphase + self.submodules.slave = Minicon(phy_settings, sdram_geom, sdram_timing) + + self.submodules.tap = wishbone.Tap(self.slave.bus) + self.submodules.dc = dc = wishbone.DownConverter(32, phy_settings.nphases*flen(dfi.phases[rdphase].rddata)) + self.submodules.master = wishbone.Initiator(self.genxfers(), bus=dc.wishbone_i) + self.submodules.intercon = wishbone.InterconnectPointToPoint(dc.wishbone_o, self.slave.bus) + + self.submodules.sdrphy = self.sdrphy = sdrphy + self.dfi = dfi + self.pads = pads + + self.specials += Instance("mt48lc4m16a2", + io_Dq=pads.dq, + i_Addr=pads.a, + i_Ba=pads.ba, + i_Clk=ClockSignal(), + i_Cke=pads.cke, + i_Cs_n=pads.cs_n, + i_Ras_n=pads.ras_n, + i_Cas_n=pads.cas_n, + i_We_n=pads.we_n, + i_Dqm=pads.dm + ) + + def genxfers(self): + cycle = 0 + for a in chain(range(4),range(256,260),range(1024,1028)): + t = TRead(a) + yield t + print("read {} in {} cycles".format(t.data, t.latency)) + for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): + t = TWrite(a, 0xaa55aa55+cycle) + cycle += 1 + yield t + print("read {} in {} cycles".format(t.data, t.latency)) + for a in chain(range(4),range(256,260),range(1024,1028),range(4096,4100)): + t = TRead(a) + yield t + print("read {} in {} cycles".format(t.data, t.latency)) + + def gen_simulation(self, selfp): + dfi = selfp.dfi + phy = self.sdrphy + rdphase = phy.phy_settings.rdphase + cycle = 0 + + while True: + yield + +class MyTopLevel: + def __init__(self, vcd_name=None, vcd_level=1, + top_name="top", dut_type="dut", dut_name="dut", + cd_name="sys", clk_period=10): + self.vcd_name = vcd_name + self.vcd_level = vcd_level + self.top_name = top_name + self.dut_type = dut_type + self.dut_name = dut_name + + self._cd_name = cd_name + self._clk_period = clk_period + + cd = ClockDomain(self._cd_name) + cd_ps = ClockDomain("sys_ps") + self.clock_domains = [cd, cd_ps] + self.ios = {cd.clk, cd.rst, cd_ps.clk} + + def get(self, sockaddr): + template1 = """`timescale 1ns / 1ps + +module {top_name}(); + +reg {clk_name}; +reg {rst_name}; +reg sys_ps_clk; + +initial begin + {rst_name} <= 1'b1; + @(posedge {clk_name}); + {rst_name} <= 1'b0; +end + +always begin + {clk_name} <= 1'b0; + #{hclk_period}; + {clk_name} <= 1'b1; + #{hclk_period}; +end + +always @(posedge {clk_name} or negedge {clk_name}) + sys_ps_clk <= #({hclk_period}*2-3) {clk_name}; + +{dut_type} {dut_name}( + .{rst_name}({rst_name}), + .{clk_name}({clk_name}), + .sys_ps_clk(sys_ps_clk) +); + +initial $migensim_connect("{sockaddr}"); +always @(posedge {clk_name}) $migensim_tick; +""" + template2 = """ +initial begin + $dumpfile("{vcd_name}"); + $dumpvars({vcd_level}, {dut_name}); +end +""" + r = template1.format(top_name=self.top_name, + dut_type=self.dut_type, + dut_name=self.dut_name, + clk_name=self._cd_name + "_clk", + rst_name=self._cd_name + "_rst", + hclk_period=str(self._clk_period/2), + sockaddr=sockaddr) + if self.vcd_name is not None: + r += template2.format(vcd_name=self.vcd_name, + vcd_level=str(self.vcd_level), + dut_name=self.dut_name) + r += "\nendmodule" + return r + + +if __name__ == "__main__": + + plat = board.Platform() + + sdram_geom = sdram.GeomSettings( + bank_a=2, + row_a=12, + col_a=8 + ) + + sdram_timing = sdram.TimingSettings( + tRP=ns(15), + tRCD=ns(15), + tWR=ns(14), + tWTR=2, + tREFI=ns(64*1000*1000/4096, False), + tRFC=ns(66), + req_queue_size=8, + read_time=32, + write_time=16 + ) + + sdram_pads = plat.request("sdram") + sdram_clk = plat.request("sdram_clock") + + sdrphy = gensdrphy.GENSDRPHY(sdram_pads) + +# This sets CL to 2 during LMR done on 1st cycle + sdram_pads.a.reset = 1<<5 + + s = MiniconTB(sdrphy, sdrphy.dfi, sdram_geom, sdram_timing, pads=sdram_pads, sdram_clk=sdram_clk) + + extra_files = [ "sdram_model/mt48lc4m16a2.v" ] + + if not isfile(extra_files[0]): + print("ERROR: You need to download Micron Verilog simulation model for MT48LC4M16A2 and put it in sdram_model/mt48lc4m16a2.v") + print("File can be downloaded from this URL: http://www.micron.com/-/media/documents/products/sim%20model/dram/dram/4054mt48lc4m16a2.zip") + sys.exit(1) + + with Simulator(s, MyTopLevel("top.vcd", clk_period=int(1/0.08)), icarus.Runner(extra_files=extra_files, keep_files=True)) as sim: + sim.run(5000) diff --git a/misoclib/mem/sdram/test/refresher.py b/misoclib/mem/sdram/test/refresher.py new file mode 100644 index 00000000..7845bf90 --- /dev/null +++ b/misoclib/mem/sdram/test/refresher.py @@ -0,0 +1,45 @@ +from random import Random + +from migen.fhdl.std import * +from migen.sim.generic import run_simulation + +from misoclib.mem.sdram.lasmicon.refresher import * + +from common import CommandLogger + +class Granter(Module): + def __init__(self, req, ack): + self.req = req + self.ack = ack + self.state = 0 + self.prng = Random(92837) + + def do_simulation(self, selfp): + elts = ["@" + str(selfp.simulator.cycle_counter)] + + if self.state == 0: + if selfp.req: + elts.append("Refresher requested access") + self.state = 1 + elif self.state == 1: + if self.prng.randrange(0, 5) == 0: + elts.append("Granted access to refresher") + selfp.ack = 1 + self.state = 2 + elif self.state == 2: + if not selfp.req: + elts.append("Refresher released access") + selfp.ack = 0 + self.state = 0 + + if len(elts) > 1: + print("\t".join(elts)) + +class TB(Module): + def __init__(self): + self.submodules.dut = Refresher(13, 2, tRP=3, tREFI=100, tRFC=5) + self.submodules.logger = CommandLogger(self.dut.cmd) + self.submodules.granter = Granter(self.dut.req, self.dut.ack) + +if __name__ == "__main__": + run_simulation(TB(), ncycles=400)