Give human-readable names to slots, run functions and filenames
authorMikolaj Wielgus <wielgusmikolaj@gmail.com>
Sun, 26 Dec 2021 03:29:58 +0000 (03:29 +0000)
committerMikolaj Wielgus <wielgusmikolaj@gmail.com>
Sun, 26 Dec 2021 03:29:58 +0000 (03:29 +0000)
src/openpower/decoder/test/_pyrtl.py
src/openpower/decoder/test/pysim.py

index 47bf570eea017b6cc0858aefea1aedb95bfa9a49..a9e7749ce67071e5a84a087913c5e0aebca07908 100644 (file)
@@ -9,7 +9,7 @@ __all__ = ["PyRTLProcess"]
 
 
 class PyRTLProcess(BaseProcess):
-    __slots__ = ("is_comb", "runnable", "passive", "name", "filename", "crtl", "run")
+    __slots__ = ("is_comb", "runnable", "passive", "name", "crtl", "run")
 
     def __init__(self, *, is_comb):
         self.is_comb  = is_comb
@@ -121,10 +121,11 @@ class _RHSValueCompiler(_ValueCompiler):
         if self.inputs is not None:
             self.inputs.add(value)
 
+        macro = self.state.get_signal_macro(value)
         if self.mode == "curr":
-            return f"slots[{self.state.get_signal(value)}].{self.mode}"
+            return f"slots[{macro}].{self.mode}"
         else:
-            return f"next_{self.state.get_signal(value)}"
+            return f"next_{macro}"
 
     def on_Operator(self, value):
         def mask(value):
@@ -275,19 +276,13 @@ class _LHSValueCompiler(_ValueCompiler):
 
         def gen(arg):
             value_mask = (1 << len(value)) - 1
-            name = ''
-            # TODO: useful trick, actually put the name into the c code
-            # but this has to be done consistently right across the board.
-            # all occurrences of next_{....} have to use the same trick
-            # but at least then the names in the auto-generated c-code
-            # are readable...
-            #if hasattr(value, "name") and value.name is not None:
-            #    name = value.name
             if value.shape().signed:
                 value_sign = f"sign({value_mask} & {arg}, {-1 << (len(value) - 1)})"
             else: # unsigned
                 value_sign = f"{value_mask} & {arg}"
-            self.emitter.append(f"next_{name}{self.state.get_signal(value)} = {value_sign};")
+            
+            macro = self.state.get_signal_macro(value)
+            self.emitter.append(f"next_{macro} = {value_sign};")
         return gen
 
     def on_Operator(self, value):
@@ -397,14 +392,15 @@ class _StatementCompiler(StatementVisitor, _Compiler):
 
     @classmethod
     def compile(cls, state, stmt):
-        output_indexes = [state.get_signal(signal) for signal in stmt._lhs_signals()]
+        output_macros = \
+            [state.get_signal_macro(signal) for signal in stmt._lhs_signals()]
         emitter = _PythonEmitter()
-        for signal_index in output_indexes:
-            emitter.append(f"uint64_t next_{signal_index} = slots[{signal_index}].next")
+        for macro in output_macros:
+            emitter.append(f"uint64_t next_{macro} = slots[{macro}].next")
         compiler = cls(state, emitter)
         compiler(stmt)
-        for signal_index in output_indexes:
-            emitter.append(f"slots[{signal_index}].set(next_{signal_index})")
+        for macro in output_macros:
+            emitter.append(f"set({macro}, next_{macro})")
         return emitter.flush()
 
 
@@ -412,22 +408,24 @@ class _FragmentCompiler:
     def __init__(self, state):
         self.state = state
 
-    def __call__(self, fragment):
+    def __call__(self, fragment, fragment_name):
         processes = set()
 
         for index, (domain_name, domain_signals) in enumerate(fragment.drivers.items()):
             domain_stmts = LHSGroupFilter(domain_signals)(fragment.statements)
             domain_process = PyRTLProcess(is_comb=domain_name is None)
-
-            domain_process.name = f"{id(fragment)}_{domain_name or ''}_{index}"
+            domain_process.name = \
+                f"{fragment_name}__{domain_name or ''}" \
+                f"_{id(fragment)}_{index}"
 
             emitter = _PythonEmitter()
             emitter.append(f"void run_{domain_process.name}(void)")
             with emitter.nest():
                 if domain_name is None:
                     for signal in domain_signals:
-                        signal_index = self.state.get_signal(signal)
-                        emitter.append(f"uint64_t next_{signal_index} = {signal.reset};")
+                        macro = self.state.get_signal_macro(signal)
+                        emitter.append(
+                            f"uint64_t next_{macro} = {signal.reset};")
 
                     inputs = SignalSet()
                     _StatementCompiler(self.state, emitter, inputs=inputs)(domain_stmts)
@@ -444,14 +442,15 @@ class _FragmentCompiler:
                         self.state.add_trigger(domain_process, domain.rst, trigger=rst_trigger)
 
                     for signal in domain_signals:
-                        signal_index = self.state.get_signal(signal)
-                        emitter.append(f"uint64_t next_{signal_index} = slots[{signal_index}].next;")
+                        macro = self.state.get_signal_macro(signal)
+                        emitter.append(
+                            f"uint64_t next_{macro} = slots[{macro}].next;")
 
                     _StatementCompiler(self.state, emitter)(domain_stmts)
 
                 for signal in domain_signals:
-                    signal_index = self.state.get_signal(signal)
-                    emitter.append(f"set({signal_index}, next_{signal_index});")
+                    macro = self.state.get_signal_macro(signal)
+                    emitter.append(f"set({macro}, next_{macro});")
 
             code = "#include <stdint.h>\n"
             code += "#include \"common.h\"\n"
@@ -466,6 +465,6 @@ class _FragmentCompiler:
         for subfragment_index, (subfragment, subfragment_name) in enumerate(fragment.subfragments):
             if subfragment_name is None:
                 subfragment_name = "U${}".format(subfragment_index)
-            processes.update(self(subfragment))
+            processes.update(self(subfragment, subfragment_name))
 
         return processes
index 12afe7e85f6058a0506b4ce5f179b1734882ced6..0edf785e48b69234f5c4012edf05bbeac5d6ae3d 100644 (file)
@@ -11,9 +11,11 @@ from nmigen.sim._pycoro import PyCoroProcess
 from nmigen.sim._pyclock import PyClockProcess
 
 import os
+import re
 import sys
 import shutil
 import importlib
+
 from cffi import FFI
 from os.path import dirname, join
 from collections import namedtuple
@@ -264,6 +266,15 @@ class _PySimulation:
             self.slots.append(_PySignalState(signal, index, self))
             self.signals[signal] = index
             return index
+    
+    def get_signal_macro(self, signal):
+        index = self.get_signal(signal)
+
+        # Replace dots with double underscores, and change everything else that
+        # cannot be put in a C macro identifier to a single underscore.
+        sanitized_name = re.sub(r"\W|^(?=\d)", "_", signal.name)
+
+        return f"{sanitized_name}_{index}"
 
     def add_trigger(self, process, signal, *, trigger=None):
         index = self.get_signal(signal)
@@ -297,7 +308,7 @@ class _PySimulation:
 
 
 class PySimEngine(BaseEngine):
-    _crtl_counter = 1
+    _crtl_counter = 0
 
     def __init__(self, fragment):
         self._state = _PySimulation()
@@ -307,7 +318,7 @@ class PySimEngine(BaseEngine):
 
         # blow away and recreate crtl subdirectory.  (hope like hell
         # nobody is using this in their current working directory)
-        if PySimEngine._crtl_counter == 1:
+        if PySimEngine._crtl_counter == 0:
             shutil.rmtree("crtl", True)
         try:
             os.mkdir("crtl")
@@ -316,7 +327,7 @@ class PySimEngine(BaseEngine):
 
         # "Processes" are the compiled modules.  Each module ends up
         # with its own run() function
-        self._processes = _FragmentCompiler(self._state)(self._fragment)
+        self._processes = _FragmentCompiler(self._state)(self._fragment, "TOP")
 
         # get absolute path of this directory as the base
         filedir = os.path.dirname(os.path.abspath(__file__))
@@ -328,6 +339,16 @@ class PySimEngine(BaseEngine):
 
         # fill in the template
         cdef = template % (len(self._state.slots), len(self._state.slots))
+
+        # macros to make signals readable
+        cdef += "\n"
+        for signal in self._state.signals:
+            macro = self._state.get_signal_macro(signal)
+            index = self._state.get_signal(signal)
+            cdef += f"#define {macro} {index}\n"
+
+        # run() functions of processes
+        cdef += "\n"
         for process in self._processes:
             cdef += f"void run_{process.name}(void);\n"