Skip to content

Commit

Permalink
Merge remote-tracking branch 'wq/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
sbourdeauducq committed Mar 14, 2020
2 parents 57d95b7 + 12c7902 commit b2d924e
Show file tree
Hide file tree
Showing 32 changed files with 607 additions and 344 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ language: python
python:
- "3.6"
- "3.7"
- "3.8"
- "pypy3"
cache:
directories:
Expand All @@ -15,7 +16,7 @@ addons:
before_install:
- export PATH="/usr/lib/ccache:$HOME/.local/bin:$PATH"
install:
- pip install coverage codecov pyvcd bitarray Jinja2
- pip install coverage codecov pyvcd Jinja2
- git clone https://github.com/YosysHQ/yosys
- (cd yosys && if ! yosys -V || [ $(git rev-parse HEAD $(yosys -V | awk 'match($0,/sha1 ([0-9a-f]+)/,m) { print m[1] }') | uniq | wc -l) != 1 ]; then make CONFIG=gcc ENABLE_ABC=0 PREFIX=$HOME/.local install; fi)
- (git clone https://github.com/YosysHQ/SymbiYosys && cd SymbiYosys && make PREFIX=$HOME/.local install)
Expand Down
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,6 @@ See the [doc/](doc/) folder for more technical information.

nMigen is based on [Migen][], a hardware description language developed by [M-Labs][]. Although Migen works very well in production, its design could be improved in many fundamental ways, and nMigen reimplements Migen concepts from scratch to do so. nMigen also provides an extensive [compatibility layer](#migration-from-migen) that makes it possible to build and simulate most Migen designs unmodified, as well as integrate modules written for Migen and nMigen.

nMigen is designed for Python 3.6 and newer. nMigen's Verilog backend requires [Yosys][] 0.9 or a newer version.

The development of nMigen has been supported by [M-Labs][] and [LambdaConcept][].

[migen]: https://m-labs.hk/migen
Expand All @@ -29,7 +27,7 @@ nMigen is *not* a "Python-to-FPGA" conventional high level synthesis (HLS) tool.

### Installation

nMigen requires [Yosys][] 0.9 or newer, as well as a device-specific toolchain.
nMigen requires Python 3.6 (or newer), [Yosys][] 0.9 (or newer), as well as a device-specific toolchain.

pip install git+https://github.com/m-labs/nmigen.git
pip install git+https://github.com/m-labs/nmigen-boards.git
Expand Down Expand Up @@ -65,6 +63,10 @@ Note that nMigen will **not** produce the exact same RTL as Migen did. nMigen ha

Once your design passes verification with nMigen, you can migrate it to the nMigen syntax one module at a time. Migen modules can be added to nMigen modules and vice versa, so there is no restriction on the order of migration, either.

### Community

nMigen discussions take place on the M-Labs IRC channel, [#m-labs at freenode.net](https://webchat.freenode.net/?channels=m-labs). Feel free to join to ask questions about using nMigen or discuss ongoing development of nMigen and its related projects.

### License

nMigen is released under the very permissive two-clause BSD license. Under the terms of this license, you are authorized to use nMigen for closed-source proprietary designs.
Expand Down
Binary file removed doc/nmigen_logo.png
Binary file not shown.
224 changes: 0 additions & 224 deletions doc/nmigen_logo.svg

This file was deleted.

Binary file removed doc/nmigen_logo_white.png
Binary file not shown.
58 changes: 46 additions & 12 deletions nmigen/back/pysim.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import inspect
import os
import tempfile
import warnings
import inspect
from contextlib import contextmanager
import itertools
from vcd import VCDWriter
from vcd.gtkw import GTKWSave

Expand Down Expand Up @@ -85,7 +88,18 @@ def __init__(self, signal_names, *, vcd_file, gtkw_file=None, traces=()):
self.gtkw_file = gtkw_file
self.gtkw_save = gtkw_file and GTKWSave(self.gtkw_file)

for signal, names in signal_names.items():
self.traces = []

trace_names = SignalDict()
for trace in traces:
if trace not in signal_names:
trace_names[trace] = trace.name
self.traces.append(trace)

if self.vcd_writer is None:
return

for signal, names in itertools.chain(signal_names.items(), trace_names.items()):
if signal.decoder:
var_type = "string"
var_size = 1
Expand Down Expand Up @@ -130,21 +144,23 @@ def update(self, timestamp, signal, value):
self.vcd_writer.change(vcd_var, vcd_timestamp, var_value)

def close(self, timestamp):
self.vcd_writer.close(self.timestamp_to_vcd(timestamp))
if self.vcd_writer is not None:
self.vcd_writer.close(self.timestamp_to_vcd(timestamp))

if self.gtkw_save is not None:
self.gtkw_save.dumpfile(self.vcd_file.name)
self.gtkw_save.dumpfile_size(self.vcd_file.tell())

self.gtkw_save.treeopen("top")
for signal, hierarchy in self.gtkw_names.items():
for signal in self.traces:
if len(signal) > 1 and not signal.decoder:
suffix = "[{}:0]".format(len(signal) - 1)
else:
suffix = ""
self.gtkw_save.trace(".".join(hierarchy) + suffix)
self.gtkw_save.trace(".".join(self.gtkw_names[signal]) + suffix)

self.vcd_file.close()
if self.vcd_file is not None:
self.vcd_file.close()
if self.gtkw_file is not None:
self.gtkw_file.close()

Expand Down Expand Up @@ -417,6 +433,9 @@ def sign(value):
if value.operator == "r^":
# Believe it or not, this is the fastest way to compute a sideways XOR in Python.
return f"(format({mask(arg)}, 'b').count('1') % 2)"
if value.operator in ("u", "s"):
# These operators don't change the bit pattern, only its interpretation.
return self(arg)
elif len(value.operands) == 2:
lhs, rhs = value.operands
lhs_mask = (1 << len(lhs)) - 1
Expand Down Expand Up @@ -473,7 +492,9 @@ def on_Cat(self, value):
part_mask = (1 << len(part)) - 1
gen_parts.append(f"(({self(part)} & {part_mask}) << {offset})")
offset += len(part)
return f"({' | '.join(gen_parts)})"
if gen_parts:
return f"({' | '.join(gen_parts)})"
return f"0"

def on_Repl(self, value):
part_mask = (1 << len(value.value)) - 1
Expand All @@ -483,7 +504,9 @@ def on_Repl(self, value):
for _ in range(value.count):
gen_parts.append(f"({gen_part} << {offset})")
offset += len(value.value)
return f"({' | '.join(gen_parts)})"
if gen_parts:
return f"({' | '.join(gen_parts)})"
return f"0"

def on_ArrayProxy(self, value):
index_mask = (1 << len(value.index)) - 1
Expand Down Expand Up @@ -695,9 +718,6 @@ def add_signal_name(signal):
self.signal_names[signal].add(hierarchical_signal_name)

for domain_name, domain_signals in fragment.drivers.items():
for domain_signal in domain_signals:
add_signal_name(domain_signal)

domain_stmts = LHSGroupFilter(domain_signals)(fragment.statements)
domain_process = _CompiledProcess(self.state, comb=domain_name is None,
name=".".join((*hierarchy, "<{}>".format(domain_name or "comb"))))
Expand Down Expand Up @@ -747,12 +767,26 @@ def add_signal_name(signal):
signal_index = domain_process.context.get_signal(signal)
emitter.append(f"slots[{signal_index}].set(next_{signal_index})")

# There shouldn't be any exceptions raised by the generated code, but if there are
# (almost certainly due to a bug in the code generator), use this environment variable
# to make backtraces useful.
code = emitter.flush()
if os.getenv("NMIGEN_pysim_dump"):
file = tempfile.NamedTemporaryFile("w", prefix="nmigen_pysim_", delete=False)
file.write(code)
filename = file.name
else:
filename = "<string>"

exec_locals = {"slots": domain_process.context.slots, **_ValueCompiler.helpers}
exec(emitter.flush(), exec_locals)
exec(compile(code, filename, "exec"), exec_locals)
domain_process.run = exec_locals["run"]

processes.add(domain_process)

for used_signal in domain_process.context.indexes:
add_signal_name(used_signal)

for subfragment_index, (subfragment, subfragment_name) in enumerate(fragment.subfragments):
if subfragment_name is None:
subfragment_name = "U${}".format(subfragment_index)
Expand Down
Loading

0 comments on commit b2d924e

Please sign in to comment.