digsim-logic-simulator 0.12.0__py3-none-any.whl → 0.14.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.
Potentially problematic release.
This version of digsim-logic-simulator might be problematic. Click here for more details.
- digsim/__init__.py +1 -1
- digsim/app/__main__.py +17 -13
- digsim/app/gui/__init__.py +1 -1
- digsim/app/gui/_circuit_area.py +32 -21
- digsim/app/gui/_component_selection.py +3 -1
- digsim/app/gui/_main_window.py +1 -1
- digsim/app/gui/_top_bar.py +1 -1
- digsim/app/gui/_utils.py +1 -1
- digsim/app/gui_objects/__init__.py +2 -2
- digsim/app/gui_objects/_bus_bit_object.py +1 -1
- digsim/app/gui_objects/_buzzer_object.py +7 -7
- digsim/app/gui_objects/_component_context_menu.py +2 -2
- digsim/app/gui_objects/_component_object.py +11 -10
- digsim/app/gui_objects/_component_port_item.py +1 -3
- digsim/app/gui_objects/_dip_switch_object.py +6 -5
- digsim/app/gui_objects/_gui_note_object.py +11 -12
- digsim/app/gui_objects/_gui_object_factory.py +2 -2
- digsim/app/gui_objects/_hexdigit_object.py +1 -1
- digsim/app/gui_objects/_image_objects.py +8 -6
- digsim/app/gui_objects/_label_object.py +4 -3
- digsim/app/gui_objects/_logic_analyzer_object.py +19 -10
- digsim/app/gui_objects/_seven_segment_object.py +11 -4
- digsim/app/gui_objects/_shortcut_objects.py +4 -3
- digsim/app/gui_objects/_yosys_object.py +1 -1
- digsim/app/model/__init__.py +1 -1
- digsim/app/model/_model.py +8 -4
- digsim/app/model/_model_components.py +2 -5
- digsim/app/model/_model_new_wire.py +3 -2
- digsim/app/model/_model_objects.py +2 -6
- digsim/app/model/_model_settings.py +2 -2
- digsim/app/model/_model_shortcuts.py +1 -15
- digsim/app/settings/__init__.py +1 -1
- digsim/app/settings/_component_settings.py +2 -2
- digsim/app/settings/_gui_settings.py +1 -1
- digsim/app/settings/_shortcut_dialog.py +4 -5
- digsim/circuit/__init__.py +1 -1
- digsim/circuit/_circuit.py +52 -38
- digsim/circuit/components/__init__.py +1 -1
- digsim/circuit/components/_bus_bits.py +1 -1
- digsim/circuit/components/_button.py +2 -6
- digsim/circuit/components/_buzzer.py +1 -1
- digsim/circuit/components/_clock.py +1 -1
- digsim/circuit/components/_dip_switch.py +1 -1
- digsim/circuit/components/_flip_flops.py +1 -1
- digsim/circuit/components/_hexdigit.py +1 -1
- digsim/circuit/components/_ic.py +1 -1
- digsim/circuit/components/_label_wire.py +1 -1
- digsim/circuit/components/_led.py +1 -1
- digsim/circuit/components/_logic_analyzer.py +1 -1
- digsim/circuit/components/_mem64kbyte.py +1 -1
- digsim/circuit/components/_memstdout.py +1 -1
- digsim/circuit/components/_note.py +1 -1
- digsim/circuit/components/_on_off_switch.py +1 -1
- digsim/circuit/components/_seven_segment.py +1 -1
- digsim/circuit/components/_static_level.py +1 -1
- digsim/circuit/components/_static_value.py +1 -1
- digsim/circuit/components/_yosys_component.py +2 -2
- digsim/circuit/components/atoms/__init__.py +1 -0
- digsim/circuit/components/atoms/_component.py +14 -4
- digsim/circuit/components/atoms/_digsim_exception.py +1 -1
- digsim/circuit/components/atoms/_port.py +45 -29
- digsim/storage_model/_app.py +8 -3
- digsim/storage_model/_circuit.py +16 -8
- digsim/synth/__init__.py +1 -1
- digsim/synth/__main__.py +3 -3
- digsim/synth/_synthesis.py +6 -3
- digsim/utils/__init__.py +1 -1
- digsim/utils/_yosys_netlist.py +10 -4
- {digsim_logic_simulator-0.12.0.dist-info → digsim_logic_simulator-0.14.0.dist-info}/METADATA +4 -5
- digsim_logic_simulator-0.14.0.dist-info/RECORD +105 -0
- digsim_logic_simulator-0.12.0.dist-info/RECORD +0 -105
- {digsim_logic_simulator-0.12.0.dist-info → digsim_logic_simulator-0.14.0.dist-info}/WHEEL +0 -0
- {digsim_logic_simulator-0.12.0.dist-info → digsim_logic_simulator-0.14.0.dist-info}/licenses/LICENSE.md +0 -0
- {digsim_logic_simulator-0.12.0.dist-info → digsim_logic_simulator-0.14.0.dist-info}/top_level.txt +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""A button component with an image as symbol the GUI"""
|
|
@@ -37,6 +37,8 @@ class ButtonObject(ImageObject):
|
|
|
37
37
|
IMAGE_FILENAME = "images/PB.png"
|
|
38
38
|
BUTTON_RADIUS = 35
|
|
39
39
|
|
|
40
|
+
_BUTTON_ACTIVE_PEN = QPen(Qt.green)
|
|
41
|
+
|
|
40
42
|
def __init__(self, app_model, component, xpos, ypos):
|
|
41
43
|
super().__init__(app_model, component, xpos, ypos)
|
|
42
44
|
self.show_name(False)
|
|
@@ -45,9 +47,8 @@ class ButtonObject(ImageObject):
|
|
|
45
47
|
def paint_component(self, painter):
|
|
46
48
|
super().paint_component(painter)
|
|
47
49
|
if self.component.active:
|
|
48
|
-
pen =
|
|
50
|
+
pen = self._BUTTON_ACTIVE_PEN
|
|
49
51
|
pen.setWidth(4)
|
|
50
|
-
pen.setColor(Qt.green)
|
|
51
52
|
painter.setPen(pen)
|
|
52
53
|
painter.setBrush(Qt.NoBrush)
|
|
53
54
|
painter.drawEllipse(
|
digsim/app/model/__init__.py
CHANGED
digsim/app/model/_model.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""An application model for a GUI simulated circuit"""
|
|
@@ -37,15 +37,18 @@ class AppModel(QThread):
|
|
|
37
37
|
|
|
38
38
|
def __init__(self):
|
|
39
39
|
super().__init__()
|
|
40
|
-
self.
|
|
41
|
-
self._model_shortcuts = ModelShortcuts(self)
|
|
42
|
-
self._model_settings = ModelSettings(self)
|
|
40
|
+
self._setup_model_components()
|
|
43
41
|
self._started = False
|
|
44
42
|
self._single_step = False
|
|
45
43
|
self._changed = False
|
|
46
44
|
self._gui_event_queue = queue.Queue()
|
|
47
45
|
self._multi_select = False
|
|
48
46
|
|
|
47
|
+
def _setup_model_components(self):
|
|
48
|
+
self._model_objects = ModelObjects(self)
|
|
49
|
+
self._model_shortcuts = ModelShortcuts(self)
|
|
50
|
+
self._model_settings = ModelSettings(self)
|
|
51
|
+
|
|
49
52
|
@property
|
|
50
53
|
def objects(self):
|
|
51
54
|
"""return the model objects"""
|
|
@@ -100,6 +103,7 @@ class AppModel(QThread):
|
|
|
100
103
|
def model_stop(self):
|
|
101
104
|
"""Stop model simulation thread"""
|
|
102
105
|
self._started = False
|
|
106
|
+
self.wait()
|
|
103
107
|
|
|
104
108
|
def model_reset(self):
|
|
105
109
|
"""Reset model simulation"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""Handle component objects in the model"""
|
|
@@ -125,10 +125,7 @@ class ModelComponents:
|
|
|
125
125
|
|
|
126
126
|
def get_object_list(self):
|
|
127
127
|
"""Get list of component objects"""
|
|
128
|
-
|
|
129
|
-
for _, comp in self._component_objects.items():
|
|
130
|
-
component_objects.append(comp)
|
|
131
|
-
return component_objects
|
|
128
|
+
return list(self._component_objects.values())
|
|
132
129
|
|
|
133
130
|
def update_settings(self, component_object, settings):
|
|
134
131
|
"""Update settings for a component"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""Handle new wire object in the model"""
|
|
@@ -29,11 +29,12 @@ class NewWire:
|
|
|
29
29
|
|
|
30
30
|
def end(self, component, portname):
|
|
31
31
|
"""End new wire object"""
|
|
32
|
-
self._app_model.objects.push_undo_state()
|
|
33
32
|
end_port = component.port(portname)
|
|
34
33
|
if self._start_port.is_output() and end_port.is_input():
|
|
34
|
+
self._app_model.objects.push_undo_state()
|
|
35
35
|
self._start_port.wire = end_port
|
|
36
36
|
elif self._start_port.is_input() and end_port.is_output():
|
|
37
|
+
self._app_model.objects.push_undo_state()
|
|
37
38
|
end_port.wire = self._start_port
|
|
38
39
|
else:
|
|
39
40
|
raise PortConnectionError("Cannot connect to port of same type")
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""Handle objects in the model"""
|
|
@@ -53,11 +53,7 @@ class ModelObjects:
|
|
|
53
53
|
|
|
54
54
|
def get_selected(self):
|
|
55
55
|
"""Get selected objects"""
|
|
56
|
-
|
|
57
|
-
for obj in self.get_list():
|
|
58
|
-
if obj.selected:
|
|
59
|
-
objects.append(obj)
|
|
60
|
-
return objects
|
|
56
|
+
return [obj for obj in self.get_list() if obj.selected]
|
|
61
57
|
|
|
62
58
|
def _delete(self, selected_objects):
|
|
63
59
|
for obj in selected_objects:
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""Handle settings in the model"""
|
|
@@ -23,7 +23,7 @@ class ModelSettings:
|
|
|
23
23
|
|
|
24
24
|
def get_all(self):
|
|
25
25
|
"""Return settings dict"""
|
|
26
|
-
return self._settings
|
|
26
|
+
return self._settings.copy()
|
|
27
27
|
|
|
28
28
|
def from_dict(self, circuit_dict):
|
|
29
29
|
"""Get settings from circuit dict"""
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""Handle shortcuts in the model"""
|
|
@@ -38,20 +38,6 @@ class ModelShortcuts:
|
|
|
38
38
|
"""Get shortcut"""
|
|
39
39
|
return self._shortcut_component.get(key)
|
|
40
40
|
|
|
41
|
-
def _qtkey_to_key(self, qt_key):
|
|
42
|
-
return {
|
|
43
|
-
Qt.Key_0: "0",
|
|
44
|
-
Qt.Key_1: "1",
|
|
45
|
-
Qt.Key_2: "2",
|
|
46
|
-
Qt.Key_3: "3",
|
|
47
|
-
Qt.Key_4: "4",
|
|
48
|
-
Qt.Key_5: "5",
|
|
49
|
-
Qt.Key_6: "6",
|
|
50
|
-
Qt.Key_7: "7",
|
|
51
|
-
Qt.Key_8: "8",
|
|
52
|
-
Qt.Key_9: "9",
|
|
53
|
-
}.get(qt_key)
|
|
54
|
-
|
|
55
41
|
def press(self, qtkey):
|
|
56
42
|
"""Handle shortcut keypress"""
|
|
57
43
|
key = self.QT_KEY_TO_KEY.get(qtkey)
|
digsim/app/settings/__init__.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""The component settings dialog(s)"""
|
|
@@ -271,7 +271,7 @@ class ComponentSettingsCheckBoxWidthBool(ComponentSettingsBase):
|
|
|
271
271
|
checkbox = QCheckBox(f"bit{checkbox_id}")
|
|
272
272
|
checkbox.setChecked(True)
|
|
273
273
|
checkbox.stateChanged.connect(self._update)
|
|
274
|
-
self.layout().addWidget(checkbox, checkbox_id % 8, checkbox_id
|
|
274
|
+
self.layout().addWidget(checkbox, checkbox_id % 8, checkbox_id // 8, 1, 1)
|
|
275
275
|
self._bit_checkboxes.append(checkbox)
|
|
276
276
|
disable_all = QPushButton("Disable All")
|
|
277
277
|
disable_all.clicked.connect(self._disable_all)
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""The shurtcut dialog"""
|
|
@@ -20,12 +20,11 @@ class ShortcutDialog(QDialog):
|
|
|
20
20
|
self.layout().addWidget(QLabel("Select shortcut key for component"))
|
|
21
21
|
self._key_selector = QComboBox(parent)
|
|
22
22
|
for key in "1234567890":
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
shortcut_component = app_model.shortcuts.get_component(shortcut_key)
|
|
23
|
+
shortcut_string = key
|
|
24
|
+
shortcut_component = app_model.shortcuts.get_component(key)
|
|
26
25
|
if shortcut_component is not None:
|
|
27
26
|
shortcut_string += f" - {shortcut_component.name()}"
|
|
28
|
-
self._key_selector.addItem(shortcut_string, userData=
|
|
27
|
+
self._key_selector.addItem(shortcut_string, userData=key)
|
|
29
28
|
self.layout().addWidget(self._key_selector)
|
|
30
29
|
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok | QDialogButtonBox.Cancel)
|
|
31
30
|
self.buttonBox.accepted.connect(self.accept)
|
digsim/circuit/__init__.py
CHANGED
digsim/circuit/_circuit.py
CHANGED
|
@@ -7,13 +7,14 @@ Module that handles the circuit simulation of components
|
|
|
7
7
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
|
-
import
|
|
10
|
+
import heapq
|
|
11
|
+
import pathlib
|
|
11
12
|
from typing import Tuple
|
|
12
13
|
|
|
13
14
|
from digsim.storage_model import CircuitDataClass, CircuitFileDataClass
|
|
14
15
|
|
|
15
16
|
from ._waves_writer import WavesWriter
|
|
16
|
-
from .components.atoms import Component, DigsimException, PortOutDelta
|
|
17
|
+
from .components.atoms import VALUE_TYPE, Component, DigsimException, PortOutDelta
|
|
17
18
|
|
|
18
19
|
|
|
19
20
|
class CircuitError(DigsimException):
|
|
@@ -26,10 +27,10 @@ class CircuitEvent:
|
|
|
26
27
|
delta events in the simulation.
|
|
27
28
|
"""
|
|
28
29
|
|
|
29
|
-
def __init__(self, time_ns: int, port: PortOutDelta, value:
|
|
30
|
+
def __init__(self, time_ns: int, port: PortOutDelta, value: VALUE_TYPE):
|
|
30
31
|
self._time_ns: int = time_ns
|
|
31
32
|
self._port: PortOutDelta = port
|
|
32
|
-
self._value:
|
|
33
|
+
self._value: VALUE_TYPE = value
|
|
33
34
|
|
|
34
35
|
@property
|
|
35
36
|
def time_ns(self) -> int:
|
|
@@ -42,7 +43,7 @@ class CircuitEvent:
|
|
|
42
43
|
return self._port
|
|
43
44
|
|
|
44
45
|
@property
|
|
45
|
-
def value(self) ->
|
|
46
|
+
def value(self) -> VALUE_TYPE:
|
|
46
47
|
"""Get the delta cycle value of this event"""
|
|
47
48
|
return self._value
|
|
48
49
|
|
|
@@ -50,7 +51,7 @@ class CircuitEvent:
|
|
|
50
51
|
"""Return True if the in the event is the same as"""
|
|
51
52
|
return port == self._port
|
|
52
53
|
|
|
53
|
-
def update(self, time_ns: int, value:
|
|
54
|
+
def update(self, time_ns: int, value: VALUE_TYPE):
|
|
54
55
|
"""Update the event with a new time (ns) and a new value"""
|
|
55
56
|
self._time_ns = time_ns
|
|
56
57
|
self._value = value
|
|
@@ -58,6 +59,14 @@ class CircuitEvent:
|
|
|
58
59
|
def __lt__(self, other) -> bool:
|
|
59
60
|
return other.time_ns > self.time_ns
|
|
60
61
|
|
|
62
|
+
def __eq__(self, other) -> bool:
|
|
63
|
+
return (
|
|
64
|
+
isinstance(other, CircuitEvent)
|
|
65
|
+
and self._port == other._port
|
|
66
|
+
and self._time_ns == other._time_ns
|
|
67
|
+
and self._value == other._value
|
|
68
|
+
)
|
|
69
|
+
|
|
61
70
|
|
|
62
71
|
class Circuit:
|
|
63
72
|
"""Class thay handles the circuit simulation"""
|
|
@@ -65,6 +74,7 @@ class Circuit:
|
|
|
65
74
|
def __init__(self, name: str | None = None, vcd: str | None = None):
|
|
66
75
|
self._components: dict[str, Component] = {}
|
|
67
76
|
self._circuit_events: list[CircuitEvent] = []
|
|
77
|
+
self._events_by_port: dict[PortOutDelta, CircuitEvent] = {}
|
|
68
78
|
self._name: str | None = name
|
|
69
79
|
self._time_ns: int = 0
|
|
70
80
|
self._folder: str | None = None
|
|
@@ -86,10 +96,7 @@ class Circuit:
|
|
|
86
96
|
@property
|
|
87
97
|
def components(self) -> list[Component]:
|
|
88
98
|
"""Get the components in this circuit"""
|
|
89
|
-
|
|
90
|
-
for _, comp in self._components.items():
|
|
91
|
-
comp_array.append(comp)
|
|
92
|
-
return comp_array
|
|
99
|
+
return list(self._components.values())
|
|
93
100
|
|
|
94
101
|
def load_path(self, path) -> str:
|
|
95
102
|
"""Get the load path relative to the circuit path"""
|
|
@@ -100,7 +107,9 @@ class Circuit:
|
|
|
100
107
|
def store_path(self, path) -> str:
|
|
101
108
|
"""Get the store path relative to the circuit path"""
|
|
102
109
|
if self._folder is not None:
|
|
103
|
-
return
|
|
110
|
+
return str(
|
|
111
|
+
pathlib.Path(path).resolve().absolute().relative_to(pathlib.Path(self._folder))
|
|
112
|
+
)
|
|
104
113
|
return path
|
|
105
114
|
|
|
106
115
|
def delete_component(self, component: Component):
|
|
@@ -110,16 +119,13 @@ class Circuit:
|
|
|
110
119
|
|
|
111
120
|
def get_toplevel_components(self) -> list[Component]:
|
|
112
121
|
"""Get toplevel components in the circuit"""
|
|
113
|
-
|
|
114
|
-
for _, comp in self._components.items():
|
|
115
|
-
if comp.is_toplevel():
|
|
116
|
-
toplevel_components.append(comp)
|
|
117
|
-
return toplevel_components
|
|
122
|
+
return [comp for comp in self._components.values() if comp.is_toplevel()]
|
|
118
123
|
|
|
119
124
|
def init(self):
|
|
120
125
|
"""Initialize circuit and components (and ports)"""
|
|
121
126
|
self._time_ns = 0
|
|
122
127
|
self._circuit_events = []
|
|
128
|
+
self._events_by_port = {}
|
|
123
129
|
if self._vcd is not None:
|
|
124
130
|
self._vcd_init()
|
|
125
131
|
for _, comp in self._components.items():
|
|
@@ -175,22 +181,32 @@ class Circuit:
|
|
|
175
181
|
Process one simulation event
|
|
176
182
|
Return False if ther are now events of if the stop_time has passed
|
|
177
183
|
"""
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
184
|
+
while self._circuit_events:
|
|
185
|
+
event = heapq.heappop(self._circuit_events)
|
|
186
|
+
|
|
187
|
+
# Check if this is the latest event for this port
|
|
188
|
+
if event != self._events_by_port.get(event.port):
|
|
189
|
+
# This is a stale event, ignore it
|
|
190
|
+
continue
|
|
191
|
+
|
|
192
|
+
if stop_time_ns is not None and event.time_ns > stop_time_ns:
|
|
193
|
+
# Put the event back if it's after the stop time
|
|
194
|
+
heapq.heappush(self._circuit_events, event)
|
|
195
|
+
return False, False
|
|
196
|
+
|
|
197
|
+
del self._events_by_port[event.port]
|
|
198
|
+
# print(
|
|
199
|
+
# f"Execute event {event.port.path()}.{event.port.name()}"
|
|
200
|
+
# f" {event.time_ns} {event.value}"
|
|
201
|
+
# )
|
|
202
|
+
self._time_ns = event.time_ns
|
|
203
|
+
event.port.delta_cycle(event.value)
|
|
204
|
+
toplevel = event.port.parent().is_toplevel()
|
|
205
|
+
if self._vcd is not None:
|
|
206
|
+
self._vcd.write(event.port, self._time_ns)
|
|
207
|
+
return True, toplevel
|
|
208
|
+
|
|
209
|
+
return False, False
|
|
194
210
|
|
|
195
211
|
def _is_toplevel_event(self) -> bool:
|
|
196
212
|
if len(self._circuit_events) == 0:
|
|
@@ -231,15 +247,13 @@ class Circuit:
|
|
|
231
247
|
if stop_time_ns >= self._time_ns:
|
|
232
248
|
self.run(ns=stop_time_ns - self._time_ns)
|
|
233
249
|
|
|
234
|
-
def add_event(self, port: PortOutDelta, value:
|
|
250
|
+
def add_event(self, port: PortOutDelta, value: VALUE_TYPE, propagation_delay_ns: int):
|
|
235
251
|
"""Add delta cycle event, this will also write values to .vcd file"""
|
|
236
252
|
event_time_ns = self._time_ns + propagation_delay_ns
|
|
237
253
|
# print(f"Add event {port.parent().name()}:{port.name()} => {value}")
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
return
|
|
242
|
-
self._circuit_events.append(CircuitEvent(event_time_ns, port, value))
|
|
254
|
+
event = CircuitEvent(event_time_ns, port, value)
|
|
255
|
+
self._events_by_port[port] = event
|
|
256
|
+
heapq.heappush(self._circuit_events, event)
|
|
243
257
|
|
|
244
258
|
def add_component(self, component: Component):
|
|
245
259
|
"""Add component to circuit"""
|
|
@@ -1,23 +1,19 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""A PushButton component"""
|
|
5
5
|
|
|
6
|
-
import logging
|
|
7
|
-
|
|
8
6
|
from .atoms import CallbackComponent, PortOutImmediate
|
|
9
7
|
|
|
10
8
|
|
|
11
9
|
class PushButton(CallbackComponent):
|
|
12
10
|
"""PushButton component class"""
|
|
13
11
|
|
|
14
|
-
def __init__(self, circuit, name=None
|
|
12
|
+
def __init__(self, circuit, name=None):
|
|
15
13
|
super().__init__(circuit, name)
|
|
16
14
|
portout = PortOutImmediate(self, "O")
|
|
17
15
|
self.add_port(portout)
|
|
18
16
|
portout.update_parent(True)
|
|
19
|
-
if inverted:
|
|
20
|
-
logging.warning("Setting 'inverted' has been removed")
|
|
21
17
|
|
|
22
18
|
def default_state(self):
|
|
23
19
|
self.release()
|
digsim/circuit/components/_ic.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright (c) Fredrik Andersson, 2023-
|
|
1
|
+
# Copyright (c) Fredrik Andersson, 2023-2025
|
|
2
2
|
# All rights reserved
|
|
3
3
|
|
|
4
4
|
"""
|
|
@@ -26,7 +26,7 @@ class YosysComponent(MultiComponent):
|
|
|
26
26
|
def __init__(self, circuit, path=None, name=None, nets=True):
|
|
27
27
|
super().__init__(circuit, name)
|
|
28
28
|
self._circuit = circuit
|
|
29
|
-
self._path = path
|
|
29
|
+
self._path = str(path)
|
|
30
30
|
self._gates_comp = None
|
|
31
31
|
self._net_comp = None
|
|
32
32
|
self._netlist_module = None
|
|
@@ -63,10 +63,20 @@ class Component(abc.ABC):
|
|
|
63
63
|
self._ports = []
|
|
64
64
|
|
|
65
65
|
def path(self) -> str:
|
|
66
|
-
"""Get component path"""
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
66
|
+
"""Get component path (iterative)"""
|
|
67
|
+
path_parts = []
|
|
68
|
+
current_component = self
|
|
69
|
+
while current_component is not None:
|
|
70
|
+
name = current_component.name()
|
|
71
|
+
if not isinstance(name, str):
|
|
72
|
+
raise TypeError(
|
|
73
|
+
f"Component name is not a string: "
|
|
74
|
+
f"{name} ({type(name)}), "
|
|
75
|
+
f"component: {current_component.__class__.__name__}"
|
|
76
|
+
)
|
|
77
|
+
path_parts.append(name)
|
|
78
|
+
current_component = current_component._parent
|
|
79
|
+
return ".".join(reversed(path_parts))
|
|
70
80
|
|
|
71
81
|
@property
|
|
72
82
|
def ports(self):
|