nortl 1.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. nortl/__init__.py +85 -0
  2. nortl/components/__init__.py +8 -0
  3. nortl/components/channel.py +132 -0
  4. nortl/components/timer.py +73 -0
  5. nortl/core/__init__.py +40 -0
  6. nortl/core/checker.py +135 -0
  7. nortl/core/common/__init__.py +4 -0
  8. nortl/core/common/access.py +25 -0
  9. nortl/core/common/debug.py +6 -0
  10. nortl/core/common/naming_helper.py +33 -0
  11. nortl/core/constructs/__init__.py +13 -0
  12. nortl/core/constructs/condition.py +143 -0
  13. nortl/core/constructs/fork_join.py +84 -0
  14. nortl/core/constructs/loop.py +138 -0
  15. nortl/core/engine.py +575 -0
  16. nortl/core/exceptions.py +139 -0
  17. nortl/core/manager/__init__.py +6 -0
  18. nortl/core/manager/scratch_manager.py +128 -0
  19. nortl/core/manager/signal_manager.py +71 -0
  20. nortl/core/modifiers.py +136 -0
  21. nortl/core/module.py +181 -0
  22. nortl/core/operations.py +834 -0
  23. nortl/core/parameter.py +88 -0
  24. nortl/core/process.py +451 -0
  25. nortl/core/protocols.py +628 -0
  26. nortl/core/renderers/__init__.py +0 -0
  27. nortl/core/renderers/operations/__init__.py +34 -0
  28. nortl/core/renderers/operations/arithmetics.py +38 -0
  29. nortl/core/renderers/operations/base.py +111 -0
  30. nortl/core/renderers/operations/comparison.py +44 -0
  31. nortl/core/renderers/operations/logic.py +38 -0
  32. nortl/core/renderers/operations/misc.py +26 -0
  33. nortl/core/renderers/operations/slice.py +30 -0
  34. nortl/core/signal.py +878 -0
  35. nortl/core/state.py +201 -0
  36. nortl/py.typed +0 -0
  37. nortl/renderer/__init__.py +5 -0
  38. nortl/renderer/mermaid_renderer.py +38 -0
  39. nortl/renderer/networkx_renderer.py +29 -0
  40. nortl/renderer/verilog_renderer.py +325 -0
  41. nortl/renderer/verilog_utils/__init__.py +6 -0
  42. nortl/renderer/verilog_utils/formatter.py +29 -0
  43. nortl/renderer/verilog_utils/process.py +226 -0
  44. nortl/renderer/verilog_utils/structural.py +146 -0
  45. nortl/renderer/verilog_utils/utils.py +23 -0
  46. nortl/utils/__init__.py +0 -0
  47. nortl/utils/parse_utils.py +37 -0
  48. nortl/utils/templates/testbench.sv +41 -0
  49. nortl/utils/test_wrapper.py +218 -0
  50. nortl/utils/type_aliases.py +15 -0
  51. nortl/verilog_library/__init__.py +74 -0
  52. nortl/verilog_library/nortl_clock_gate.sv +20 -0
  53. nortl/verilog_library/nortl_count_down_timer.sv +50 -0
  54. nortl/verilog_library/nortl_delay.sv +66 -0
  55. nortl/verilog_library/nortl_edge_detector.sv +34 -0
  56. nortl/verilog_library/nortl_sync.sv +28 -0
  57. nortl-1.4.0.dist-info/METADATA +105 -0
  58. nortl-1.4.0.dist-info/RECORD +60 -0
  59. nortl-1.4.0.dist-info/WHEEL +4 -0
  60. nortl-1.4.0.dist-info/licenses/LICENSE +11 -0
@@ -0,0 +1,143 @@
1
+ from types import TracebackType
2
+
3
+ from nortl.core import Const
4
+ from nortl.core.protocols import EngineProto, Renderable
5
+ from nortl.core.state import State
6
+
7
+ __all__ = [
8
+ 'Condition',
9
+ 'ElseCondition',
10
+ ]
11
+
12
+
13
+ class Condition:
14
+ """Context manager to realize an if-then-else behavior within a noRTL engine."""
15
+
16
+ final_state_key: str = 'Condition.start_state'
17
+
18
+ def __init__(self, engine: EngineProto, condition: Renderable):
19
+ """Initializes the Condition context manager.
20
+
21
+ The state management is as follows:
22
+
23
+ * If we are realizing the first conditional in a state, we need to create a final-state where the engine should be after executing the conditional code.
24
+ * This final-state is stored in the metadata of the current state (and will be reused if another conditional is added)
25
+ * The final-state also has the start state in its meta-data -- if another condition is to be added,
26
+ it should start from the same initial state as the first conditional.
27
+ * After the conditional has been executed, the engine is placed in the final state
28
+ * If we get to realize the second conditional, we recognize that from the metadata of the current state
29
+ * The start and final state are adapted to resemble the behavior of the first conditional
30
+
31
+ The Context manager can be used as follows:
32
+ ```python
33
+ from nortl.core import CoreEngine
34
+ from nortl.utils.context_manager import Condition
35
+
36
+ f = CoreEngine('my_engine')
37
+ in_signal = f.define_input('IN')
38
+
39
+ # Example usage:
40
+ # <= We start at a start_state
41
+ with Condition(f, in_signal == 1):
42
+ f.sync()
43
+ f.do_something()
44
+ # At the end, the engine goes to an inferred final_state
45
+
46
+ with Condition(f, in_signal == 0):
47
+ #The context manager again starts from the same start_state as before
48
+ f.sync()
49
+ f.do_something_else()
50
+ # At the end, the engine goes to an inferred final_state
51
+
52
+ # We proceed execution from the final_state
53
+
54
+ # When no further conditions are expected, an f.sync() creates a new state and breaks the chain-of-conditionals.
55
+
56
+ ```
57
+
58
+ Arguments:
59
+ engine: The CoreEngine instance.
60
+ condition: A Renderable signal representing the condition to evaluate.
61
+ """
62
+ self.engine = engine
63
+ self.condition = condition
64
+
65
+ if self.engine.current_state.has_metadata(self.final_state_key):
66
+ self.start_state = self.engine.current_state.get_metadata(self.final_state_key)
67
+ self.final_state = self.engine.current_state
68
+ self.engine.current_state = self.start_state
69
+ else:
70
+ self.start_state = self.engine.current_state
71
+ self.final_state = engine.create_state()
72
+ self.final_state.set_metadata(self.final_state_key, self.start_state)
73
+
74
+ def __enter__(self) -> None:
75
+ """Executes the provided function if the condition is met."""
76
+ conditional_state = self.engine.create_state()
77
+ self.engine.jump_if(self.condition, conditional_state)
78
+ self.engine.current_state = conditional_state
79
+
80
+ # TODO consider moving this into the engine itself
81
+ self.engine.scratch_manager.enter_context()
82
+
83
+ def __exit__(
84
+ self,
85
+ exc_type: type[BaseException] | None,
86
+ exc_val: BaseException | None,
87
+ exc_tb: TracebackType | None,
88
+ ) -> None:
89
+ jumpconds = [t[0] for t in self.engine.current_state.transitions]
90
+ if Const(1) not in jumpconds:
91
+ self.engine.jump_if(Const(1), self.final_state)
92
+ self.engine.current_state = self.final_state
93
+
94
+ self.engine.scratch_manager.exit_context()
95
+
96
+
97
+ def get_else_condition(state: State) -> Renderable:
98
+ conditions = [c for c, _ in state.transitions]
99
+ ret: Renderable = Const(1)
100
+
101
+ for c in conditions:
102
+ ret = ret & ~c
103
+
104
+ return ret
105
+
106
+
107
+ class ElseCondition(Condition):
108
+ """Context manager to realize an else behavior within a noRTL engine.
109
+
110
+ Usage example:
111
+
112
+ from nortl.core import CoreEngine
113
+ from nortl.utils.context_manager import Condition, ElseCondition
114
+
115
+ f = CoreEngine('my_engine')
116
+ in_signal = f.define_input('IN')
117
+
118
+ with Condition(f, in_signal == 1):
119
+ f.sync()
120
+ f.do_something()
121
+ with Condition(f, possible_second_condition):
122
+ f.sync()
123
+ f.do_something()
124
+
125
+ with ElseCondition(f):
126
+ f.do_something_else()
127
+
128
+
129
+ """
130
+
131
+ def __init__(self, engine: EngineProto):
132
+ state = engine.current_state.get_metadata(self.final_state_key)
133
+ condition = get_else_condition(state)
134
+ super().__init__(engine, condition)
135
+
136
+ def __exit__(
137
+ self,
138
+ exc_type: type[BaseException] | None,
139
+ exc_val: BaseException | None,
140
+ exc_tb: TracebackType | None,
141
+ ) -> None:
142
+ super().__exit__(exc_type, exc_val, exc_tb)
143
+ self.engine.sync()
@@ -0,0 +1,84 @@
1
+ from types import TracebackType
2
+ from typing import List
3
+
4
+ from nortl.core.constructs import Condition
5
+ from nortl.core.protocols import EngineProto, ThreadProto, WorkerProto
6
+
7
+ __all__ = [
8
+ 'Fork',
9
+ ]
10
+
11
+
12
+ class Fork:
13
+ """Context manager to realize a Fork."""
14
+
15
+ def __init__(self, engine: EngineProto, threadname: str):
16
+ """Initializes the Fork context manager.
17
+
18
+ Arguments:
19
+ engine: The CoreEngine instance.
20
+ threadname: Name of the new thread, optional
21
+ """
22
+ self.engine = engine
23
+ self.threadname = threadname
24
+
25
+ self.checkpoint_worker = self.engine.current_worker
26
+ self.checkpoint_state = self.engine.current_state
27
+
28
+ free_workers: List[WorkerProto] = [w for w in self.engine.workers.values() if not w.working]
29
+
30
+ if free_workers == []:
31
+ self.assigned_worker = self.engine.create_worker()
32
+ else:
33
+ self.assigned_worker = free_workers[0]
34
+
35
+ self.new_thread = self.assigned_worker.create_thread(self.threadname)
36
+
37
+ self.engine.current_worker = self.assigned_worker
38
+
39
+ def __enter__(self) -> ThreadProto:
40
+ """Create a new thread and integrate it into next free worker (or create a new worker)."""
41
+
42
+ self.engine.current_state = self.assigned_worker.reset_state
43
+
44
+ condition = Condition(self.engine, self.assigned_worker.start & (self.assigned_worker.select == len(self.assigned_worker.threads)))
45
+
46
+ with condition:
47
+ state_within_condition = self.engine.current_state
48
+ self.engine.set(self.assigned_worker.idle, 0)
49
+
50
+ for worker in self.engine.workers.values():
51
+ if worker is self.checkpoint_worker:
52
+ spawning_worker = worker
53
+
54
+ spawning_thread = spawning_worker.threads[-1]
55
+ spawning_thread._spawned_threads.append(self.new_thread)
56
+
57
+ # Adjust signal accesses
58
+ self.engine.signal_manager.free_accesses_from_thread(spawning_thread)
59
+ self.engine.scratch_manager.free_accesses_from_thread(spawning_thread)
60
+
61
+ self.engine.current_state = state_within_condition
62
+
63
+ self.engine.sync()
64
+
65
+ self.new_thread.active = True
66
+
67
+ return self.new_thread
68
+
69
+ def __exit__(
70
+ self,
71
+ exc_type: type[BaseException] | None,
72
+ exc_val: BaseException | None,
73
+ exc_tb: TracebackType | None,
74
+ ) -> None:
75
+ self.engine.sync()
76
+ self.new_thread.finish()
77
+
78
+ self.engine.current_worker = self.checkpoint_worker
79
+ self.engine.current_state = self.checkpoint_state
80
+
81
+ # Now the thread has been rendered and so we start the Worker!
82
+ self.engine.set(self.assigned_worker.start, 1)
83
+ self.engine.set(self.assigned_worker.select, (len(self.assigned_worker.threads)))
84
+ self.engine.sync()
@@ -0,0 +1,138 @@
1
+ from types import TracebackType
2
+
3
+ from nortl.core import Const
4
+ from nortl.core.operations import to_renderable
5
+ from nortl.core.protocols import EngineProto, Renderable, StateProto
6
+
7
+ __all__ = [
8
+ 'ForLoop',
9
+ 'WhileLoop',
10
+ ]
11
+
12
+
13
+ class ForLoop:
14
+ """Context manager to realize a for-loop within a noRTL engine."""
15
+
16
+ def __init__(
17
+ self, engine: EngineProto, start: Renderable | int, stop: Renderable | int, step: Renderable | int = 1, counter_width: int = 16
18
+ ) -> None:
19
+ """Initializes the ForLoop context manager.
20
+
21
+ Its intention is to emulate the behavior of a for loop in a engine.
22
+
23
+ Example:
24
+ ```python
25
+ engine = CoreEngine("my_engine")
26
+ out = engine.define_output("test_output", width=8)
27
+
28
+ with ForLoop(engine, 0, 100, 2) as i:
29
+ # code that should be run multiple times
30
+ engine.set(out, i)
31
+ ```
32
+
33
+ The context manager cares about the realization of the counter variable and returns it to be used in the loop.
34
+ This means, multiple (non-colliding) loops may use the same count registers.
35
+
36
+ As in other programming languages: Only modify the counter variable within the loop if you really know, what you do.
37
+ Generally, it is a very bad idea to write to the loop variable.
38
+
39
+ Arguments:
40
+ engine: The CoreEngine instance.
41
+ start: A signal or int representing the start value of the loop counter
42
+ stop: A signal or int representing the final value of the loop counter. The value is non-inclusive.
43
+ step: A signal or int representing the step value of the counter (default: 1)
44
+ counter_width: Width of the counter variable (default: 16). The counter width must fit the stop value.
45
+ """
46
+ self.engine = engine
47
+ self.start = to_renderable(start)
48
+ self.stop = to_renderable(stop)
49
+ self.step = to_renderable(step)
50
+
51
+ self.start_state = engine.current_state
52
+ self.final_state = engine.create_state()
53
+
54
+ # TODO Validate start and stop values against counter_width, if possible
55
+ # FIXME width must be 1 bit wider than the actual counter!
56
+ self.counter = self.engine.define_scratch(counter_width)
57
+ self.counter_nxt = self.counter + self.step
58
+
59
+ def __enter__(self) -> Renderable:
60
+ """Executes the provided function if the condition is met."""
61
+ self.engine.set(self.counter, self.start)
62
+ self.engine.sync()
63
+ self.start_state = self.engine.current_state
64
+
65
+ other_state = self.engine.create_state()
66
+
67
+ self.engine.jump_if(self.counter == self.stop, self.final_state, other_state)
68
+
69
+ self.engine.current_state = other_state
70
+
71
+ # TODO consider moving this into the engine itself
72
+ self.engine.scratch_manager.enter_context()
73
+
74
+ return self.counter
75
+
76
+ def __exit__(
77
+ self,
78
+ exc_type: type[BaseException] | None,
79
+ exc_val: BaseException | None,
80
+ exc_tb: TracebackType | None,
81
+ ) -> None:
82
+ self.engine.sync()
83
+ self.engine.set(self.counter, self.counter_nxt)
84
+ self.engine.jump_if(Const(1), self.start_state)
85
+
86
+ # Goto final state
87
+ self.engine.current_state = self.final_state
88
+
89
+ self.engine.scratch_manager.exit_context()
90
+ self.counter.release()
91
+
92
+ self.engine.sync()
93
+
94
+
95
+ class WhileLoop:
96
+ """Context manager to realize a While loop within a noRTL engine."""
97
+
98
+ def __init__(self, engine: EngineProto, condition: Renderable) -> None:
99
+ """Initializes a While construct.
100
+
101
+ Arguments:
102
+ engine: The CoreEngine instance.
103
+ condition: The condition of the while loop.
104
+ """
105
+ self.engine = engine
106
+ self.condition = to_renderable(condition)
107
+
108
+ self.start_state: StateProto
109
+ self.final_state: StateProto
110
+
111
+ def __enter__(self) -> None:
112
+ self.start_state = self.engine.current_state
113
+ self.final_state = self.engine.create_state()
114
+
115
+ # Add conditional jump to start state
116
+ self.engine.jump_if(self.condition, self.engine.next_state, self.final_state)
117
+
118
+ # Switch to loop content and yield back
119
+ self.engine.current_state = self.engine.next_state
120
+
121
+ # TODO consider moving this into the engine itself
122
+ self.engine.scratch_manager.enter_context()
123
+
124
+ def __exit__(
125
+ self,
126
+ exc_type: type[BaseException] | None,
127
+ exc_val: BaseException | None,
128
+ exc_tb: TracebackType | None,
129
+ ) -> None:
130
+ if len(self.engine.current_state.transitions) > 0:
131
+ raise RuntimeError('Last state in a While loop must not have any outgoing transitions!')
132
+
133
+ self.engine.jump_if(Const(1), self.start_state)
134
+
135
+ # Goto final state
136
+ self.engine.current_state = self.final_state
137
+
138
+ self.engine.scratch_manager.exit_context()