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.
- nortl/__init__.py +85 -0
- nortl/components/__init__.py +8 -0
- nortl/components/channel.py +132 -0
- nortl/components/timer.py +73 -0
- nortl/core/__init__.py +40 -0
- nortl/core/checker.py +135 -0
- nortl/core/common/__init__.py +4 -0
- nortl/core/common/access.py +25 -0
- nortl/core/common/debug.py +6 -0
- nortl/core/common/naming_helper.py +33 -0
- nortl/core/constructs/__init__.py +13 -0
- nortl/core/constructs/condition.py +143 -0
- nortl/core/constructs/fork_join.py +84 -0
- nortl/core/constructs/loop.py +138 -0
- nortl/core/engine.py +575 -0
- nortl/core/exceptions.py +139 -0
- nortl/core/manager/__init__.py +6 -0
- nortl/core/manager/scratch_manager.py +128 -0
- nortl/core/manager/signal_manager.py +71 -0
- nortl/core/modifiers.py +136 -0
- nortl/core/module.py +181 -0
- nortl/core/operations.py +834 -0
- nortl/core/parameter.py +88 -0
- nortl/core/process.py +451 -0
- nortl/core/protocols.py +628 -0
- nortl/core/renderers/__init__.py +0 -0
- nortl/core/renderers/operations/__init__.py +34 -0
- nortl/core/renderers/operations/arithmetics.py +38 -0
- nortl/core/renderers/operations/base.py +111 -0
- nortl/core/renderers/operations/comparison.py +44 -0
- nortl/core/renderers/operations/logic.py +38 -0
- nortl/core/renderers/operations/misc.py +26 -0
- nortl/core/renderers/operations/slice.py +30 -0
- nortl/core/signal.py +878 -0
- nortl/core/state.py +201 -0
- nortl/py.typed +0 -0
- nortl/renderer/__init__.py +5 -0
- nortl/renderer/mermaid_renderer.py +38 -0
- nortl/renderer/networkx_renderer.py +29 -0
- nortl/renderer/verilog_renderer.py +325 -0
- nortl/renderer/verilog_utils/__init__.py +6 -0
- nortl/renderer/verilog_utils/formatter.py +29 -0
- nortl/renderer/verilog_utils/process.py +226 -0
- nortl/renderer/verilog_utils/structural.py +146 -0
- nortl/renderer/verilog_utils/utils.py +23 -0
- nortl/utils/__init__.py +0 -0
- nortl/utils/parse_utils.py +37 -0
- nortl/utils/templates/testbench.sv +41 -0
- nortl/utils/test_wrapper.py +218 -0
- nortl/utils/type_aliases.py +15 -0
- nortl/verilog_library/__init__.py +74 -0
- nortl/verilog_library/nortl_clock_gate.sv +20 -0
- nortl/verilog_library/nortl_count_down_timer.sv +50 -0
- nortl/verilog_library/nortl_delay.sv +66 -0
- nortl/verilog_library/nortl_edge_detector.sv +34 -0
- nortl/verilog_library/nortl_sync.sv +28 -0
- nortl-1.4.0.dist-info/METADATA +105 -0
- nortl-1.4.0.dist-info/RECORD +60 -0
- nortl-1.4.0.dist-info/WHEEL +4 -0
- 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()
|