class PyRTLProcess(BaseProcess):
- __slots__ = ("is_comb", "runnable", "passive", "run")
+ __slots__ = ("is_comb", "runnable", "passive", "crtl")
def __init__(self, *, is_comb):
self.is_comb = is_comb
emitter.append(f"slots[{signal_index}].set(next_{signal_index})")
return emitter.flush()
-# TODO: for use in the linux kernel stdint.h will not be available. ok for now
-code_hdr = """\
+code_includes = """\
#include <stdint.h>
-typedef struct slot_t
+"""
+
+code_cdef = """\
+typedef struct signal_t
{
uint64_t curr;
uint64_t next;
-} slot_t;
-slot_t slots[%d] =
+} signal_t;
+
+uint64_t capture(uint64_t id);
+uint64_t get_curr(uint64_t id);
+uint64_t get_next(uint64_t id);
+void run(void);
+"""
+
+code_header = code_includes
+code_header += "\n"
+code_header += code_cdef
+code_header += """
+signal_t slots[%d] =
{
"""
-code_ftr = """\
+code_footer = """\
};
-static void set(slot_t *slot, uint64_t value)
+uint64_t capture(uint64_t id)
+{
+ if (slots[id].curr == slots[id].next)
+ return 0;
+
+ slots[id].curr = slots[id].next;
+
+ return 1;
+}
+
+uint64_t get_curr(uint64_t id)
+{
+ return slots[id].curr;
+}
+
+uint64_t get_next(uint64_t id)
+{
+ return slots[id].next;
+}
+
+static void set(signal_t *slot, uint64_t value)
{
- if (slot->next == value)
- return;
slot->next = value;
}
"""
emitter.append(f"set(&slots[{signal_index}], next_{signal_index});")
# create code header, slots, footer, followed by emit actual code
- code = code_hdr % len(self.state.slots)
+ code = code_header % len(self.state.slots)
for slot in self.state.slots:
- code += " {%s, %s},\n" % (str(slot.curr), str(slot.next))
- code += code_ftr
+ code += " {%s, %s},\n" % (str(slot.signal.reset), str(slot.signal.reset))
+ code += code_footer
code += emitter.flush()
try:
file.write(code)
file.close()
- cdef = "void run(void);"
-
ffibuilder = FFI()
- ffibuilder.cdef(cdef)
+ ffibuilder.cdef(code_cdef)
ffibuilder.set_source(f"crtl._{basename}",
- cdef,
+ code_cdef,
sources=[f"crtl/{basename}.c"],
include_dirs=["/usr/include/python3.7m"])
ffibuilder.compile(verbose=True)
- domain_process.run = importlib.import_module(f"crtl._{basename}").lib.run
+ #domain_process.run = importlib.import_module(f"crtl._{basename}").lib.run
+ domain_process.crtl = importlib.import_module(f"crtl._{basename}").lib
processes.add(domain_process)
for subfragment_index, (subfragment, subfragment_name) in enumerate(fragment.subfragments):
return True
-class _PySignalState(BaseSignalState):
- __slots__ = ("signal", "curr", "next", "waiters", "pending")
+class _PySignalState:
+ __slots__ = ("signal", "waiters", "pending", "_crtl", "_id", "_curr", "_next")
- def __init__(self, signal, pending):
+ def __init__(self, signal, pending, id, crtl):
self.signal = signal
self.pending = pending
self.waiters = dict()
- self.curr = self.next = signal.reset
+ self._id = id
+ self._crtl = crtl
+
+ if self._crtl is None:
+ self._curr = self._next = signal.reset
def set(self, value):
- if self.next == value:
+ if self._crtl is not None:
+ # Shouldn't be called from Python if the signal is implemented through CRTL.
+ raise NotImplementedError
+
+ if self._next == value:
return
- self.next = value
+
+ self._next = value
self.pending.add(self)
def commit(self):
- if self.curr == self.next:
- return False
- self.curr = self.next
+ if self._crtl is not None:
+ if self._crtl.capture(self._id) == 0:
+ return False
+ else:
+ if self._curr == self._next:
+ return False
+ self._curr = self._next
awoken_any = False
for process, trigger in self.waiters.items():
if trigger is None or trigger == self.curr:
process.runnable = awoken_any = True
return awoken_any
+
+ @property
+ def curr(self):
+ if self._crtl is not None:
+ return self._crtl.get_curr(self._id)
+
+ return self._curr
+
+ @property
+ def next(self):
+ if self._crtl is not None:
+ return self._crtl.get_next(self._id)
+ return self._next
-class _PySimulation(BaseSimulation):
+
+class _PySimulation:
def __init__(self):
self.timeline = _Timeline()
self.signals = SignalDict()
self.slots = []
self.pending = set()
+ self.crtl = None
def reset(self):
self.timeline.reset()
try:
return self.signals[signal]
except KeyError:
- index = len(self.slots)
- self.slots.append(_PySignalState(signal, self.pending))
- self.signals[signal] = index
- return index
+ id = len(self.slots)
+ self.slots.append(_PySignalState(signal, self.pending, id, self.crtl))
+ self.signals[signal] = id
+ return id
def add_trigger(self, process, signal, *, trigger=None):
index = self.get_signal(signal)
for process in self._processes:
if process.runnable:
process.runnable = False
- process.run()
+
+ if hasattr(process, "crtl"):
+ process.crtl.run()
+ else:
+ process.run()
# 2. commit: apply every queued signal change, waking up any waiting processes
converged = self._state.commit(changed)