The main parameters of its constructor are the output VCD file (default: ``None``) and the levels of hierarchy that must be present in the VCD (default: 1).
-Basic simulation example
-========================
-::
-
- from migen.fhdl.structure import *
- from migen.sim.generic import Simulator
- from migen.sim.icarus import Runner
-
- class Counter:
- def __init__(self):
- self.count = Signal(BV(4))
-
- def do_simulation(self, s):
- print("Count: " + str(s.rd(self.count)))
-
- def get_fragment(self):
- sync = [self.count.eq(self.count + 1)]
- sim = [self.do_simulation]
- return Fragment(sync=sync, sim=sim)
-
- def main():
- dut = Counter()
- sim = Simulator(dut.get_fragment(), Runner())
- sim.run(20)
-
- main()
+Simulation examples
+*******************
+
+Most basic
+==========
+.. include:: ../examples/basic_sim.py
+ :code: python
+
+A few more features
+===================
+.. include:: ../examples/basic2_sim.py
+ :code: python
+
+Memory access
+=============
+.. include:: ../examples/memory_sim.py
+ :code: python
+
+A FIR filter
+============
+.. include:: ../examples/fir.py
+ :code: python
+
+Wishbone
+========
+.. include:: ../examples/wb_initiator.py
+ :code: python
--- /dev/null
+from migen.fhdl.structure import *
+from migen.sim.generic import Simulator, TopLevel
+from migen.sim.icarus import Runner
+
+# A slightly improved counter.
+# Has a clock enable (CE) signal, counts on more bits
+# and resets with a negative number.
+class Counter:
+ def __init__(self):
+ self.ce = Signal()
+ # Demonstrate negative numbers and signals larger than 32 bits.
+ self.count = Signal(BV(37, True), reset=-5)
+
+ def do_simulation(self, s):
+ # Only assert CE every second cycle.
+ # => each counter value is held for two cycles.
+ if s.cycle_counter % 2:
+ s.wr(self.ce, 0) # This is how you write to a signal.
+ else:
+ s.wr(self.ce, 1)
+ print("Cycle: " + str(s.cycle_counter) + " Count: " + \
+ str(s.rd(self.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:
+ # Cycle: -1 Count: 0
+ # Cycle: 0 Count: -5
+ # Cycle: 1 Count: -5
+ # Cycle: 2 Count: -4
+ # Cycle: 3 Count: -4
+ # Cycle: 4 Count: -3
+ # ...
+
+ def get_fragment(self):
+ sync = [If(self.ce, self.count.eq(self.count + 1))]
+ sim = [self.do_simulation]
+ return Fragment(sync=sync, sim=sim)
+
+def main():
+ dut = Counter()
+ # Instantiating the generic top-level ourselves lets us
+ # specify a VCD output file.
+ sim = Simulator(dut.get_fragment(), Runner(), TopLevel("my.vcd"))
+ sim.run(20)
+
+main()
from migen.fhdl.structure import *
-from migen.sim.generic import Simulator, TopLevel
+from migen.sim.generic import Simulator
from migen.sim.icarus import Runner
+# Our simple counter, which increments at every cycle
+# and prints its current value in simulation.
class Counter:
def __init__(self):
- self.ce = Signal()
- self.count = Signal(BV(37, True), reset=-5)
+ self.count = Signal(BV(4))
+ # This function will be called at every cycle.
def do_simulation(self, s):
- if s.cycle_counter % 2:
- s.wr(self.ce, 0)
- else:
- s.wr(self.ce, 1)
- print("Cycle: " + str(s.cycle_counter) + " Count: " + str(s.rd(self.count)))
- do_simulation.initialize = True
+ # Simply read the count signal and print it.
+ # The output is:
+ # Count: 0
+ # Count: 1
+ # Count: 2
+ # ...
+ print("Count: " + str(s.rd(self.count)))
def get_fragment(self):
- sync = [If(self.ce, self.count.eq(self.count + 1))]
+ # At each cycle, increase the value of the count signal.
+ # We do it with convertible/synthesizable FHDL code.
+ sync = [self.count.eq(self.count + 1)]
+ # List our simulation function in the fragment.
sim = [self.do_simulation]
return Fragment(sync=sync, sim=sim)
def main():
dut = Counter()
- sim = Simulator(dut.get_fragment(), Runner(), TopLevel("my.vcd"))
+ # Use the Icarus Verilog runner.
+ # We do not specify a top-level object, and use the default.
+ sim = Simulator(dut.get_fragment(), Runner())
+ # Since we do not use sim.interrupt, limit the simulation
+ # to some number of cycles.
sim.run(20)
main()
-from scipy import signal
from math import cos, pi
+from scipy import signal
from migen.fhdl.structure import *
from migen.fhdl import verilog
from migen.sim.generic import Simulator
from migen.sim.icarus import Runner
+# A synthesizable FIR filter.
class FIR:
def __init__(self, coef, wsize=16):
self.coef = coef
comb = [self.o.eq(sum_full[self.wsize-1:])]
return Fragment(comb, sync)
+# A test bench for our FIR filter.
+# Generates a sine wave at the input and records the output.
class TB:
def __init__(self, fir, frequency):
self.fir = fir
return Fragment(sim=[self.do_simulation])
def main():
+ # Compute filter coefficients with SciPy.
coef = signal.remez(80, [0, 0.1, 0.1, 0.5], [1, 0])
fir = FIR(coef)
tb = TB(fir, 0.3)
+ # Combine the FIR filter with its test bench.
fragment = autofragment.from_local()
sim = Simulator(fragment, Runner())
sim.run(200)
+ # Print data from the input and output waveforms.
+ # When matplotlib works easily with Python 3, we could
+ # display them graphically here.
print(tb.inputs)
print(tb.outputs)
self.a = Signal(BV(12))
self.d = Signal(BV(16))
p = MemoryPort(self.a, self.d)
+ # Initialize the beginning of the memory with integers
+ # from 0 to 19.
self.mem = Memory(16, 2**12, p, init=list(range(20)))
def do_simulation(self, s):
+ # Read the memory. Use the cycle counter as address.
value = s.rd(self.mem, s.cycle_counter)
+ # Print the result. Output is:
+ # 0
+ # 1
+ # 2
+ # ...
print(value)
+ # Demonstrate how to interrupt the simulator.
if value == 10:
s.interrupt = True
def main():
dut = Mem()
sim = Simulator(dut.get_fragment(), Runner())
+ # No need for a cycle limit here, we use sim.interrupt instead.
sim.run()
main()
from migen.sim.generic import Simulator
from migen.sim.icarus import Runner
+# Our bus master.
+# Python generators let us program bus transactions in an elegant sequential style.
def my_generator():
prng = Random(92837)
+
+ # Write to the first addresses.
for x in range(10):
t = TWrite(x, 2*x)
yield t
print("Wrote in " + str(t.latency) + " cycle(s)")
+ # Insert some dead cycles to simulate bus inactivity.
for delay in range(prng.randrange(0, 3)):
yield None
+
+ # Read from the first addresses.
for x in range(10):
t = TRead(x)
yield t
for delay in range(prng.randrange(0, 3)):
yield None
+# Our bus slave.
+# All transactions complete with a random delay.
+# Reads return address + 4. Writes are simply acknowledged.
class MyPeripheral:
def __init__(self):
self.bus = wishbone.Interface()
self.prng = Random(763627)
def do_simulation(self, s):
- # Only authorize acks on certain cycles to simulate variable latency
+ # Only authorize acks on certain cycles to simulate variable latency.
s.wr(self.ack_en, self.prng.randrange(0, 2))
def get_fragment(self):
return Fragment(comb, sim=[self.do_simulation])
def main():
+ # The "wishbone.Initiator" library component runs our generator
+ # and manipulates the bus signals accordingly.
master = wishbone.Initiator(my_generator())
+ # Our slave.
slave = MyPeripheral()
+ # The "wishbone.Tap" library component examines the bus at the slave port
+ # and displays the transactions on the console (<TRead...>/<TWrite...>).
tap = wishbone.Tap(slave.bus)
+ # Connect the master to the slave.
intercon = wishbone.InterconnectPointToPoint(master.bus, slave.bus)
+ # A small extra simulation function to terminate the process when
+ # the initiator is done (i.e. our generator is exhausted).
def end_simulation(s):
s.interrupt = master.done
fragment = autofragment.from_local() + Fragment(sim=[end_simulation])
sim.run()
main()
+
+# Output:
+# <TWrite adr:0x0 dat:0x0>
+# Wrote in 0 cycle(s)
+# <TWrite adr:0x1 dat:0x2>
+# Wrote in 0 cycle(s)
+# <TWrite adr:0x2 dat:0x4>
+# Wrote in 0 cycle(s)
+# <TWrite adr:0x3 dat:0x6>
+# Wrote in 1 cycle(s)
+# <TWrite adr:0x4 dat:0x8>
+# Wrote in 1 cycle(s)
+# <TWrite adr:0x5 dat:0xa>
+# Wrote in 2 cycle(s)
+# ...
+# <TRead adr:0x0 dat:0x4>
+# Read 4 in 2 cycle(s)
+# <TRead adr:0x1 dat:0x5>
+# Read 5 in 2 cycle(s)
+# <TRead adr:0x2 dat:0x6>
+# Read 6 in 1 cycle(s)
+# <TRead adr:0x3 dat:0x7>
+# Read 7 in 1 cycle(s)
+# ...