New simulation API

This commit is contained in:
Sebastien Bourdeauducq 2014-01-26 22:19:43 +01:00
parent 8f69d9b669
commit 63c1d7e4b7
29 changed files with 406 additions and 463 deletions

View file

@ -2,7 +2,7 @@ from random import Random
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.genlib.cdc import GrayCounter from migen.genlib.cdc import GrayCounter
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
class TB(Module): class TB(Module):
def __init__(self, width=3): def __init__(self, width=3):
@ -10,10 +10,10 @@ class TB(Module):
self.submodules.gc = GrayCounter(self.width) self.submodules.gc = GrayCounter(self.width)
self.prng = Random(7345) self.prng = Random(7345)
def do_simulation(self, s): def do_simulation(self, selfp):
print("{0:0{1}b} CE={2} bin={3}".format(s.rd(self.gc.q), print("{0:0{1}b} CE={2} bin={3}".format(selfp.gc.q,
self.width, s.rd(self.gc.ce), s.rd(self.gc.q_binary))) self.width, selfp.gc.ce, selfp.gc.q_binary))
s.wr(self.gc.ce, self.prng.getrandbits(1)) selfp.gc.ce = self.prng.getrandbits(1)
sim = Simulator(TB()) if __name__ == "__main__":
sim.run(35) run_simulation(TB(), ncycles=35)

View file

@ -3,10 +3,10 @@ from random import Random
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.flow.network import * from migen.flow.network import *
from migen.flow.transactions import * from migen.flow.transactions import *
from migen.actorlib import dma_wishbone, dma_asmi from migen.actorlib import dma_wishbone
from migen.actorlib.sim import * from migen.actorlib.sim import *
from migen.bus import wishbone, asmibus from migen.bus import wishbone
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
class MyModel: class MyModel:
def read(self, address): def read(self, address):
@ -19,9 +19,6 @@ class MyModelWB(MyModel, wishbone.TargetModel):
def can_ack(self, bus): def can_ack(self, bus):
return self.prng.randrange(0, 2) return self.prng.randrange(0, 2)
class MyModelASMI(MyModel, asmibus.TargetModel):
pass
def adrgen_gen(): def adrgen_gen():
for i in range(10): for i in range(10):
print("Address: " + hex(i)) print("Address: " + hex(i))
@ -73,9 +70,6 @@ class TBWishboneReader(TBWishbone):
self.submodules.comp = CompositeActor(g) self.submodules.comp = CompositeActor(g)
TBWishbone.__init__(self, self.reader) TBWishbone.__init__(self, self.reader)
def do_simulation(self, s):
s.interrupt = self.adrgen.token_exchanger.done and not s.rd(self.comp.busy)
class TBWishboneWriter(TBWishbone): class TBWishboneWriter(TBWishbone):
def __init__(self): def __init__(self):
self.trgen = SimTrGen(30) self.trgen = SimTrGen(30)
@ -85,65 +79,14 @@ class TBWishboneWriter(TBWishbone):
self.submodules.comp = CompositeActor(g) self.submodules.comp = CompositeActor(g)
TBWishbone.__init__(self, self.writer) TBWishbone.__init__(self, self.writer)
def do_simulation(self, s):
s.interrupt = self.trgen.token_exchanger.done and not s.rd(self.comp.busy)
class TBAsmi(Module):
def __init__(self, nslots):
self.submodules.hub = asmibus.Hub(32, 32)
self.port = self.hub.get_port(nslots)
self.hub.finalize()
self.submodules.peripheral = asmibus.Target(MyModelASMI(), self.hub)
self.submodules.tap = asmibus.Tap(self.hub)
class TBAsmiReader(TBAsmi):
def __init__(self, nslots):
TBAsmi.__init__(self, nslots)
self.adrgen = SimAdrGen(32)
self.reader = dma_asmi.Reader(self.port)
self.dumper = SimDumper()
g = DataFlowGraph()
g.add_connection(self.adrgen, self.reader)
g.add_connection(self.reader, self.dumper)
self.submodules.comp = CompositeActor(g)
def do_simulation(self, s):
s.interrupt = self.adrgen.token_exchanger.done and not s.rd(self.comp.busy)
class TBAsmiWriter(TBAsmi):
def __init__(self, nslots):
TBAsmi.__init__(self, nslots)
self.trgen = SimTrGen(32)
self.writer = dma_asmi.Writer(self.port)
g = DataFlowGraph()
g.add_connection(self.trgen, self.writer)
self.submodules.comp = CompositeActor(g)
def do_simulation(self, s):
s.interrupt = self.trgen.token_exchanger.done and not s.rd(self.comp.busy)
def test_wb_reader(): def test_wb_reader():
print("*** Testing Wishbone reader") print("*** Testing Wishbone reader")
Simulator(TBWishboneReader()).run() run_simulation(TBWishboneReader())
def test_wb_writer(): def test_wb_writer():
print("*** Testing Wishbone writer") print("*** Testing Wishbone writer")
Simulator(TBWishboneWriter()).run() run_simulation(TBWishboneWriter())
def test_asmi_reader(nslots): if __name__ == "__main__":
print("*** Testing ASMI reader (nslots={})".format(nslots)) test_wb_reader()
Simulator(TBAsmiReader(nslots)).run() test_wb_writer()
def test_asmi_writer(nslots):
print("*** Testing ASMI writer (nslots={})".format(nslots))
Simulator(TBAsmiWriter(nslots)).run()
test_wb_reader()
test_wb_writer()
test_asmi_reader(1)
test_asmi_reader(2)
test_asmi_writer(1)
test_asmi_writer(2)

View file

@ -2,7 +2,7 @@ from migen.flow.network import *
from migen.flow.transactions import * from migen.flow.transactions import *
from migen.actorlib import misc from migen.actorlib import misc
from migen.actorlib.sim import * from migen.actorlib.sim import *
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
def source_gen(): def source_gen():
for i in range(10): for i in range(10):
@ -26,7 +26,7 @@ class SimSink(SimActor):
self.sink = Sink([("value", 32)]) self.sink = Sink([("value", 32)])
SimActor.__init__(self, sink_gen()) SimActor.__init__(self, sink_gen())
def main(): if __name__ == "__main__":
source = SimSource() source = SimSource()
loop = misc.IntSequence(32) loop = misc.IntSequence(32)
sink = SimSink() sink = SimSink()
@ -34,7 +34,4 @@ def main():
g.add_connection(source, loop) g.add_connection(source, loop)
g.add_connection(loop, sink) g.add_connection(loop, sink)
comp = CompositeActor(g) comp = CompositeActor(g)
sim = Simulator(comp) run_simulation(comp, ncycles=500)
sim.run(500)
main()

View file

@ -7,8 +7,8 @@ from migen.flow.network import *
from migen.flow.transactions import * from migen.flow.transactions import *
from migen.actorlib import structuring from migen.actorlib import structuring
from migen.actorlib.sim import * from migen.actorlib.sim import *
from migen.sim.generic import Simulator
from migen.flow import perftools from migen.flow import perftools
from migen.sim.generic import run_simulation
pack_factor = 5 pack_factor = 5
base_layout = [("value", 32)] base_layout = [("value", 32)]
@ -55,13 +55,11 @@ class TB(Module):
self.submodules.comp = CompositeActor(self.g) self.submodules.comp = CompositeActor(self.g)
self.submodules.reporter = perftools.DFGReporter(self.g) self.submodules.reporter = perftools.DFGReporter(self.g)
def main(): if __name__ == "__main__":
tb = TB() tb = TB()
sim = Simulator(tb).run(1000) run_simulation(tb, ncycles=1000)
g_layout = nx.spectral_layout(tb.g) g_layout = nx.spectral_layout(tb.g)
nx.draw(tb.g, g_layout) nx.draw(tb.g, g_layout)
nx.draw_networkx_edge_labels(tb.g, g_layout, tb.reporter.get_edge_labels()) nx.draw_networkx_edge_labels(tb.g, g_layout, tb.reporter.get_edge_labels())
plt.show() plt.show()
main()

View file

@ -2,7 +2,7 @@ from migen.flow.network import *
from migen.flow.transactions import * from migen.flow.transactions import *
from migen.actorlib.sim import * from migen.actorlib.sim import *
from migen.pytholite.compiler import Pytholite from migen.pytholite.compiler import Pytholite
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
from migen.fhdl import verilog from migen.fhdl import verilog
layout = [("r", 32)] layout = [("r", 32)]
@ -16,15 +16,13 @@ class SimNumberGen(SimActor):
self.result = Source(layout) self.result = Source(layout)
SimActor.__init__(self, number_gen(5)) SimActor.__init__(self, number_gen(5))
def run_sim(ng): def run_ng_sim(ng):
g = DataFlowGraph() g = DataFlowGraph()
d = Dumper(layout) d = Dumper(layout)
g.add_connection(ng, d) g.add_connection(ng, d)
c = CompositeActor(g) c = CompositeActor(g)
sim = Simulator(c) run_simulation(c, ncycles=20)
sim.run(20)
del sim
def make_ng_pytholite(): def make_ng_pytholite():
ng_pytholite = Pytholite(number_gen, 5) ng_pytholite = Pytholite(number_gen, 5)
@ -35,11 +33,11 @@ def make_ng_pytholite():
def main(): def main():
print("Simulating native Python:") print("Simulating native Python:")
ng_native = SimNumberGen() ng_native = SimNumberGen()
run_sim(ng_native) run_ng_sim(ng_native)
print("Simulating Pytholite:") print("Simulating Pytholite:")
ng_pytholite = make_ng_pytholite() ng_pytholite = make_ng_pytholite()
run_sim(ng_pytholite) run_ng_sim(ng_pytholite)
print("Converting Pytholite to Verilog:") print("Converting Pytholite to Verilog:")
ng_pytholite = make_ng_pytholite() ng_pytholite = make_ng_pytholite()

View file

@ -6,7 +6,7 @@ from migen.bus.transactions import *
from migen.genlib.ioo import UnifiedIOSimulation from migen.genlib.ioo import UnifiedIOSimulation
from migen.pytholite.transel import Register from migen.pytholite.transel import Register
from migen.pytholite.compiler import Pytholite from migen.pytholite.compiler import Pytholite
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.fhdl import verilog from migen.fhdl import verilog
@ -39,10 +39,8 @@ class TestBench(Module):
self.submodules.intercon = wishbone.InterconnectPointToPoint(ng.wb, self.slave.bus) self.submodules.intercon = wishbone.InterconnectPointToPoint(ng.wb, self.slave.bus)
self.submodules.ca = CompositeActor(g) self.submodules.ca = CompositeActor(g)
def run_sim(ng): def run_ng_sim(ng):
sim = Simulator(TestBench(ng)) run_simulation(TestBench(ng), ncycles=50)
sim.run(50)
del sim
def add_interfaces(obj): def add_interfaces(obj):
obj.result = Source(layout) obj.result = Source(layout)
@ -54,12 +52,12 @@ def main():
print("Simulating native Python:") print("Simulating native Python:")
ng_native = UnifiedIOSimulation(gen()) ng_native = UnifiedIOSimulation(gen())
add_interfaces(ng_native) add_interfaces(ng_native)
run_sim(ng_native) run_ng_sim(ng_native)
print("Simulating Pytholite:") print("Simulating Pytholite:")
ng_pytholite = Pytholite(gen) ng_pytholite = Pytholite(gen)
add_interfaces(ng_pytholite) add_interfaces(ng_pytholite)
run_sim(ng_pytholite) run_ng_sim(ng_pytholite)
print("Converting Pytholite to Verilog:") print("Converting Pytholite to Verilog:")
ng_pytholite = Pytholite(gen) ng_pytholite = Pytholite(gen)

View file

@ -1,7 +1,7 @@
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.bus.transactions import * from migen.bus.transactions import *
from migen.bus import lasmibus from migen.bus import lasmibus
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
def my_generator(n): def my_generator(n):
bank = n % 4 bank = n % 4
@ -30,16 +30,9 @@ class TB(Module):
def __init__(self): def __init__(self):
self.submodules.controller = lasmibus.Target(MyModel(), aw=4, dw=32, nbanks=4, req_queue_size=4, self.submodules.controller = lasmibus.Target(MyModel(), aw=4, dw=32, nbanks=4, req_queue_size=4,
read_latency=4, write_latency=1) read_latency=4, write_latency=1)
self.submodules.xbar = lasmibus.Crossbar([self.controller.bus], 4, 2) self.submodules.xbar = lasmibus.Crossbar([self.controller.bus], 2)
self.initiators = [lasmibus.Initiator(my_generator(n), bus) for n, bus in enumerate(self.xbar.masters)] self.initiators = [lasmibus.Initiator(my_generator(n), self.xbar.get_master()) for n in range(4)]
self.submodules += self.initiators self.submodules += self.initiators
def do_simulation(self, s): if __name__ == "__main__":
s.interrupt = all(m.done for m in self.initiators) run_simulation(TB())
def main():
tb = TB()
sim = Simulator(tb)
sim.run()
main()

View file

@ -3,7 +3,7 @@ from random import Random
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.bus.transactions import * from migen.bus.transactions import *
from migen.bus import wishbone from migen.bus import wishbone
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
# Our bus master. # Our bus master.
# Python generators let us program bus transactions in an elegant sequential style. # Python generators let us program bus transactions in an elegant sequential style.
@ -53,16 +53,8 @@ class TB(Module):
# Connect the master to the slave. # Connect the master to the slave.
self.submodules.intercon = wishbone.InterconnectPointToPoint(self.master.bus, self.slave.bus) self.submodules.intercon = wishbone.InterconnectPointToPoint(self.master.bus, self.slave.bus)
def do_simulation(self, s): if __name__ == "__main__":
# Terminate the simulation when the initiator is done (i.e. our generator is exhausted). run_simulation(TB())
s.interrupt = self.master.done
def main():
tb = TB()
sim = Simulator(tb)
sim.run()
main()
# Output: # Output:
# <TWrite adr:0x0 dat:0x0> # <TWrite adr:0x0 dat:0x0>

View file

@ -1,8 +1,5 @@
# Copyright (C) 2012 Vermeer Manufacturing Co.
# License: GPLv3 with additional permissions (see README).
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
# Our simple counter, which increments at every cycle # Our simple counter, which increments at every cycle
# and prints its current value in simulation. # and prints its current value in simulation.
@ -15,21 +12,17 @@ class Counter(Module):
self.sync += self.count.eq(self.count + 1) self.sync += self.count.eq(self.count + 1)
# This function will be called at every cycle. # This function will be called at every cycle.
def do_simulation(self, s): def do_simulation(self, selfp):
# Simply read the count signal and print it. # Simply read the count signal and print it.
# The output is: # The output is:
# Count: 0 # Count: 0
# Count: 1 # Count: 1
# Count: 2 # Count: 2
# ... # ...
print("Count: " + str(s.rd(self.count))) print("Count: " + str(selfp.count))
def main(): if __name__ == "__main__":
dut = Counter() dut = Counter()
# We do not specify a top-level nor runner object, and use the defaults. # Since we do not use StopSimulation, limit the simulation
sim = Simulator(dut)
# Since we do not use sim.interrupt, limit the simulation
# to some number of cycles. # to some number of cycles.
sim.run(20) run_simulation(dut, ncycles=20)
main()

View file

@ -1,10 +1,7 @@
# Copyright (C) 2012 Vermeer Manufacturing Co.
# License: GPLv3 with additional permissions (see README).
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.sim.generic import Simulator, TopLevel from migen.sim.generic import run_simulation
# A slightly improved counter. # A slightly more elaborate counter.
# Has a clock enable (CE) signal, counts on more bits # Has a clock enable (CE) signal, counts on more bits
# and resets with a negative number. # and resets with a negative number.
class Counter(Module): class Counter(Module):
@ -15,34 +12,25 @@ class Counter(Module):
self.sync += If(self.ce, self.count.eq(self.count + 1)) self.sync += If(self.ce, self.count.eq(self.count + 1))
def do_simulation(self, s): def do_simulation(self, selfp):
# Only assert CE every second cycle. # Only assert CE every second cycle.
# => each counter value is held for two cycles. # => each counter value is held for two cycles.
if s.cycle_counter % 2: if selfp.simulator.cycle_counter % 2:
s.wr(self.ce, 0) # This is how you write to a signal. selfp.ce = 0 # This is how you write to a signal.
else: else:
s.wr(self.ce, 1) selfp.ce = 1
print("Cycle: " + str(s.cycle_counter) + " Count: " + \ print("Cycle: " + str(selfp.simulator.cycle_counter) + " Count: " + \
str(s.rd(self.count))) str(selfp.count))
# Set the "initialize" property on our simulation function.
# The simulator will call it during the reset cycle,
# with s.cycle_counter == -1.
do_simulation.initialize = True
# Output is: # Output is:
# Cycle: -1 Count: 0 # Cycle: 0 Count: -5
# Cycle: 0 Count: -5 # Cycle: 1 Count: -5
# Cycle: 1 Count: -5 # Cycle: 2 Count: -4
# Cycle: 2 Count: -4 # Cycle: 3 Count: -4
# Cycle: 3 Count: -4 # Cycle: 4 Count: -3
# Cycle: 4 Count: -3 # ...
# ...
def main(): if __name__ == "__main__":
dut = Counter() dut = Counter()
# Instantiating the generic top-level ourselves lets us # Demonstrate VCD output
# specify a VCD output file. run_simulation(dut, vcd_name="my.vcd", ncycles=20)
sim = Simulator(dut, TopLevel("my.vcd"))
sim.run(20)
main()

View file

@ -6,7 +6,7 @@ import matplotlib.pyplot as plt
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.fhdl import verilog from migen.fhdl import verilog
from migen.genlib.cordic import Cordic from migen.genlib.cordic import Cordic
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
class TestBench(Module): class TestBench(Module):
def __init__(self, n=None, xmax=.98, i=None, **kwargs): def __init__(self, n=None, xmax=.98, i=None, **kwargs):
@ -23,25 +23,17 @@ class TestBench(Module):
self.ii = iter(self.i) self.ii = iter(self.i)
self.o = [] self.o = []
def do_simulation(self, s): def do_simulation(self, selfp):
if s.rd(self.cordic.new_in): if selfp.cordic.new_in:
try: try:
xi, yi, zi = next(self.ii) selfp.cordic.xi, selfp.cordic.yi, selfp.cordic.zi = next(self.ii)
except StopIteration: except StopIteration:
s.interrupt = True raise StopSimulation
return if selfp.cordic.new_out:
s.wr(self.cordic.xi, xi) self.o.append((selfp.cordic.xo, selfp.cordic.yo, selfp.cordic.zo))
s.wr(self.cordic.yi, yi)
s.wr(self.cordic.zi, zi)
if s.rd(self.cordic.new_out):
xo = s.rd(self.cordic.xo)
yo = s.rd(self.cordic.yo)
zo = s.rd(self.cordic.zo)
self.o.append((xo, yo, zo))
def run_io(self): def run_io(self):
with Simulator(self) as sim: run_simulation(self)
sim.run()
del self.i[-1], self.o[0] del self.i[-1], self.o[0]
if self.i[0] != (0, 0, 0): if self.i[0] != (0, 0, 0):
assert self.o[0] != (0, 0, 0) assert self.o[0] != (0, 0, 0)

View file

@ -3,7 +3,7 @@ from migen.flow.actor import *
from migen.flow.transactions import * from migen.flow.transactions import *
from migen.flow.network import * from migen.flow.network import *
from migen.actorlib.sim import * from migen.actorlib.sim import *
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
def source_gen(): def source_gen():
for i in range(10): for i in range(10):
@ -34,7 +34,5 @@ class TB(Module):
g.add_connection(self.source, self.sink) g.add_connection(self.source, self.sink)
self.submodules.comp = CompositeActor(g) self.submodules.comp = CompositeActor(g)
def do_simulation(self, s): if __name__ == "__main__":
s.interrupt = self.source.token_exchanger.done run_simulation(TB())
Simulator(TB()).run()

View file

@ -1,6 +1,3 @@
# Copyright (C) 2012 Vermeer Manufacturing Co.
# License: GPLv3 with additional permissions (see README).
from math import cos, pi from math import cos, pi
from scipy import signal from scipy import signal
import matplotlib.pyplot as plt import matplotlib.pyplot as plt
@ -8,7 +5,7 @@ import matplotlib.pyplot as plt
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.fhdl import verilog from migen.fhdl import verilog
from migen.genlib.misc import optree from migen.genlib.misc import optree
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
# A synthesizable FIR filter. # A synthesizable FIR filter.
class FIR(Module): class FIR(Module):
@ -41,14 +38,14 @@ class TB(Module):
self.inputs = [] self.inputs = []
self.outputs = [] self.outputs = []
def do_simulation(self, s): def do_simulation(self, selfp):
f = 2**(self.fir.wsize - 1) f = 2**(self.fir.wsize - 1)
v = 0.1*cos(2*pi*self.frequency*s.cycle_counter) v = 0.1*cos(2*pi*self.frequency*selfp.simulator.cycle_counter)
s.wr(self.fir.i, int(f*v)) selfp.fir.i = int(f*v)
self.inputs.append(v) self.inputs.append(v)
self.outputs.append(s.rd(self.fir.o)/f) self.outputs.append(selfp.fir.o/f)
def main(): if __name__ == "__main__":
# Compute filter coefficients with SciPy. # Compute filter coefficients with SciPy.
coef = signal.remez(30, [0, 0.1, 0.2, 0.4, 0.45, 0.5], [0, 1, 0]) coef = signal.remez(30, [0, 0.1, 0.2, 0.4, 0.45, 0.5], [0, 1, 0])
@ -58,9 +55,7 @@ def main():
out_signals = [] out_signals = []
for frequency in [0.05, 0.1, 0.25]: for frequency in [0.05, 0.1, 0.25]:
tb = TB(coef, frequency) tb = TB(coef, frequency)
sim = Simulator(tb) run_simulation(tb, ncycles=200)
sim.run(200)
del sim
in_signals += tb.inputs in_signals += tb.inputs
out_signals += tb.outputs out_signals += tb.outputs
@ -72,5 +67,3 @@ def main():
# Print the Verilog source for the filter. # Print the Verilog source for the filter.
fir = FIR(coef) fir = FIR(coef)
print(verilog.convert(fir, ios={fir.i, fir.o})) print(verilog.convert(fir, ios={fir.i, fir.o}))
main()

View file

@ -1,8 +1,5 @@
# Copyright (C) 2012 Vermeer Manufacturing Co.
# License: GPLv3 with additional permissions (see README).
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
class Mem(Module): class Mem(Module):
def __init__(self): def __init__(self):
@ -10,23 +7,19 @@ class Mem(Module):
# from 0 to 19. # from 0 to 19.
self.specials.mem = Memory(16, 2**12, init=list(range(20))) self.specials.mem = Memory(16, 2**12, init=list(range(20)))
def do_simulation(self, s): def do_simulation(self, selfp):
# Read the memory. Use the cycle counter as address. # Read the memory. Use the cycle counter as address.
value = s.rd(self.mem, s.cycle_counter) value = selfp.mem[selfp.simulator.cycle_counter]
# Print the result. Output is: # Print the result. Output is:
# 0 # 0
# 1 # 1
# 2 # 2
# ... # ...
print(value) print(value)
# Demonstrate how to interrupt the simulator. # Raising StopSimulation disables the current (and here, only one)
# simulation function. Simulator stops when all functions are disabled.
if value == 10: if value == 10:
s.interrupt = True raise StopSimulation
def main(): if __name__ == "__main__":
dut = Mem() run_simulation(Mem())
sim = Simulator(dut)
# No need for a cycle limit here, we use sim.interrupt instead.
sim.run()
main()

View file

@ -1,6 +1,25 @@
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.flow.actor import * from migen.flow.actor import *
from migen.flow.transactions import * from migen.flow.transactions import *
from migen.util.misc import xdir
def _sim_multiread(sim, obj):
if isinstance(obj, Signal):
return sim.rd(obj)
else:
r = {}
for k, v in xdir(obj, True):
rd = _sim_multiread(sim, v)
if isinstance(rd, int) or rd:
r[k] = rd
return r
def _sim_multiwrite(sim, obj, value):
if isinstance(obj, Signal):
sim.wr(obj, value)
else:
for k, v in value.items():
_sim_multiwrite(sim, getattr(obj, k), v)
# Generators yield None or a tuple of Tokens. # Generators yield None or a tuple of Tokens.
# Tokens for Sink endpoints are pulled and the "value" field filled in. # Tokens for Sink endpoints are pulled and the "value" field filled in.
@ -14,35 +33,34 @@ class TokenExchanger(Module):
self.actor = actor self.actor = actor
self.active = set() self.active = set()
self.busy = True self.busy = True
self.done = False
def _process_transactions(self, s): def _process_transactions(self, selfp):
completed = set() completed = set()
for token in self.active: for token in self.active:
ep = getattr(self.actor, token.endpoint) ep = getattr(self.actor, token.endpoint)
if isinstance(ep, Sink): if isinstance(ep, Sink):
if s.rd(ep.ack) and s.rd(ep.stb): if selfp.simulator.rd(ep.ack) and selfp.simulator.rd(ep.stb):
token.value = s.multiread(ep.payload) token.value = _sim_multiread(selfp.simulator, ep.payload)
completed.add(token) completed.add(token)
s.wr(ep.ack, 0) selfp.simulator.wr(ep.ack, 0)
elif isinstance(ep, Source): elif isinstance(ep, Source):
if s.rd(ep.ack) and s.rd(ep.stb): if selfp.simulator.rd(ep.ack) and selfp.simulator.rd(ep.stb):
completed.add(token) completed.add(token)
s.wr(ep.stb, 0) selfp.simulator.wr(ep.stb, 0)
else: else:
raise TypeError raise TypeError
self.active -= completed self.active -= completed
if not self.active: if not self.active:
self.busy = True self.busy = True
def _update_control_signals(self, s): def _update_control_signals(self, selfp):
for token in self.active: for token in self.active:
ep = getattr(self.actor, token.endpoint) ep = getattr(self.actor, token.endpoint)
if isinstance(ep, Sink): if isinstance(ep, Sink):
s.wr(ep.ack, 1) selfp.simulator.wr(ep.ack, 1)
elif isinstance(ep, Source): elif isinstance(ep, Source):
s.multiwrite(ep.payload, token.value) _sim_multiwrite(selfp.simulator, ep.payload, token.value)
s.wr(ep.stb, 1) selfp.simulator.wr(ep.stb, 1)
else: else:
raise TypeError raise TypeError
@ -50,9 +68,8 @@ class TokenExchanger(Module):
try: try:
transactions = next(self.generator) transactions = next(self.generator)
except StopIteration: except StopIteration:
self.done = True
self.busy = False self.busy = False
transactions = None raise StopSimulation
if isinstance(transactions, Token): if isinstance(transactions, Token):
self.active = {transactions} self.active = {transactions}
elif isinstance(transactions, (tuple, list, set)): elif isinstance(transactions, (tuple, list, set)):
@ -64,23 +81,20 @@ class TokenExchanger(Module):
if self.active and all(transaction.idle_wait for transaction in self.active): if self.active and all(transaction.idle_wait for transaction in self.active):
self.busy = False self.busy = False
def do_simulation(self, s): def do_simulation(self, selfp):
if not self.done: if self.active:
if self.active: self._process_transactions(selfp)
self._process_transactions(s) if not self.active:
if not self.active: self._next_transactions()
self._next_transactions() self._update_control_signals(selfp)
self._update_control_signals(s)
do_simulation.initialize = True
class SimActor(Module): class SimActor(Module):
def __init__(self, generator): def __init__(self, generator):
self.busy = Signal() self.busy = Signal()
self.submodules.token_exchanger = TokenExchanger(generator, self) self.submodules.token_exchanger = TokenExchanger(generator, self)
def do_simulation(self, s): def do_simulation(self, selfp):
s.wr(self.busy, self.token_exchanger.busy) selfp.busy = self.token_exchanger.busy
def _dumper_gen(prefix): def _dumper_gen(prefix):
while True: while True:

View file

@ -190,42 +190,40 @@ class Initiator(Module):
self.transaction_start = 0 self.transaction_start = 0
self.transaction = None self.transaction = None
self.transaction_end = None self.transaction_end = None
self.done = False
def do_simulation(self, s): def do_simulation(self, selfp):
s.wr(self.bus.dat_w, 0) selfp.bus.dat_w = 0
s.wr(self.bus.dat_we, 0) selfp.bus.dat_we = 0
if not self.done:
if self.transaction is not None:
if s.rd(self.bus.req_ack):
s.wr(self.bus.stb, 0)
if s.rd(self.bus.dat_ack):
if isinstance(self.transaction, TRead):
self.transaction_end = s.cycle_counter + self.bus.read_latency
else:
self.transaction_end = s.cycle_counter + self.bus.write_latency - 1
if self.transaction is None or s.cycle_counter == self.transaction_end: if self.transaction is not None:
if self.transaction is not None: if selfp.bus.req_ack:
self.transaction.latency = s.cycle_counter - self.transaction_start - 1 selfp.bus.stb = 0
if isinstance(self.transaction, TRead): if selfp.bus.dat_ack:
self.transaction.data = s.rd(self.bus.dat_r) if isinstance(self.transaction, TRead):
else: self.transaction_end = selfp.simulator.cycle_counter + self.bus.read_latency
s.wr(self.bus.dat_w, self.transaction.data) else:
s.wr(self.bus.dat_we, self.transaction.sel) self.transaction_end = selfp.simulator.cycle_counter + self.bus.write_latency - 1
try:
self.transaction = next(self.generator) if self.transaction is None or selfp.simulator.cycle_counter == self.transaction_end:
except StopIteration: if self.transaction is not None:
self.done = True self.transaction.latency = selfp.simulator.cycle_counter - self.transaction_start - 1
self.transaction = None if isinstance(self.transaction, TRead):
if self.transaction is not None: self.transaction.data = selfp.bus.dat_r
self.transaction_start = s.cycle_counter else:
s.wr(self.bus.stb, 1) selfp.bus.dat_w = self.transaction.data
s.wr(self.bus.adr, self.transaction.address) selfp.bus.dat_we = self.transaction.sel
if isinstance(self.transaction, TRead): try:
s.wr(self.bus.we, 0) self.transaction = next(self.generator)
else: except StopIteration:
s.wr(self.bus.we, 1) raise StopSimulation
if self.transaction is not None:
self.transaction_start = selfp.simulator.cycle_counter
selfp.bus.stb = 1
selfp.bus.adr = self.transaction.address
if isinstance(self.transaction, TRead):
selfp.bus.we = 0
else:
selfp.bus.we = 1
class TargetModel: class TargetModel:
def __init__(self): def __init__(self):
@ -254,14 +252,14 @@ class _ReqFIFO(Module):
self.bank = bank self.bank = bank
self.contents = [] self.contents = []
def do_simulation(self, s): def do_simulation(self, selfp):
if len(self.contents) < self.req_queue_size: if len(self.contents) < self.req_queue_size:
if s.rd(self.bank.stb): if selfp.bank.stb:
self.contents.append((s.rd(self.bank.we), s.rd(self.bank.adr))) self.contents.append((selfp.bank.we, selfp.bank.adr))
s.wr(self.bank.req_ack, 1) selfp.bank.req_ack = 1
else: else:
s.wr(self.bank.req_ack, 0) selfp.bank.req_ack = 0
s.wr(self.bank.lock, bool(self.contents)) selfp.bank.lock = bool(self.contents)
class Target(Module): class Target(Module):
def __init__(self, model, *ifargs, **ifkwargs): def __init__(self, model, *ifargs, **ifkwargs):
@ -273,7 +271,7 @@ class Target(Module):
self.rd_pipeline = [None]*self.bus.read_latency self.rd_pipeline = [None]*self.bus.read_latency
self.wr_pipeline = [None]*(self.bus.write_latency + 1) self.wr_pipeline = [None]*(self.bus.write_latency + 1)
def do_simulation(self, s): def do_simulation(self, selfp):
# determine banks with pending requests # determine banks with pending requests
pending_banks = set(nb for nb, rf in enumerate(self.req_fifos) if rf.contents) pending_banks = set(nb for nb, rf in enumerate(self.req_fifos) if rf.contents)
@ -281,12 +279,12 @@ class Target(Module):
selected_bank_n = self.model.select_bank(pending_banks) selected_bank_n = self.model.select_bank(pending_banks)
selected_transaction = None selected_transaction = None
for nb in range(self.bus.nbanks): for nb in range(self.bus.nbanks):
bank = getattr(self.bus, "bank"+str(nb)) bank = getattr(selfp.bus, "bank"+str(nb))
if nb == selected_bank_n: if nb == selected_bank_n:
s.wr(bank.dat_ack, 1) bank.dat_ack = 1
selected_transaction = self.req_fifos[nb].contents.pop(0) selected_transaction = self.req_fifos[nb].contents.pop(0)
else: else:
s.wr(bank.dat_ack, 0) bank.dat_ack = 0
rd_transaction = None rd_transaction = None
wr_transaction = None wr_transaction = None
@ -303,7 +301,7 @@ class Target(Module):
done_rd_transaction = self.rd_pipeline.pop(0) done_rd_transaction = self.rd_pipeline.pop(0)
done_wr_transaction = self.wr_pipeline.pop(0) done_wr_transaction = self.wr_pipeline.pop(0)
if done_rd_transaction is not None: if done_rd_transaction is not None:
s.wr(self.bus.dat_r, self.model.read(done_rd_transaction[0], done_rd_transaction[1])) selfp.bus.dat_r = self.model.read(done_rd_transaction[0], done_rd_transaction[1])
if done_wr_transaction is not None: if done_wr_transaction is not None:
self.model.write(done_wr_transaction[0], done_wr_transaction[1], self.model.write(done_wr_transaction[0], done_wr_transaction[1],
s.rd(self.bus.dat_w), s.rd(self.bus.dat_we)) selfp.bus.dat_w, selfp.bus.dat_we)

View file

@ -19,18 +19,16 @@ class Initiator(Module):
def __init__(self, generator, mem): def __init__(self, generator, mem):
self.generator = generator self.generator = generator
self.mem = mem self.mem = mem
self.done = False
def do_simulation(self, s): def do_simulation(self, selfp):
if not self.done: try:
try: transaction = next(self.generator)
transaction = next(self.generator) except StopIteration:
except StopIteration: transaction = None
self.done = True raise StopSimulation
transaction = None if isinstance(transaction, TRead):
if isinstance(transaction, TRead): transaction.data = selfp.mem[transaction.address]
transaction.data = s.rd(self.mem, transaction.address) elif isinstance(transaction, TWrite):
elif isinstance(transaction, TWrite): d = selfp.mem[transaction.address]
d = s.rd(self.mem, transaction.address) d_mask = _byte_mask(d, transaction.data, transaction.sel)
d_mask = _byte_mask(d, transaction.data, transaction.sel) selfp.mem[transaction.address] = d_mask
s.wr(s.mem, d_mask, transaction.address)

View file

@ -4,7 +4,6 @@ from migen.genlib.record import *
from migen.genlib.misc import optree, chooser from migen.genlib.misc import optree, chooser
from migen.genlib.fsm import FSM, NextState from migen.genlib.fsm import FSM, NextState
from migen.bus.transactions import * from migen.bus.transactions import *
from migen.sim.generic import Proxy
_layout = [ _layout = [
("adr", 30, DIR_M_TO_S), ("adr", 30, DIR_M_TO_S),
@ -202,16 +201,16 @@ class Tap(Module):
self.bus = bus self.bus = bus
self.handler = handler self.handler = handler
def do_simulation(self, s): def do_simulation(self, selfp):
if s.rd(self.bus.ack): if selfp.bus.ack:
assert(s.rd(self.bus.cyc) and s.rd(self.bus.stb)) assert(selfp.bus.cyc and selfp.bus.stb)
if s.rd(self.bus.we): if selfp.bus.we:
transaction = TWrite(s.rd(self.bus.adr), transaction = TWrite(selfp.bus.adr,
s.rd(self.bus.dat_w), selfp.bus.dat_w,
s.rd(self.bus.sel)) selfp.bus.sel)
else: else:
transaction = TRead(s.rd(self.bus.adr), transaction = TRead(selfp.bus.adr,
s.rd(self.bus.dat_r)) selfp.bus.dat_r)
self.handler(transaction) self.handler(transaction)
class Initiator(Module): class Initiator(Module):
@ -222,34 +221,33 @@ class Initiator(Module):
self.bus = bus self.bus = bus
self.transaction_start = 0 self.transaction_start = 0
self.transaction = None self.transaction = None
self.done = False
def do_simulation(self, s): def do_simulation(self, selfp):
if not self.done: if self.transaction is None or selfp.bus.ack:
if self.transaction is None or s.rd(self.bus.ack): if self.transaction is not None:
if self.transaction is not None: self.transaction.latency = selfp.simulator.cycle_counter - self.transaction_start - 1
self.transaction.latency = s.cycle_counter - self.transaction_start - 1 if isinstance(self.transaction, TRead):
if isinstance(self.transaction, TRead): self.transaction.data = selfp.bus.dat_r
self.transaction.data = s.rd(self.bus.dat_r) try:
try: self.transaction = next(self.generator)
self.transaction = next(self.generator) except StopIteration:
except StopIteration: selfp.bus.cyc = 0
self.done = True selfp.bus.stb = 0
self.transaction = None raise StopSimulation
if self.transaction is not None: if self.transaction is not None:
self.transaction_start = s.cycle_counter self.transaction_start = selfp.simulator.cycle_counter
s.wr(self.bus.cyc, 1) selfp.bus.cyc = 1
s.wr(self.bus.stb, 1) selfp.bus.stb = 1
s.wr(self.bus.adr, self.transaction.address) selfp.bus.adr = self.transaction.address
if isinstance(self.transaction, TWrite): if isinstance(self.transaction, TWrite):
s.wr(self.bus.we, 1) selfp.bus.we = 1
s.wr(self.bus.sel, self.transaction.sel) selfp.bus.sel = self.transaction.sel
s.wr(self.bus.dat_w, self.transaction.data) selfp.bus.dat_w = self.transaction.data
else:
s.wr(self.bus.we, 0)
else: else:
s.wr(self.bus.cyc, 0) selfp.bus.we = 0
s.wr(self.bus.stb, 0) else:
selfp.bus.cyc = 0
selfp.bus.stb = 0
class TargetModel: class TargetModel:
def read(self, address): def read(self, address):
@ -268,8 +266,8 @@ class Target(Module):
self.bus = bus self.bus = bus
self.model = model self.model = model
def do_simulation(self, s): def do_simulation(self, selfp):
bus = Proxy(s, self.bus) bus = selfp.bus
if not bus.ack: if not bus.ack:
if self.model.can_ack(bus) and bus.cyc and bus.stb: if self.model.can_ack(bus) and bus.cyc and bus.stb:
if bus.we: if bus.we:

View file

@ -1,11 +1,11 @@
import collections import collections
from itertools import combinations from itertools import combinations
from migen.util.misc import flat_iteration
from migen.fhdl.structure import * from migen.fhdl.structure import *
from migen.fhdl.structure import _Fragment from migen.fhdl.structure import _Fragment
from migen.fhdl.specials import Special
from migen.fhdl.tools import rename_clock_domain from migen.fhdl.tools import rename_clock_domain
from migen.util.misc import flat_iteration from migen.sim.upper import GenSim, ProxySim
class FinalizeError(Exception): class FinalizeError(Exception):
pass pass
@ -106,10 +106,21 @@ class Module:
self.finalized = False self.finalized = False
return self.finalized return self.finalized
elif name == "_fragment": elif name == "_fragment":
simf = None
try: try:
sim = [self.do_simulation] simf = self.do_simulation
except AttributeError: except AttributeError:
sim = [] try:
simg = self.gen_simulation
except AttributeError:
pass
else:
gs = GenSim(simg)
simf = gs.do_simulation
if simf is not None:
ps = ProxySim(self, simf)
simf = ps.do_simulation
sim = [] if simf is None else [simf]
self._fragment = _Fragment(sim=sim) self._fragment = _Fragment(sim=sim)
return self._fragment return self._fragment
elif name == "_submodules": elif name == "_submodules":

View file

@ -528,6 +528,9 @@ class _ClockDomainList(list):
(SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3) (SPECIAL_INPUT, SPECIAL_OUTPUT, SPECIAL_INOUT) = range(3)
class StopSimulation(Exception):
pass
class _Fragment: class _Fragment:
def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None): def __init__(self, comb=None, sync=None, specials=None, clock_domains=None, sim=None):
if comb is None: comb = [] if comb is None: comb = []

View file

@ -16,9 +16,9 @@ class EndpointSimHook(Module):
def on_inactive(self): def on_inactive(self):
pass pass
def do_simulation(self, s): def do_simulation(self, selfp):
if s.rd(self.endpoint.stb): if selfp.endpoint.stb:
if s.rd(self.endpoint.ack): if selfp.endpoint.ack:
self.on_ack() self.on_ack()
else: else:
self.on_nack() self.on_nack()

View file

@ -73,9 +73,14 @@ end
return r return r
def _call_sim(fragment, simulator): def _call_sim(fragment, simulator):
del_list = []
for s in fragment.sim: for s in fragment.sim:
if simulator.cycle_counter >= 0 or (hasattr(s, "initialize") and s.initialize): try:
s(simulator) s(simulator)
except StopSimulation:
del_list.append(s)
for s in del_list:
fragment.sim.remove(s)
class Simulator: class Simulator:
def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts): def __init__(self, fragment, top_level=None, sim_runner=None, sockaddr="simsocket", **vopts):
@ -99,19 +104,16 @@ class Simulator:
**vopts) **vopts)
self.cycle_counter = -1 self.cycle_counter = -1
self.interrupt = False
self.sim_runner = sim_runner self.sim_runner = sim_runner
self.sim_runner.start(c_top, c_fragment) self.sim_runner.start(c_top, c_fragment)
self.ipc.accept() self.ipc.accept()
reply = self.ipc.recv() reply = self.ipc.recv()
assert(isinstance(reply, MessageTick)) assert(isinstance(reply, MessageTick))
_call_sim(self.fragment, self)
def run(self, ncycles=-1): def run(self, ncycles=None):
self.interrupt = False
counter = 0 counter = 0
while not self.interrupt and (ncycles < 0 or counter < ncycles): while self.fragment.sim and (ncycles is None or counter < ncycles):
self.cycle_counter += 1 self.cycle_counter += 1
counter += 1 counter += 1
self.ipc.send(MessageGo()) self.ipc.send(MessageGo())
@ -150,34 +152,6 @@ class Simulator:
assert(value >= 0 and value < 2**nbits) assert(value >= 0 and value < 2**nbits)
self.ipc.send(MessageWrite(name, Int32(index), value)) self.ipc.send(MessageWrite(name, Int32(index), value))
def multiread(self, obj):
if isinstance(obj, Signal):
return self.rd(obj)
elif isinstance(obj, list):
r = []
for item in obj:
rd = self.multiread(item)
if isinstance(item, Signal) or rd:
r.append(rd)
return r
elif hasattr(obj, "__dict__"):
r = {}
for k, v in obj.__dict__.items():
rd = self.multiread(v)
if isinstance(v, Signal) or rd:
r[k] = rd
return r
def multiwrite(self, obj, value):
if isinstance(obj, Signal):
self.wr(obj, value)
elif isinstance(obj, list):
for target, source in zip(obj, value):
self.multiwrite(target, source)
else:
for k, v in value.items():
self.multiwrite(getattr(obj, k), v)
def __del__(self): def __del__(self):
if hasattr(self, "ipc"): if hasattr(self, "ipc"):
warnings.warn("call Simulator.close() to clean up " warnings.warn("call Simulator.close() to clean up "
@ -193,26 +167,9 @@ class Simulator:
def __enter__(self): def __enter__(self):
return self return self
def __exit__(self, type, value, traceback): def __exit__(self, type, value, traceback):
self.close() self.close()
# Contrary to multiread/multiwrite, Proxy fetches the necessary signals only and def run_simulation(fragment, ncycles=None, vcd_name=None, keep_files=False):
# immediately forwards writes into the simulation. with Simulator(fragment, TopLevel(vcd_name), icarus.Runner(keep_files=keep_files)) as s:
class Proxy: s.run(ncycles)
def __init__(self, sim, obj):
self.__dict__["_sim"] = sim
self.__dict__["_obj"] = obj
def __getattr__(self, name):
item = getattr(self._obj, name)
if isinstance(item, Signal):
return self._sim.rd(item)
elif isinstance(item, list):
return [Proxy(self._sim, si) for si in item]
else:
return Proxy(self._sim, item)
def __setattr__(self, name, value):
item = getattr(self._obj, name)
assert(isinstance(item, Signal))
self._sim.wr(item, value)

99
migen/sim/upper.py Normal file
View file

@ -0,0 +1,99 @@
from migen.fhdl.structure import Signal, StopSimulation
from migen.fhdl.specials import Memory
class MemoryProxy:
def __init__(self, simulator, obj):
self.simulator = simulator
self._simproxy_obj = obj
def __getitem__(self, key):
if isinstance(key, int):
return self.simulator.rd(self._simproxy_obj, key)
else:
start, stop, step = key.indices(self._simproxy_obj.depth)
return [self.simulator.rd(self._simproxy_obj, i) for i in range(start, stop, step)]
def __setitem__(self, key, value):
if isinstance(key, int):
self.simulator.wr(self._simproxy_obj, key, value)
else:
start, stop, step = key.indices(self.__obj.depth)
if len(value) != (stop - start)//step:
raise ValueError
for i, v in zip(range(start, stop, step), value):
self.simulator.wr(self._simproxy_obj, i, v)
class Proxy:
def __init__(self, simulator, obj):
object.__setattr__(self, "simulator", simulator)
object.__setattr__(self, "_simproxy_obj", obj)
def __process_get(self, item):
if isinstance(item, Signal):
return self.simulator.rd(item)
elif isinstance(item, Memory):
return MemoryProxy(self.simulator, item)
else:
return Proxy(self.simulator, item)
def __getattr__(self, name):
return self.__process_get(getattr(self._simproxy_obj, name))
def __setattr__(self, name, value):
item = getattr(self._simproxy_obj, name)
assert(isinstance(item, Signal))
self.simulator.wr(item, value)
def __getitem__(self, key):
return self.__process_get(self._simproxy_obj[key])
def __setitem__(self, key, value):
item = self._simproxy_obj[key]
assert(isinstance(item, Signal))
self.simulator.wr(item, value)
class GenSim:
def __init__(self, simg):
self.simg = simg
self.gens = dict()
self.resume_cycle = 0
def do_simulation(self, s):
if isinstance(s, Proxy):
simulator = s.simulator
else:
simulator = s
if simulator.cycle_counter >= self.resume_cycle:
try:
gen = self.gens[simulator]
except KeyError:
gen = self.simg(s)
self.gens[simulator] = gen
try:
n = next(gen)
except StopIteration:
del self.gens[simulator]
raise StopSimulation
else:
if n is None:
n = 1
self.resume_cycle = simulator.cycle_counter + n
class ProxySim:
def __init__(self, target, simf):
self.target = target
self.simf = simf
self.proxies = dict()
def do_simulation(self, simulator):
try:
proxy = self.proxies[simulator]
except KeyError:
proxy = Proxy(simulator, self.target)
self.proxies[simulator] = proxy
try:
self.simf(proxy)
except StopSimulation:
del self.proxies[simulator]
raise

View file

@ -1,13 +1,12 @@
import unittest
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.sim.generic import Simulator from migen.sim.generic import run_simulation
from migen.fhdl import verilog from migen.fhdl import verilog
class SimBench(Module): class SimBench(Module):
callback = None callback = None
def do_simulation(self, s): def do_simulation(self, selfp):
if self.callback is not None: if self.callback is not None:
return self.callback(self, s) return self.callback(self, selfp)
class SimCase: class SimCase:
TestBench = SimBench TestBench = SimBench
@ -18,7 +17,6 @@ class SimCase:
def test_to_verilog(self): def test_to_verilog(self):
verilog.convert(self.tb) verilog.convert(self.tb)
def run_with(self, cb, cycles=-1): def run_with(self, cb, ncycles=-1):
self.tb.callback = cb self.tb.callback = cb
with Simulator(self.tb) as s: run_simulation(self.tb, ncycles=ncycles)
s.run(cycles)

View file

@ -17,16 +17,13 @@ class EncCase(SimCase, unittest.TestCase):
def test_run_sequence(self): def test_run_sequence(self):
seq = list(range(1<<8)) seq = list(range(1<<8))
cur = None def cb(tb, tbp):
def cb(tb, s):
if seq: if seq:
s.wr(tb.dut.i, seq.pop(0)) tbp.dut.i = seq.pop(0)
i = s.rd(tb.dut.i) if tbp.dut.n:
if s.rd(tb.dut.n): self.assertNotIn(tbp.dut.i, [1<<i for i in range(8)])
self.assertNotIn(i, [1<<i for i in range(8)])
else: else:
o = s.rd(tb.dut.o) self.assertEqual(tbp.dut.i, 1<<tbp.dut.o)
self.assertEqual(i, 1<<o)
self.run_with(cb, 256) self.run_with(cb, 256)
class PrioEncCase(SimCase, unittest.TestCase): class PrioEncCase(SimCase, unittest.TestCase):
@ -41,15 +38,14 @@ class PrioEncCase(SimCase, unittest.TestCase):
def test_run_sequence(self): def test_run_sequence(self):
seq = list(range(1<<8)) seq = list(range(1<<8))
cur = None def cb(tb, tbp):
def cb(tb, s):
if seq: if seq:
s.wr(tb.dut.i, seq.pop(0)) tbp.dut.i = seq.pop(0)
i = s.rd(tb.dut.i) i = tbp.dut.i
if s.rd(tb.dut.n): if tbp.dut.n:
self.assertEqual(i, 0) self.assertEqual(i, 0)
else: else:
o = s.rd(tb.dut.o) o = tbp.dut.o
if o > 0: if o > 0:
self.assertEqual(i & 1<<(o - 1), 0) self.assertEqual(i & 1<<(o - 1), 0)
self.assertGreaterEqual(i, 1<<o) self.assertGreaterEqual(i, 1<<o)
@ -67,15 +63,14 @@ class DecCase(SimCase, unittest.TestCase):
def test_run_sequence(self): def test_run_sequence(self):
seq = list(range(8*2)) seq = list(range(8*2))
cur = None def cb(tb, tbp):
def cb(tb, s):
if seq: if seq:
i = seq.pop() i = seq.pop()
s.wr(tb.dut.i, i//2) tbp.dut.i = i//2
s.wr(tb.dut.n, i%2) tbp.dut.n = i%2
i = s.rd(tb.dut.i) i = tbp.dut.i
o = s.rd(tb.dut.o) o = tbp.dut.o
if s.rd(tb.dut.n): if tbp.dut.n:
self.assertEqual(o, 0) self.assertEqual(o, 0)
else: else:
self.assertEqual(o, 1<<i) self.assertEqual(o, 1<<i)

View file

@ -7,7 +7,6 @@ from migen.genlib.cordic import *
from migen.test.support import SimCase, SimBench from migen.test.support import SimCase, SimBench
class CordicCase(SimCase, unittest.TestCase): class CordicCase(SimCase, unittest.TestCase):
class TestBench(SimBench): class TestBench(SimBench):
def __init__(self, **kwargs): def __init__(self, **kwargs):
@ -23,22 +22,21 @@ class CordicCase(SimCase, unittest.TestCase):
zm = self.tb.dut.zmax zm = self.tb.dut.zmax
pipe = {} pipe = {}
genn = [gen() for i in range(n)] genn = [gen() for i in range(n)]
def cb(tb, s): def cb(tb, tbp):
if s.rd(tb.dut.new_in): if tbp.dut.new_in:
if genn: if genn:
xi, yi, zi = genn.pop(0) xi, yi, zi = genn.pop(0)
else: else:
s.interrupt = True raise StopSimulation
return
xi = floor(xi*c/g) xi = floor(xi*c/g)
yi = floor(yi*c/g) yi = floor(yi*c/g)
zi = floor(zi*c/zm) zi = floor(zi*c/zm)
s.wr(tb.dut.xi, xi) tbp.dut.xi = xi
s.wr(tb.dut.yi, yi) tbp.dut.yi = yi
s.wr(tb.dut.zi, zi) tbp.dut.zi = zi
pipe[s.cycle_counter] = xi, yi, zi pipe[tbp.simulator.cycle_counter] = xi, yi, zi
if s.rd(tb.dut.new_out): if tbp.dut.new_out:
t = s.cycle_counter - tb.dut.latency - 1 t = tbp.simulator.cycle_counter - tb.dut.latency - 1
if t < 1: if t < 1:
return return
xi, yi, zi = pipe.pop(t) xi, yi, zi = pipe.pop(t)

View file

@ -1,7 +1,7 @@
import unittest import unittest
from migen.fhdl.std import * from migen.fhdl.std import *
from migen.genlib.fifo import SyncFIFO, AsyncFIFO from migen.genlib.fifo import SyncFIFO
from migen.test.support import SimCase, SimBench from migen.test.support import SimCase, SimBench
@ -23,13 +23,13 @@ class SyncFIFOCase(SimCase, unittest.TestCase):
def test_run_sequence(self): def test_run_sequence(self):
seq = list(range(20)) seq = list(range(20))
def cb(tb, s): def cb(tb, tbp):
# fire re and we at "random" # fire re and we at "random"
s.wr(tb.dut.we, s.cycle_counter % 2 == 0) tbp.dut.we = tbp.simulator.cycle_counter % 2 == 0
s.wr(tb.dut.re, s.cycle_counter % 3 == 0) tbp.dut.re = tbp.simulator.cycle_counter % 3 == 0
# the output if valid must be correct # the output if valid must be correct
if s.rd(tb.dut.readable) and s.rd(tb.dut.re): if tbp.dut.readable and tbp.dut.re:
i = seq.pop(0) i = seq.pop(0)
self.assertEqual(s.rd(tb.dut.dout.a), i) self.assertEqual(tbp.dut.dout.a, i)
self.assertEqual(s.rd(tb.dut.dout.b), i*2) self.assertEqual(tbp.dut.dout.b, i*2)
self.run_with(cb, 20) self.run_with(cb, 20)

View file

@ -9,13 +9,13 @@ class SignedCase(SimCase, unittest.TestCase):
self.a = Signal((3, True)) self.a = Signal((3, True))
self.b = Signal((4, True)) self.b = Signal((4, True))
comps = [ comps = [
lambda p, q: p > q, lambda p, q: p > q,
lambda p, q: p >= q, lambda p, q: p >= q,
lambda p, q: p < q, lambda p, q: p < q,
lambda p, q: p <= q, lambda p, q: p <= q,
lambda p, q: p == q, lambda p, q: p == q,
lambda p, q: p != q, lambda p, q: p != q,
] ]
self.vals = [] self.vals = []
for asign in 1, -1: for asign in 1, -1:
for bsign in 1, -1: for bsign in 1, -1:
@ -29,16 +29,16 @@ class SignedCase(SimCase, unittest.TestCase):
values = range(-4, 4) values = range(-4, 4)
agen = iter(values) agen = iter(values)
bgen = iter(values) bgen = iter(values)
def cb(tb, s): def cb(tb, tbp):
try: try:
s.wr(self.tb.a, next(agen)) tbp.a = next(agen)
s.wr(self.tb.b, next(bgen)) tbp.b = next(bgen)
except StopIteration: except StopIteration:
s.interrupt = True raise StopSimulation
a = s.rd(self.tb.a) a = tbp.a
b = s.rd(self.tb.b) b = tbp.b
for asign, bsign, f, r, op in self.tb.vals: for asign, bsign, f, r, op in self.tb.vals:
r, r0 = s.rd(r), f(asign*a, bsign*b) r, r0 = tbp.simulator.rd(r), f(asign*a, bsign*b)
self.assertEqual(r, int(r0), self.assertEqual(r, int(r0),
"got {}, want {}*{} {} {}*{} = {}".format( "got {}, want {}*{} {} {}*{} = {}".format(
r, asign, a, op, bsign, b, r0)) r, asign, a, op, bsign, b, r0))

View file

@ -19,10 +19,8 @@ class BitonicCase(SimCase, unittest.TestCase):
self.assertEqual(flen(self.tb.dut.o[i]), 4) self.assertEqual(flen(self.tb.dut.o[i]), 4)
def test_sort(self): def test_sort(self):
def cb(tb, s): def cb(tb, tbp):
for i in tb.dut.i: for i in tb.dut.i:
s.wr(i, randrange(1<<flen(i))) tbp.simulator.wr(i, randrange(1<<flen(i)))
i = [s.rd(i) for i in tb.dut.i] self.assertEqual(sorted(list(tbp.dut.i)), list(tbp.dut.o))
o = [s.rd(o) for o in tb.dut.o]
self.assertEqual(sorted(i), o)
self.run_with(cb, 20) self.run_with(cb, 20)