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: amaranth-lang/amaranth
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: c08c30c90710
Choose a base ref
...
head repository: amaranth-lang/amaranth
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 9cbdff0a681a
Choose a head ref
  • 1 commit
  • 7 files changed
  • 1 contributor

Commits on Sep 2, 2020

  1. Copy the full SHA
    9cbdff0 View commit details
Showing with 417 additions and 55 deletions.
  1. +6 −4 nmigen/back/cxxrtl.py
  2. +175 −0 nmigen/sim/_cxxrtl.py
  3. +0 −2 nmigen/sim/_pyclock.py
  4. +49 −0 nmigen/sim/_sched.py
  5. +3 −0 nmigen/sim/core.py
  6. +182 −0 nmigen/sim/cxxsim.py
  7. +2 −49 nmigen/sim/pysim.py
10 changes: 6 additions & 4 deletions nmigen/back/cxxrtl.py
Original file line number Diff line number Diff line change
@@ -5,6 +5,10 @@
__all__ = ["YosysError", "convert", "convert_fragment"]


def _find_yosys():
return find_yosys(lambda ver: ver >= (0, 9, 3468))


def _convert_rtlil_text(rtlil_text, black_boxes, *, src_loc_at=0):
if black_boxes is not None:
if not isinstance(black_boxes, dict):
@@ -18,17 +22,15 @@ def _convert_rtlil_text(rtlil_text, black_boxes, *, src_loc_at=0):
raise TypeError("CXXRTL black box source code must be a string, not {!r}"
.format(box_source))

yosys = find_yosys(lambda ver: ver >= (0, 9, 3468))

script = []
if black_boxes is not None:
for box_name, box_source in black_boxes.items():
script.append("read_ilang <<rtlil\n{}\nrtlil".format(box_source))
script.append("read_ilang <<rtlil\n{}\nrtlil".format(rtlil_text))
script.append("delete w:$verilog_initial_trigger")
script.append("write_cxxrtl")
script.append("write_cxxrtl -Og")

return yosys.run(["-q", "-"], "\n".join(script), src_loc_at=1 + src_loc_at)
return _find_yosys().run(["-q", "-"], "\n".join(script), src_loc_at=1 + src_loc_at)


def convert_fragment(*args, black_boxes=None, **kwargs):
175 changes: 175 additions & 0 deletions nmigen/sim/_cxxrtl.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
from enum import IntEnum
from ctypes import (cdll, Structure, POINTER, CFUNCTYPE,
c_int, c_size_t, c_uint32, c_uint64, c_void_p, c_char_p,
byref, string_at)


__all__ = []


class _cxxrtl_toplevel(Structure):
pass


cxxrtl_toplevel = POINTER(_cxxrtl_toplevel)


class _cxxrtl_handle(Structure):
pass


cxxrtl_handle = POINTER(_cxxrtl_handle)


class cxxrtl_type(IntEnum):
VALUE = 0
WIRE = 1
MEMORY = 2
ALIAS = 3


class cxxrtl_object(Structure):
_fields_ = [
("_type", c_uint32),
("width", c_size_t),
("lsb_at", c_size_t),
("depth", c_size_t),
("zero_at", c_size_t),
("_curr", POINTER(c_uint32)),
("_next", POINTER(c_uint32)),
]

@property
def type(self):
return cxxrtl_type(self._type)

@property
def chunks(self):
return ((self.width + 31) // 32) * self.depth

@property
def curr(self):
value = 0
for chunk in range(self.chunks)[::-1]:
value <<= 32
value |= self._curr[chunk]
return value << self.lsb_at

@curr.setter
def curr(self, value):
value = (value >> self.lsb_at) & ((1 << self.width) - 1)
for chunk in range(self.chunks)[::-1]:
self._curr[chunk] = value & 0xffffffff
value >>= 32

@property
def next(self):
value = 0
for chunk in range(self.chunks)[::-1]:
value <<= 32
value |= self._next[chunk]
return value << self.lsb_at

@next.setter
def next(self, value):
value = (value >> self.lsb_at) & ((1 << self.width) - 1)
for chunk in range(self.chunks)[::-1]:
self._next[chunk] = value & 0xffffffff
value >>= 32


cxxrtl_object_p = POINTER(cxxrtl_object)
cxxrtl_enum_callback_fn = CFUNCTYPE(c_void_p, cxxrtl_object_p, c_size_t)


class _cxxrtl_vcd(Structure):
pass


cxxrtl_vcd = POINTER(_cxxrtl_vcd)
cxxrtl_vcd_filter_fn = CFUNCTYPE(c_void_p, c_char_p, cxxrtl_object_p)


class cxxrtl_library:
def __init__(self, filename, *, design_name="cxxrtl_design"):
self._library = library = cdll.LoadLibrary(filename)

self.design_create = getattr(library, f"{design_name}_create")
self.design_create.argtypes = []
self.design_create.restype = cxxrtl_toplevel

self.create = library.cxxrtl_create
self.create.argtypes = [cxxrtl_toplevel]
self.create.restype = cxxrtl_handle

self.destroy = library.cxxrtl_destroy
self.destroy.argtypes = [cxxrtl_handle]
self.destroy.restype = None

self.eval = library.cxxrtl_eval
self.eval.argtypes = [cxxrtl_handle]
self.eval.restype = c_int

self.commit = library.cxxrtl_commit
self.commit.argtypes = [cxxrtl_handle]
self.commit.restype = c_int

self.step = library.cxxrtl_step
self.step.argtypes = [cxxrtl_handle]
self.step.restype = None

_get_parts = library.cxxrtl_get_parts
_get_parts.argtypes = [cxxrtl_handle, c_char_p, POINTER(c_size_t)]
_get_parts.restype = cxxrtl_object_p
def get_parts(handle, name):
count = c_size_t()
parts = _get_parts(handle, name, byref(count))
if parts:
return [parts[n] for n in range(count.value)]
self.get_parts = get_parts

self.enum = library.cxxrtl_enum
self.enum.argtypes = [cxxrtl_handle, c_void_p, cxxrtl_enum_callback_fn]
self.enum.restype = None

self.vcd_create = library.cxxrtl_vcd_create
self.vcd_create.argtypes = []
self.vcd_create.restype = cxxrtl_vcd

self.vcd_destroy = library.cxxrtl_vcd_destroy
self.vcd_destroy.argtypes = [cxxrtl_vcd]
self.vcd_destroy.restype = None

self.vcd_timescale = library.cxxrtl_vcd_timescale
self.vcd_timescale.argtypes = [cxxrtl_vcd, c_int, c_char_p]
self.vcd_timescale.restype = None

self.vcd_add = library.cxxrtl_vcd_add
self.vcd_add.argtypes = [cxxrtl_vcd, c_char_p, cxxrtl_object_p]
self.vcd_add.restype = None

self.vcd_add_from = library.cxxrtl_vcd_add_from
self.vcd_add_from.argtypes = [cxxrtl_vcd, cxxrtl_handle]
self.vcd_add_from.restype = None

self.vcd_add_from_if = library.cxxrtl_vcd_add_from_if
self.vcd_add_from_if.argtypes = [cxxrtl_vcd, cxxrtl_handle, c_void_p, cxxrtl_vcd_filter_fn]
self.vcd_add_from_if.restype = None

self.vcd_add_from_without_memories = library.cxxrtl_vcd_add_from_without_memories
self.vcd_add_from_without_memories.argtypes = [cxxrtl_vcd, cxxrtl_handle]
self.vcd_add_from_without_memories.restype = None

self.vcd_sample = library.cxxrtl_vcd_sample
self.vcd_sample.argtypes = [cxxrtl_vcd, c_uint64]
self.vcd_sample.restype = None

_vcd_read = library.cxxrtl_vcd_read
_vcd_read.argtypes = [cxxrtl_vcd, POINTER(c_char_p), POINTER(c_size_t)]
_vcd_read.restype = None
def vcd_read(vcd):
data = c_char_p()
size = c_size_t()
_vcd_read(vcd, byref(data), byref(size))
return string_at(data.value, size.value)
self.vcd_read = vcd_read
2 changes: 0 additions & 2 deletions nmigen/sim/_pyclock.py
Original file line number Diff line number Diff line change
@@ -24,8 +24,6 @@ def reset(self):
self.initial = True

def run(self):
self.runnable = False

if self.initial:
self.initial = False
self.state.wait_interval(self, self.phase)
49 changes: 49 additions & 0 deletions nmigen/sim/_sched.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
__all__ = ["Timeline"]


class Timeline:
def __init__(self):
self.now = 0.0
self.deadlines = dict()

def reset(self):
self.now = 0.0
self.deadlines.clear()

def at(self, run_at, process):
assert process not in self.deadlines
self.deadlines[process] = run_at

def delay(self, delay_by, process):
if delay_by is None:
run_at = self.now
else:
run_at = self.now + delay_by
self.at(run_at, process)

def advance(self):
nearest_processes = set()
nearest_deadline = None
for process, deadline in self.deadlines.items():
if deadline is None:
if nearest_deadline is not None:
nearest_processes.clear()
nearest_processes.add(process)
nearest_deadline = self.now
break
elif nearest_deadline is None or deadline <= nearest_deadline:
assert deadline >= self.now
if nearest_deadline is not None and deadline < nearest_deadline:
nearest_processes.clear()
nearest_processes.add(process)
nearest_deadline = deadline

if not nearest_processes:
return False

for process in nearest_processes:
process.runnable = True
del self.deadlines[process]
self.now = nearest_deadline

return True
3 changes: 3 additions & 0 deletions nmigen/sim/core.py
Original file line number Diff line number Diff line change
@@ -58,6 +58,9 @@ def __init__(self, fragment, *, engine="pysim"):
elif engine == "pysim":
from .pysim import PySimEngine
engine = PySimEngine
elif engine == "cxxsim":
from .cxxsim import CxxSimEngine
engine = CxxSimEngine
else:
raise TypeError("Value '{!r}' is not a simulation engine class or "
"a simulation engine name"
Loading