Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: m-labs/migen
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 2ac748aef285
Choose a base ref
...
head repository: m-labs/migen
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: a67b4baa0c7e
Choose a head ref
  • 3 commits
  • 12 files changed
  • 1 contributor

Commits on Sep 21, 2015

  1. doc: minor edits

    sbourdeauducq committed Sep 21, 2015
    Copy the full SHA
    b8647a1 View commit details
  2. Copy the full SHA
    34ce6b0 View commit details
  3. sim: VCD output support

    sbourdeauducq committed Sep 21, 2015
    Copy the full SHA
    a67b4ba View commit details
10 changes: 8 additions & 2 deletions doc/introduction.rst
Original file line number Diff line number Diff line change
@@ -38,17 +38,23 @@ Even though the Milkymist system-on-chip [mm]_ had many successes, it suffers fr
#. Building a memory infrastructure (including bus interconnect, bridges and caches) that can automatically adapt itself at compile-time to any word size of the SDRAM is clumsy and tedious.
#. Building register banks for control, status and interrupt management of cores can also largely benefit from automation.
#. Many hardware acceleration problems can fit into the dataflow programming model. Manual dataflow implementation in V*HDL has, again, a lot of redundancy and potential for human errors. See the Milkymist texture mapping unit [mthesis]_ [mxcell]_ for an example of this. The amount of detail to deal with manually also makes the design space exploration difficult, and therefore hinders the design of efficient architectures.
#. Pre-computation of values, such as filter coefficients for DSP or even simply trigonometric tables, must often be done using external tools whose results are copy-and-pasted (in the best cases, automatically) into the V*HDL source.
#. Pre-computation of values, such as filter coefficients for DSP or even simply trigonometric tables, must often be done using external tools whose results are copy-and-pasted (in the best case, automatically) into the V*HDL source.

.. [mthesis] http://m-labs.hk/thesis/thesis.pdf
.. [mxcell] http://www.xilinx.com/publications/archives/xcell/Xcell77.pdf p30-35
Enter Migen, a Python toolbox for building complex digital hardware. We could have designed a brand new programming language, but that would have been reinventing the wheel instead of being able to benefit from Python's rich features and immense library. The price to pay is a slightly cluttered syntax at times when writing descriptions in FHDL, but we believe this is totally acceptable, particularly when compared to VHDL ;-)

Migen is made up of several related components, which are described in this manual.
Migen is made up of several related components:

#. the base language, FHDL
#. a library of small generic cores
#. a simulator
#. a build system

Installing Migen
****************

Either run the ``setup.py`` installation script or simply set ``PYTHONPATH`` to the root of the source directory.

If you wish to contribute patches, the suggest way to install is;
2 changes: 1 addition & 1 deletion doc/simulation.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Simulating a Migen design
#########################

Migen allows you to easily simulate your FHDL design and interface it with arbitrary Python code.
Migen allows you to easily simulate your FHDL design and interface it with arbitrary Python code. The simulator is written in pure Python and interprets the FHDL structure directly without using an external Verilog simulator.

[To be rewritten]
2 changes: 1 addition & 1 deletion examples/basic/graycounter.py
Original file line number Diff line number Diff line change
@@ -15,4 +15,4 @@ def tb(dut):

if __name__ == "__main__":
dut = GrayCounter(3)
Simulator(dut, tb(dut)).run()
run_simulation(dut, tb(dut), vcd_name="graycounter.vcd")
2 changes: 1 addition & 1 deletion examples/sim/basic1.py
Original file line number Diff line number Diff line change
@@ -26,4 +26,4 @@ def counter_test(dut):

if __name__ == "__main__":
dut = Counter()
Simulator(dut, counter_test(dut)).run()
run_simulation(dut, counter_test(dut), vcd_name="basic1.vcd")
2 changes: 1 addition & 1 deletion examples/sim/basic2.py
Original file line number Diff line number Diff line change
@@ -34,4 +34,4 @@ def counter_test(dut):

if __name__ == "__main__":
dut = Counter()
Simulator(dut, counter_test(dut)).run()
run_simulation(dut, counter_test(dut), vcd_name="basic2.vcd")
2 changes: 1 addition & 1 deletion examples/sim/fir.py
Original file line number Diff line number Diff line change
@@ -55,7 +55,7 @@ def fir_tb(dut, frequency, inputs, outputs):
for frequency in [0.05, 0.1, 0.25]:
dut = FIR(coef)
tb = fir_tb(dut, frequency, in_signals, out_signals)
Simulator(dut, tb).run()
run_simulation(dut, tb)

# Plot data from the input and output waveforms.
plt.plot(in_signals)
2 changes: 1 addition & 1 deletion examples/sim/memory.py
Original file line number Diff line number Diff line change
@@ -23,4 +23,4 @@ def memory_test(dut):

if __name__ == "__main__":
dut = Mem()
Simulator(dut, memory_test(dut)).run()
run_simulation(dut, memory_test(dut))
2 changes: 1 addition & 1 deletion migen/fhdl/verilog.py
Original file line number Diff line number Diff line change
@@ -5,7 +5,7 @@
from migen.fhdl.structure import _Operator, _Slice, _Assign, _Fragment
from migen.fhdl.tools import *
from migen.fhdl.bitcontainer import bits_for, flen
from migen.fhdl.namer import Namespace, build_namespace
from migen.fhdl.namer import build_namespace
from migen.fhdl.conv_output import ConvOutput


1 change: 1 addition & 0 deletions migen/sim/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from migen.sim.core import Simulator, run_simulation
40 changes: 32 additions & 8 deletions migen/sim.py → migen/sim/core.py
Original file line number Diff line number Diff line change
@@ -5,12 +5,10 @@
_Operator, _Slice, _ArrayProxy,
_Assign, _Fragment)
from migen.fhdl.bitcontainer import flen
from migen.fhdl.tools import list_targets
from migen.fhdl.tools import list_signals, list_targets
from migen.fhdl.simplify import MemoryToArray
from migen.fhdl.specials import _MemoryLocation


__all__ = ["Simulator"]
from migen.sim.vcd import VCDWriter, DummyVCDWriter


class ClockState:
@@ -37,7 +35,7 @@ def tick(self):
cs.times_before_tick -= dt
if not cs.times_before_tick:
cs.times_before_tick += cs.period
return r
return dt, r


str2op = {
@@ -175,9 +173,8 @@ def execute(self, statements):


# TODO: instances via Iverilog/VPI
# TODO: VCD output
class Simulator:
def __init__(self, fragment_or_module, generators, clocks={"sys": 100}):
def __init__(self, fragment_or_module, generators, clocks={"sys": 10}, vcd_name=None):
if isinstance(fragment_or_module, _Fragment):
self.fragment = fragment_or_module
else:
@@ -198,15 +195,36 @@ def __init__(self, fragment_or_module, generators, clocks={"sys": 100}):
self.fragment.comb[0:0] = [s.eq(s.reset)
for s in list_targets(self.fragment.comb)]

if vcd_name is None:
self.vcd = DummyVCDWriter()
else:
signals = sorted(list_signals(self.fragment),
key=lambda x: x.duid)
self.vcd = VCDWriter(vcd_name, signals)

self.time = TimeManager(clocks)
self.evaluator = Evaluator(mta.replacements)

def __enter__(self):
return self

def __exit__(self, type, value, traceback):
self.close()

def close(self):
self.vcd.close()

def _commit_and_comb_propagate(self):
# TODO: optimize
all_modified = set()
modified = self.evaluator.commit()
all_modified |= modified
while modified:
self.evaluator.execute(self.fragment.comb)
modified = self.evaluator.commit()
all_modified |= modified
for signal in all_modified:
self.vcd.set(signal, self.evaluator.signal_values[signal])

def _evalexec_nested_lists(self, x):
if isinstance(x, list):
@@ -245,7 +263,8 @@ def run(self):
self._commit_and_comb_propagate()

while True:
cds = self.time.tick()
dt, cds = self.time.tick()
self.vcd.delay(dt)
for cd in cds:
if cd in self.fragment.sync:
self.evaluator.execute(self.fragment.sync[cd])
@@ -255,3 +274,8 @@ def run(self):

if not self._continue_simulation():
break


def run_simulation(*args, **kwargs):
with Simulator(*args, **kwargs) as s:
s.run()
76 changes: 76 additions & 0 deletions migen/sim/vcd.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
from itertools import count

from migen.fhdl.bitcontainer import flen
from migen.fhdl.namer import build_namespace


def vcd_codes():
codechars = [chr(i) for i in range(33, 127)]
for n in count():
q, r = divmod(n, len(codechars))
code = codechars[r]
while q > 0:
q, r = divmod(q, len(codechars))
code = codechars[r] + code
yield code


class VCDWriter:
def __init__(self, filename, signals):
self.fo = open(filename, "w")
self.codes = dict()
self.signal_values = dict()
self.t = 0

try:
ns = build_namespace(signals)
codes = vcd_codes()
for signal in signals:
name = ns.get_name(signal)
code = next(codes)
self.codes[signal] = code
self.fo.write("$var wire {len} {code} {name} $end\n"
.format(name=name, code=code, len=flen(signal)))
self.fo.write("$dumpvars\n")
for signal in signals:
value = signal.reset.value
self._write_value(signal, value)
self.signal_values[signal] = value
self.fo.write("$end\n")
self.fo.write("#0\n")
except:
self.close()
raise

def _write_value(self, signal, value):
l = flen(signal)
if value < 0:
value += 2**l
if l > 1:
fmtstr = "b{:0" + str(l) + "b} {}\n"
else:
fmtstr = "{}{}\n"
self.fo.write(fmtstr.format(value, self.codes[signal]))

def set(self, signal, value):
if self.signal_values[signal] != value:
self._write_value(signal, value)
self.signal_values[signal] = value

def delay(self, delay):
self.t += delay
self.fo.write("#{}\n".format(self.t))

def close(self):
self.fo.close()


class DummyVCDWriter:
def set(self, signal, value):
pass

def delay(self, delay):
pass

def close(self):
pass
2 changes: 1 addition & 1 deletion migen/test/support.py
Original file line number Diff line number Diff line change
@@ -10,4 +10,4 @@ def test_to_verilog(self):
verilog.convert(self.tb)

def run_with(self, generator):
Simulator(self.tb, generator).run()
run_simulation(self.tb, generator)