From: Sebastien Bourdeauducq Date: Mon, 15 Jul 2013 15:45:55 +0000 (+0200) Subject: lasmicon: update test benches X-Git-Tag: 24jan2021_ls180~2866 X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=a0f1ee3fbbd69140e66184b77c63dbda5d6f331b;p=litex.git lasmicon: update test benches --- diff --git a/tb/asmicon/asmicon.py b/tb/asmicon/asmicon.py deleted file mode 100644 index 399a18b3..00000000 --- a/tb/asmicon/asmicon.py +++ /dev/null @@ -1,38 +0,0 @@ -from migen.fhdl.std import * -from migen.bus.asmibus import * -from migen.sim.generic import Simulator, TopLevel - -from milkymist.asmicon import * - -from common import sdram_phy, sdram_geom, sdram_timing, DFILogger - -def my_generator_r(): - for x in range(50): - t = TRead(x) - yield t - print("reads done") - -def my_generator_w(): - for x in range(50): - t = TWrite(x, x) - yield t - print("writes done") - -def main(): - dut = ASMIcon(sdram_phy, sdram_geom, sdram_timing) - initiator1 = Initiator(my_generator_r(), dut.hub.get_port()) - initiator2 = Initiator(my_generator_w(), dut.hub.get_port()) - dut.finalize() - - logger = DFILogger(dut.dfi) - - def end_simulation(s): - s.interrupt = initiator1.done and initiator2.done - - fragment = dut.get_fragment() + initiator1.get_fragment() + initiator2.get_fragment() + \ - logger.get_fragment() + \ - Fragment(sim=[end_simulation]) - sim = Simulator(fragment, TopLevel("my.vcd")) - sim.run(700) - -main() diff --git a/tb/asmicon/asmicon_wb.py b/tb/asmicon/asmicon_wb.py deleted file mode 100644 index e5efe0f4..00000000 --- a/tb/asmicon/asmicon_wb.py +++ /dev/null @@ -1,46 +0,0 @@ -from migen.fhdl.std import * -from migen.bus import wishbone, wishbone2asmi, asmibus -from migen.sim.generic import Simulator, TopLevel - -from milkymist.asmicon import * - -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)) - -def main(): - controller = ASMIcon(sdram_phy, sdram_geom, sdram_timing) - bridge = wishbone2asmi.WB2ASMI(l2_size//4, controller.hub.get_port()) - controller.finalize() - initiator = wishbone.Initiator(my_generator()) - conn = wishbone.InterconnectPointToPoint(initiator.bus, bridge.wishbone) - - logger = DFILogger(controller.dfi) - - def end_simulation(s): - s.interrupt = initiator.done - - fragment = controller.get_fragment() + \ - bridge.get_fragment() + \ - initiator.get_fragment() + \ - conn.get_fragment() + \ - logger.get_fragment() + \ - Fragment(sim=[end_simulation]) - sim = Simulator(fragment, TopLevel("my.vcd")) - sim.run() - -main() diff --git a/tb/asmicon/bankmachine.py b/tb/asmicon/bankmachine.py deleted file mode 100644 index fd495d6e..00000000 --- a/tb/asmicon/bankmachine.py +++ /dev/null @@ -1,47 +0,0 @@ -from migen.fhdl.std import * -from migen.bus.asmibus import * -from migen.sim.generic import Simulator, TopLevel - -from milkymist.asmicon.bankmachine import * - -from common import sdram_geom, sdram_timing, CommandLogger - -def my_generator(): - for x in range(10): - t = TWrite(x) - yield t - for x in range(10): - t = TWrite(x + 2200) - yield t - -class Completer: - def __init__(self, hub, cmd): - self.hub = hub - self.cmd = cmd - - def get_fragment(self): - sync = [ - self.hub.call.eq(self.cmd.stb & self.cmd.ack & (self.cmd.is_read | self.cmd.is_write)), - self.hub.tag_call.eq(self.cmd.tag) - ] - return Fragment(sync=sync) - -def main(): - hub = Hub(12, 128, 2) - initiator = Initiator(hub.get_port(), my_generator()) - hub.finalize() - - dut = BankMachine(sdram_geom, sdram_timing, 2, 0, hub.get_slots()) - logger = CommandLogger(dut.cmd, True) - completer = Completer(hub, dut.cmd) - - def end_simulation(s): - s.interrupt = initiator.done - - fragment = hub.get_fragment() + initiator.get_fragment() + \ - dut.get_fragment() + logger.get_fragment() + completer.get_fragment() + \ - Fragment(sim=[end_simulation]) - sim = Simulator(fragment, TopLevel("my.vcd")) - sim.run() - -main() diff --git a/tb/asmicon/common.py b/tb/asmicon/common.py deleted file mode 100644 index b41956c3..00000000 --- a/tb/asmicon/common.py +++ /dev/null @@ -1,130 +0,0 @@ -from fractions import Fraction -from math import ceil - -from migen.fhdl.std import * -from migen.sim.generic import Proxy - -from milkymist import asmicon - -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 = asmicon.PhySettings( - dfi_d=64, - nphases=2, - rdphase=0, - wrphase=1 -) -sdram_geom = asmicon.GeomSettings( - bank_a=2, - row_a=13, - col_a=10 -) -sdram_timing = asmicon.TimingSettings( - tRP=ns(15), - tRCD=ns(15), - tWR=ns(15), - tREFI=ns(7800, False), - tRFC=ns(70), - - CL=3, - rd_delay=4, - - slot_time=16, - 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: - def __init__(self, cmd, rw=False): - self.cmd = cmd - self.rw = rw - - def do_simulation(self, s): - elts = ["@" + str(s.cycle_counter)] - cmdp = Proxy(s, self.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)) - - def get_fragment(self): - if self.rw: - comb = [self.cmd.ack.eq(1)] - else: - comb = [] - return Fragment(comb, sim=[self.do_simulation]) - -class DFILogger: - def __init__(self, dfi): - self.dfi = dfi - - def do_simulation(self, s): - dfip = Proxy(s, self.dfi) - - for i, p in enumerate(dfip.phases): - elts = ["PH=" + str(i) + "\t @" + str(s.cycle_counter)] - elts += decode_sdram(p.ras_n, p.cas_n, p.we_n, p.bank, p.address) - if len(elts) > 1: - print("\t".join(elts)) - - def get_fragment(self): - return Fragment(sim=[self.do_simulation]) - -class SlotsLogger: - def __init__(self, slicer, slots): - self.slicer = slicer - self.slots = slots - - def do_simulation(self, sim): - state_strs = ["EMPTY", "PEND", "PRCESS"] - rw_strs = ["RD", "WR"] - print("\t" + "\t".join([str(x) for x in range(len(self.slots))])) - print("State:\t" + "\t".join([state_strs[sim.rd(s.state)] for s in self.slots])) - print("RW:\t" + "\t".join([rw_strs[sim.rd(s.we)] for s in self.slots])) - print("Row:\t" + "\t".join([str(self.slicer.row(sim.rd(s.adr))) for s in self.slots])) - print("Bank:\t" + "\t".join([str(self.slicer.bank(sim.rd(s.adr))) for s in self.slots])) - print("Col:\t" + "\t".join([str(self.slicer.col(sim.rd(s.adr))) for s in self.slots])) - times = [] - for s in self.slots: - if s.time: - times.append(str(sim.rd(s._counter)) + "/" + str(s.time)) - else: - times.append("N/A") - print("Time:\t" + "\t".join(times)) - - def get_fragment(self): - return Fragment(sim=[self.do_simulation]) diff --git a/tb/asmicon/refresher.py b/tb/asmicon/refresher.py deleted file mode 100644 index 79b9b189..00000000 --- a/tb/asmicon/refresher.py +++ /dev/null @@ -1,49 +0,0 @@ -from random import Random - -from migen.fhdl.std import * -from migen.sim.generic import Simulator, TopLevel - -from milkymist.asmicon.refresher import * - -from common import CommandLogger - -class Granter: - def __init__(self, req, ack): - self.req = req - self.ack = ack - self.state = 0 - self.prng = Random(92837) - - def do_simulation(self, s): - elts = ["@" + str(s.cycle_counter)] - - if self.state == 0: - if s.rd(self.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") - s.wr(self.ack, 1) - self.state = 2 - elif self.state == 2: - if not s.rd(self.req): - elts.append("Refresher released access") - s.wr(self.ack, 0) - self.state = 0 - - if len(elts) > 1: - print("\t".join(elts)) - - def get_fragment(self): - return Fragment(sim=[self.do_simulation]) - -def main(): - dut = Refresher(13, 2, tRP=3, tREFI=100, tRFC=5) - logger = CommandLogger(dut.cmd) - granter = Granter(dut.req, dut.ack) - fragment = dut.get_fragment() + logger.get_fragment() + granter.get_fragment() - sim = Simulator(fragment) - sim.run(400) - -main() diff --git a/tb/asmicon/selector.py b/tb/asmicon/selector.py deleted file mode 100644 index ee987814..00000000 --- a/tb/asmicon/selector.py +++ /dev/null @@ -1,76 +0,0 @@ -from random import Random - -from migen.fhdl.std import * -from migen.bus.asmibus import * -from migen.sim.generic import Simulator, TopLevel - -from milkymist.asmicon.bankmachine import _AddressSlicer, _SimpleSelector - -from common import SlotsLogger, sdram_geom - -def my_generator(dt, offset): - for t in range(dt): - yield None - for x in range(10): - t = TRead(x + offset) - yield t - -class Selector: - def __init__(self, slicer, bankn, slots): - self.selector = _SimpleSelector(slicer, bankn, slots) - self.queue = [] - self.prng = Random(876) - - def do_simulation(self, s): - if self.prng.randrange(0, 5): - s.wr(self.selector.ack, 1) - else: - s.wr(self.selector.ack, 0) - if s.rd(self.selector.stb) and s.rd(self.selector.ack): - tag = s.rd(self.selector.tag) - self.queue.append(tag) - print("==> SELECTED: " + str(tag)) - print("") - - def get_fragment(self): - return self.selector.get_fragment() + \ - Fragment(sim=[self.do_simulation]) - -class Completer: - def __init__(self, hub, queue): - self.hub = hub - self.queue = queue - - def do_simulation(self, s): - if self.queue: - tag = self.queue.pop() - s.wr(self.hub.call, 1) - s.wr(self.hub.tag_call, tag) - else: - s.wr(self.hub.call, 0) - - def get_fragment(self): - return Fragment(sim=[self.do_simulation]) - -def main(): - hub = Hub(12, 128, 8) - initiators = [Initiator(hub.get_port(), my_generator(0, 2200*(i//6)+i*10)) - for i in range(8)] - hub.finalize() - - slots = hub.get_slots() - slicer = _AddressSlicer(sdram_geom, 2) - logger = SlotsLogger(slicer, slots) - selector = Selector(slicer, 0, slots) - completer = Completer(hub, selector.queue) - - def end_simulation(s): - s.interrupt = all([i.done for i in initiators]) - - fragment = hub.get_fragment() + sum([i.get_fragment() for i in initiators], Fragment()) + \ - logger.get_fragment() + selector.get_fragment() + completer.get_fragment() + \ - Fragment(sim=[end_simulation]) - sim = Simulator(fragment, TopLevel("my.vcd")) - sim.run() - -main() diff --git a/tb/lasmicon/bankmachine.py b/tb/lasmicon/bankmachine.py new file mode 100644 index 00000000..3564183a --- /dev/null +++ b/tb/lasmicon/bankmachine.py @@ -0,0 +1,44 @@ +from migen.fhdl.std import * +from migen.bus.lasmibus import * +from migen.sim.generic import Simulator, TopLevel + +from milkymist.lasmicon.bankmachine import * + +from common import 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_timing.read_latency, sdram_timing.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, s): + if s.rd(self.req.dat_ack): + self.dat_ack_cnt += 1 + if s.rd(self.req.req_ack): + try: + we, adr = next(self.generator) + except StopIteration: + s.wr(self.req.stb, 0) + if not s.rd(self.req.lock): + s.interrupt = True + print("data ack count: {0}".format(self.dat_ack_cnt)) + return + s.wr(self.req.adr, adr) + s.wr(self.req.we, we) + s.wr(self.req.stb, 1) + +def main(): + sim = Simulator(TB(), TopLevel("my.vcd")) + sim.run() + +main() diff --git a/tb/lasmicon/common.py b/tb/lasmicon/common.py new file mode 100644 index 00000000..e7e63e17 --- /dev/null +++ b/tb/lasmicon/common.py @@ -0,0 +1,99 @@ +from fractions import Fraction +from math import ceil + +from migen.fhdl.std import * +from migen.sim.generic import Proxy + +from milkymist import lasmicon + +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 = lasmicon.PhySettings( + type="DDR", + dfi_d=64, + nphases=2, + rdphase=0, + wrphase=1, + cl=3 +) +sdram_geom = lasmicon.GeomSettings( + bank_a=2, + row_a=13, + col_a=10 +) +sdram_timing = lasmicon.TimingSettings( + tRP=ns(15), + tRCD=ns(15), + tWR=ns(15), + tWTR=2, + tREFI=ns(7800, False), + tRFC=ns(70), + + read_latency=5, + write_latency=0, + + 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, s): + elts = ["@" + str(s.cycle_counter)] + cmdp = Proxy(s, self.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)) + +class DFILogger(Module): + def __init__(self, dfi): + self.dfi = dfi + + def do_simulation(self, s): + dfip = Proxy(s, self.dfi) + + for i, p in enumerate(dfip.phases): + elts = ["@" + str(s.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)) diff --git a/tb/lasmicon/lasmicon.py b/tb/lasmicon/lasmicon.py new file mode 100644 index 00000000..e64ece39 --- /dev/null +++ b/tb/lasmicon/lasmicon.py @@ -0,0 +1,45 @@ +from migen.fhdl.std import * +from migen.bus.lasmibus import * +from migen.sim.generic import Simulator, TopLevel + +from milkymist.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], 6, self.dut.nrowbits) + self.submodules.logger = DFILogger(self.dut.dfi) + + self.initiators = [Initiator(my_generator(n), master) + for n, master in enumerate(self.xbar.masters)] + self.submodules += self.initiators + + def do_simulation(self, s): + s.interrupt = all(initiator.done for initiator in self.initiators) + + +def main(): + sim = Simulator(TB(), TopLevel("my.vcd")) + sim.run() + +main() diff --git a/tb/lasmicon/lasmicon_wb.py b/tb/lasmicon/lasmicon_wb.py new file mode 100644 index 00000000..4d6e2476 --- /dev/null +++ b/tb/lasmicon/lasmicon_wb.py @@ -0,0 +1,43 @@ +from migen.fhdl.std import * +from migen.bus import wishbone, wishbone2lasmi, lasmibus +from migen.bus.transactions import * +from migen.sim.generic import Simulator, TopLevel + +from milkymist.lasmicon import * + +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) + # FIXME: remove dummy master + self.submodules.xbar = lasmibus.Crossbar([self.ctler.lasmic], 2, self.ctler.nrowbits) + self.submodules.logger = DFILogger(self.ctler.dfi) + self.submodules.bridge = wishbone2lasmi.WB2LASMI(l2_size//4, self.xbar.masters[0]) + self.submodules.initiator = wishbone.Initiator(my_generator()) + self.submodules.conn = wishbone.InterconnectPointToPoint(self.initiator.bus, self.bridge.wishbone) + + def do_simulation(self, s): + s.interrupt = self.initiator.done + +def main(): + sim = Simulator(TB(), TopLevel("my.vcd")) + sim.run() + +main() diff --git a/tb/lasmicon/refresher.py b/tb/lasmicon/refresher.py new file mode 100644 index 00000000..72a527a3 --- /dev/null +++ b/tb/lasmicon/refresher.py @@ -0,0 +1,47 @@ +from random import Random + +from migen.fhdl.std import * +from migen.sim.generic import Simulator, TopLevel + +from milkymist.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, s): + elts = ["@" + str(s.cycle_counter)] + + if self.state == 0: + if s.rd(self.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") + s.wr(self.ack, 1) + self.state = 2 + elif self.state == 2: + if not s.rd(self.req): + elts.append("Refresher released access") + s.wr(self.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) + +def main(): + Simulator(TB()).run(400) + +main()