digsim-logic-simulator 0.22.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 (107) hide show
  1. digsim/__init__.py +6 -0
  2. digsim/app/__main__.py +12 -0
  3. digsim/app/cli.py +68 -0
  4. digsim/app/gui/__init__.py +6 -0
  5. digsim/app/gui/_circuit_area.py +468 -0
  6. digsim/app/gui/_component_selection.py +154 -0
  7. digsim/app/gui/_main_window.py +163 -0
  8. digsim/app/gui/_top_bar.py +339 -0
  9. digsim/app/gui/_utils.py +26 -0
  10. digsim/app/gui/_warning_dialog.py +46 -0
  11. digsim/app/gui_objects/__init__.py +7 -0
  12. digsim/app/gui_objects/_bus_bit_object.py +94 -0
  13. digsim/app/gui_objects/_buzzer_object.py +97 -0
  14. digsim/app/gui_objects/_component_context_menu.py +79 -0
  15. digsim/app/gui_objects/_component_object.py +374 -0
  16. digsim/app/gui_objects/_component_port_item.py +63 -0
  17. digsim/app/gui_objects/_dip_switch_object.py +104 -0
  18. digsim/app/gui_objects/_gui_note_object.py +80 -0
  19. digsim/app/gui_objects/_gui_object_factory.py +80 -0
  20. digsim/app/gui_objects/_hexdigit_object.py +53 -0
  21. digsim/app/gui_objects/_image_objects.py +239 -0
  22. digsim/app/gui_objects/_label_object.py +97 -0
  23. digsim/app/gui_objects/_logic_analyzer_object.py +86 -0
  24. digsim/app/gui_objects/_seven_segment_object.py +131 -0
  25. digsim/app/gui_objects/_shortcut_objects.py +82 -0
  26. digsim/app/gui_objects/_yosys_object.py +32 -0
  27. digsim/app/gui_objects/images/AND.png +0 -0
  28. digsim/app/gui_objects/images/Analyzer.png +0 -0
  29. digsim/app/gui_objects/images/BUF.png +0 -0
  30. digsim/app/gui_objects/images/Buzzer.png +0 -0
  31. digsim/app/gui_objects/images/Clock.png +0 -0
  32. digsim/app/gui_objects/images/DFF.png +0 -0
  33. digsim/app/gui_objects/images/DIP_SWITCH.png +0 -0
  34. digsim/app/gui_objects/images/FlipFlop.png +0 -0
  35. digsim/app/gui_objects/images/IC.png +0 -0
  36. digsim/app/gui_objects/images/LED_OFF.png +0 -0
  37. digsim/app/gui_objects/images/LED_ON.png +0 -0
  38. digsim/app/gui_objects/images/MUX.png +0 -0
  39. digsim/app/gui_objects/images/NAND.png +0 -0
  40. digsim/app/gui_objects/images/NOR.png +0 -0
  41. digsim/app/gui_objects/images/NOT.png +0 -0
  42. digsim/app/gui_objects/images/ONE.png +0 -0
  43. digsim/app/gui_objects/images/OR.png +0 -0
  44. digsim/app/gui_objects/images/PB.png +0 -0
  45. digsim/app/gui_objects/images/Switch_OFF.png +0 -0
  46. digsim/app/gui_objects/images/Switch_ON.png +0 -0
  47. digsim/app/gui_objects/images/XNOR.png +0 -0
  48. digsim/app/gui_objects/images/XOR.png +0 -0
  49. digsim/app/gui_objects/images/YOSYS.png +0 -0
  50. digsim/app/gui_objects/images/ZERO.png +0 -0
  51. digsim/app/images/app_icon.png +0 -0
  52. digsim/app/model/__init__.py +6 -0
  53. digsim/app/model/_model.py +210 -0
  54. digsim/app/model/_model_components.py +162 -0
  55. digsim/app/model/_model_new_wire.py +57 -0
  56. digsim/app/model/_model_objects.py +155 -0
  57. digsim/app/model/_model_settings.py +35 -0
  58. digsim/app/model/_model_shortcuts.py +72 -0
  59. digsim/app/settings/__init__.py +8 -0
  60. digsim/app/settings/_component_settings.py +415 -0
  61. digsim/app/settings/_gui_settings.py +71 -0
  62. digsim/app/settings/_shortcut_dialog.py +39 -0
  63. digsim/circuit/__init__.py +7 -0
  64. digsim/circuit/_circuit.py +329 -0
  65. digsim/circuit/_waves_writer.py +61 -0
  66. digsim/circuit/components/__init__.py +26 -0
  67. digsim/circuit/components/_bus_bits.py +68 -0
  68. digsim/circuit/components/_button.py +44 -0
  69. digsim/circuit/components/_buzzer.py +45 -0
  70. digsim/circuit/components/_clock.py +54 -0
  71. digsim/circuit/components/_dip_switch.py +73 -0
  72. digsim/circuit/components/_flip_flops.py +99 -0
  73. digsim/circuit/components/_gates.py +246 -0
  74. digsim/circuit/components/_hexdigit.py +82 -0
  75. digsim/circuit/components/_ic.py +36 -0
  76. digsim/circuit/components/_label_wire.py +167 -0
  77. digsim/circuit/components/_led.py +18 -0
  78. digsim/circuit/components/_logic_analyzer.py +60 -0
  79. digsim/circuit/components/_mem64kbyte.py +42 -0
  80. digsim/circuit/components/_memstdout.py +37 -0
  81. digsim/circuit/components/_note.py +25 -0
  82. digsim/circuit/components/_on_off_switch.py +54 -0
  83. digsim/circuit/components/_seven_segment.py +28 -0
  84. digsim/circuit/components/_static_level.py +28 -0
  85. digsim/circuit/components/_static_value.py +44 -0
  86. digsim/circuit/components/_yosys_atoms.py +1353 -0
  87. digsim/circuit/components/_yosys_component.py +232 -0
  88. digsim/circuit/components/atoms/__init__.py +23 -0
  89. digsim/circuit/components/atoms/_component.py +280 -0
  90. digsim/circuit/components/atoms/_digsim_exception.py +8 -0
  91. digsim/circuit/components/atoms/_port.py +398 -0
  92. digsim/circuit/components/ic/74162.json +1331 -0
  93. digsim/circuit/components/ic/7448.json +834 -0
  94. digsim/storage_model/__init__.py +7 -0
  95. digsim/storage_model/_app.py +58 -0
  96. digsim/storage_model/_circuit.py +126 -0
  97. digsim/synth/__init__.py +6 -0
  98. digsim/synth/__main__.py +67 -0
  99. digsim/synth/_synthesis.py +156 -0
  100. digsim/utils/__init__.py +6 -0
  101. digsim/utils/_yosys_netlist.py +134 -0
  102. digsim_logic_simulator-0.22.0.dist-info/METADATA +140 -0
  103. digsim_logic_simulator-0.22.0.dist-info/RECORD +107 -0
  104. digsim_logic_simulator-0.22.0.dist-info/WHEEL +5 -0
  105. digsim_logic_simulator-0.22.0.dist-info/entry_points.txt +2 -0
  106. digsim_logic_simulator-0.22.0.dist-info/licenses/LICENSE.md +32 -0
  107. digsim_logic_simulator-0.22.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,97 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """A label component placed in the GUI"""
5
+
6
+ from PySide6.QtCore import QPoint, QRect, Qt
7
+ from PySide6.QtGui import QPen, QPolygon
8
+
9
+ from ._component_object import ComponentObject
10
+
11
+
12
+ class LabelObject(ComponentObject):
13
+ """The class for a bus/bit component placed in the GUI"""
14
+
15
+ _LABEL_PEN = QPen(Qt.black)
16
+
17
+ def __init__(self, app_model, component, xpos, ypos):
18
+ super().__init__(app_model, component, xpos, ypos)
19
+ label = component.label()
20
+ label_w, label_h = self.get_string_metrics(label)
21
+ self.width = 2 * self.PORT_SIDE + label_w
22
+ self.height = self.PORT_SIDE + label_h
23
+ self._input = len(self._component.inports()) > 0
24
+
25
+ if self._input:
26
+ xpos = -ComponentObject.RECT_TO_BORDER
27
+ else:
28
+ xpos = self.width - self.PORT_SIDE - 1
29
+ rect = QRect(
30
+ self.object_pos.x() + xpos,
31
+ self.object_pos.y() + self.height / 2 - self.PORT_SIDE / 2,
32
+ self.PORT_SIDE,
33
+ self.PORT_SIDE,
34
+ )
35
+ port = self.component.port(label)
36
+ self.set_port_rect(port, rect)
37
+
38
+ @classmethod
39
+ def _paint_label(cls, painter, comp_rect, name, selected=False):
40
+ pen = cls._LABEL_PEN
41
+ if selected:
42
+ pen.setWidth(4)
43
+ else:
44
+ pen.setWidth(1)
45
+ painter.setPen(pen)
46
+ painter.setBrush(Qt.SolidPattern)
47
+ painter.setBrush(Qt.gray)
48
+
49
+ if "in" in name.lower():
50
+ points = QPolygon(
51
+ [
52
+ QPoint(comp_rect.x(), comp_rect.y() + comp_rect.height() / 2),
53
+ QPoint(comp_rect.x() + comp_rect.height() / 2, comp_rect.y()),
54
+ QPoint(comp_rect.x() + comp_rect.width(), comp_rect.y()),
55
+ QPoint(comp_rect.x() + comp_rect.width(), comp_rect.y() + comp_rect.height()),
56
+ QPoint(
57
+ comp_rect.x() + comp_rect.height() / 2, comp_rect.y() + comp_rect.height()
58
+ ),
59
+ QPoint(comp_rect.x(), comp_rect.y() + comp_rect.height() / 2),
60
+ ]
61
+ )
62
+ else:
63
+ points = QPolygon(
64
+ [
65
+ QPoint(comp_rect.x(), comp_rect.y()),
66
+ QPoint(
67
+ comp_rect.x() + comp_rect.width() - comp_rect.height() / 2, comp_rect.y()
68
+ ),
69
+ QPoint(
70
+ comp_rect.x() + comp_rect.width(), comp_rect.y() + comp_rect.height() / 2
71
+ ),
72
+ QPoint(
73
+ comp_rect.x() + comp_rect.width() - comp_rect.height() / 2,
74
+ comp_rect.y() + comp_rect.height(),
75
+ ),
76
+ QPoint(comp_rect.x(), comp_rect.y() + comp_rect.height()),
77
+ QPoint(comp_rect.x(), comp_rect.y()),
78
+ ]
79
+ )
80
+ painter.drawPolygon(points)
81
+
82
+ def paint_component(self, painter):
83
+ if self._input:
84
+ self._paint_label(painter, self.rect(), "sink", self.selected)
85
+ else:
86
+ self._paint_label(painter, self.rect(), "source", self.selected)
87
+
88
+ @classmethod
89
+ def paint_selectable_component(cls, painter, size, name):
90
+ width = 40
91
+ height = 15
92
+ cls._paint_label(
93
+ painter,
94
+ QRect(size.width() / 2 - width / 2, size.height() / 2 - height / 2, width, height),
95
+ name,
96
+ )
97
+ cls.paint_selectable_component_name(painter, QPoint(0, 0), size, name)
@@ -0,0 +1,86 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """A Logic Analyzer component placed in the GUI"""
5
+
6
+ from PySide6.QtCore import QPoint, QRect, Qt
7
+ from PySide6.QtGui import QPainterPath, QPen
8
+
9
+ from ._image_objects import ImageObject
10
+
11
+
12
+ class LogicAnalyzerObject(ImageObject):
13
+ """The class for a LogicAnalyzer component placed in the GUI"""
14
+
15
+ IMAGE_FILENAME = "images/Analyzer.png"
16
+
17
+ SIGNAL_NAME_WIDTH = 40
18
+ ANALYZER_DISPLAY_WIDTH = 200
19
+
20
+ _ANALYZER_PEN = QPen(Qt.green)
21
+ _SIGNAL_VERTICAL_SCALE = 10
22
+ _SIGNAL_HORIZONTAL_SCALE = 2
23
+
24
+ def __init__(self, app_model, component, xpos, ypos):
25
+ super().__init__(app_model, component, xpos, ypos)
26
+ self.width = self.SIGNAL_NAME_WIDTH + self.ANALYZER_DISPLAY_WIDTH + 2 * self.RECT_TO_BORDER
27
+ self.update_ports()
28
+
29
+ def paint_component(self, painter):
30
+ self.paint_component_base(painter)
31
+ painter.setBrush(Qt.SolidPattern)
32
+ painter.setBrush(Qt.black)
33
+ painter.drawRoundedRect(
34
+ QRect(
35
+ self.object_pos.x() + self.SIGNAL_NAME_WIDTH,
36
+ self.object_pos.y() + 2 * self.RECT_TO_BORDER,
37
+ self.ANALYZER_DISPLAY_WIDTH,
38
+ self.height - 4 * self.RECT_TO_BORDER,
39
+ ),
40
+ 5,
41
+ 5,
42
+ )
43
+
44
+ pen = self._ANALYZER_PEN
45
+ pen.setWidth(2)
46
+ painter.setPen(pen)
47
+ signal_data_dict = self.component.signal_data()
48
+ for portname, signal_data in signal_data_dict.items():
49
+ signal_data = signal_data_dict[portname]
50
+ port_pos = self.get_port_pos(portname)
51
+ path = QPainterPath(
52
+ QPoint(
53
+ self.object_pos.x() + self.SIGNAL_NAME_WIDTH,
54
+ port_pos.y() - signal_data[0] * self._SIGNAL_VERTICAL_SCALE,
55
+ )
56
+ )
57
+ last_level = signal_data[0]
58
+ for idx, level in enumerate(signal_data[1:]):
59
+ if level == last_level:
60
+ continue
61
+ path.lineTo(
62
+ QPoint(
63
+ self.object_pos.x()
64
+ + self.SIGNAL_NAME_WIDTH
65
+ + (idx + 1) * self._SIGNAL_HORIZONTAL_SCALE,
66
+ port_pos.y() - last_level * self._SIGNAL_VERTICAL_SCALE,
67
+ )
68
+ )
69
+ path.lineTo(
70
+ QPoint(
71
+ self.object_pos.x()
72
+ + self.SIGNAL_NAME_WIDTH
73
+ + (idx + 1) * self._SIGNAL_HORIZONTAL_SCALE,
74
+ port_pos.y() - level * self._SIGNAL_VERTICAL_SCALE,
75
+ )
76
+ )
77
+ last_level = level
78
+ path.lineTo(
79
+ QPoint(
80
+ self.object_pos.x()
81
+ + self.SIGNAL_NAME_WIDTH
82
+ + len(signal_data) * self._SIGNAL_HORIZONTAL_SCALE,
83
+ port_pos.y() - last_level * self._SIGNAL_VERTICAL_SCALE,
84
+ )
85
+ )
86
+ painter.drawPath(path)
@@ -0,0 +1,131 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """A 7-segment component placed in the GUI"""
5
+
6
+ from PySide6.QtCore import QPoint, Qt
7
+ from PySide6.QtGui import QPainterPath
8
+
9
+ from ._component_object import ComponentObject
10
+
11
+
12
+ class SevenSegmentObject(ComponentObject):
13
+ """The class for a 7-segment component placed in the GUI"""
14
+
15
+ SEGMENT_TYPE_AND_POS = {
16
+ "A": ("H", QPoint(3, 0)),
17
+ "B": ("V", QPoint(31, 3)),
18
+ "C": ("V", QPoint(31, 33)),
19
+ "D": ("H", QPoint(3, 61)),
20
+ "E": ("V", QPoint(0, 33)),
21
+ "F": ("V", QPoint(0, 3)),
22
+ "G": ("H", QPoint(3, 31)),
23
+ }
24
+
25
+ SEGMENT_CORDS = {
26
+ "V": [
27
+ QPoint(3, 3),
28
+ QPoint(3, 20),
29
+ QPoint(0, 25),
30
+ QPoint(-3, 20),
31
+ QPoint(-3, 3),
32
+ QPoint(0, 0),
33
+ ],
34
+ "H": [
35
+ QPoint(3, 3),
36
+ QPoint(20, 3),
37
+ QPoint(25, 0),
38
+ QPoint(20, -3),
39
+ QPoint(3, -3),
40
+ QPoint(0, 0),
41
+ ],
42
+ }
43
+
44
+ PORT_TO_RECT_MARGIN = 5
45
+ RECT_TO_DIGIT_RECT_MARGIN = 5
46
+ DIGIT_RECT_TO_DIGIT_MARGIN = 10
47
+ DIGIT_WIDTH = 54
48
+ DIGIT_HEIGHT = 80
49
+
50
+ DOT_OFFSET_X = 40
51
+ DOT_OFFSET_Y = 60
52
+ DOT_RADIUS = 3
53
+
54
+ def __init__(self, app_model, component, xpos, ypos, port_distance=10):
55
+ super().__init__(app_model, component, xpos, ypos, port_distance=port_distance)
56
+ self.setup_size()
57
+
58
+ def setup_size(self):
59
+ """Setup the size of the component"""
60
+ str_pixels_w, _ = self.get_string_metrics("dot")
61
+ self.digit_left = self.inport_x_pos() + str_pixels_w + self.PORT_TO_RECT_MARGIN
62
+ self.width = self.digit_left + self.DIGIT_WIDTH + self.RECT_TO_DIGIT_RECT_MARGIN
63
+ self.update_ports()
64
+
65
+ def paint_component(self, painter):
66
+ self.paint_component_base(painter)
67
+ digit_ypos = self.height / 2 - self.DIGIT_HEIGHT / 2
68
+ self.paint_digit_rect(
69
+ painter, self.object_pos.x() + self.digit_left, self.object_pos.y() + digit_ypos
70
+ )
71
+ active_segments = self.component.segments()
72
+ self.draw_digit(
73
+ painter,
74
+ self.object_pos.x() + self.digit_left,
75
+ self.object_pos.y() + digit_ypos,
76
+ active_segments,
77
+ )
78
+
79
+ @classmethod
80
+ def paint_selectable_component(cls, painter, size, name):
81
+ cls.paint_selectable_digit(painter, size, name, "ADEFG")
82
+
83
+ @classmethod
84
+ def paint_selectable_digit(cls, painter, size, name, segments):
85
+ """Paint a digit (for selectable component in gui"""
86
+ xpos = size.width() / 2 - cls.DIGIT_WIDTH / 2
87
+ cls.paint_digit_rect(painter, xpos, 0)
88
+ cls.draw_digit(painter, xpos, 0, segments)
89
+ cls.paint_selectable_component_name(painter, QPoint(0, 0), size, name)
90
+
91
+ @classmethod
92
+ def paint_digit_rect(cls, painter, xpos, ypos, digits=1):
93
+ """Paint the digit background"""
94
+ painter.setBrush(Qt.SolidPattern)
95
+ painter.setPen(Qt.black)
96
+ painter.drawRoundedRect(xpos, ypos, cls.DIGIT_WIDTH * digits, cls.DIGIT_HEIGHT, 4, 4)
97
+
98
+ @classmethod
99
+ def draw_digit(cls, painter, xpos, ypos, active_segments):
100
+ """Paint the LED digit segments"""
101
+ start_point = QPoint(
102
+ xpos + cls.DIGIT_RECT_TO_DIGIT_MARGIN, ypos + cls.DIGIT_RECT_TO_DIGIT_MARGIN
103
+ )
104
+ for seg, type_pos in cls.SEGMENT_TYPE_AND_POS.items():
105
+ if seg in active_segments:
106
+ painter.setPen(Qt.red)
107
+ painter.setBrush(Qt.red)
108
+ else:
109
+ painter.setPen(Qt.darkRed)
110
+ painter.setBrush(Qt.darkRed)
111
+ pos_vector = cls.SEGMENT_CORDS[type_pos[0]]
112
+ offset = type_pos[1]
113
+ path = QPainterPath()
114
+ path.moveTo(offset + start_point)
115
+ for point in pos_vector:
116
+ path.lineTo(offset + point + start_point)
117
+ path.closeSubpath()
118
+ painter.drawPath(path)
119
+
120
+ DOT_OFFSET_X = 40
121
+ DOT_OFFSET_Y = 60
122
+ DOT_RADIUS = 3
123
+
124
+ if "." in active_segments:
125
+ painter.setPen(Qt.red)
126
+ painter.setBrush(Qt.red)
127
+ else:
128
+ painter.setPen(Qt.darkRed)
129
+ painter.setBrush(Qt.darkRed)
130
+ dotPoint = QPoint(DOT_OFFSET_X, DOT_OFFSET_Y) + start_point
131
+ painter.drawEllipse(dotPoint, DOT_RADIUS, DOT_RADIUS)
@@ -0,0 +1,82 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """A button component with an image as symbol the GUI"""
5
+
6
+ from functools import partial
7
+
8
+ from PySide6.QtCore import Qt
9
+ from PySide6.QtGui import QAction, QPen
10
+
11
+ from digsim.app.settings import ShortcutDialog
12
+
13
+ from ._image_objects import ImageObject, ImageObjectWithActiveRect
14
+
15
+
16
+ class _ShortcutObject:
17
+ """The class for a ShortcutObject component placed in the GUI"""
18
+
19
+ @classmethod
20
+ def add_context_menu_action(cls, menu, parent, app_model, component):
21
+ """Add context menu action"""
22
+ shortcutAction = QAction("Shortcut", menu)
23
+ menu.addAction(shortcutAction)
24
+ shortcutAction.triggered.connect(partial(cls._shortcut, parent, app_model, component))
25
+
26
+ @classmethod
27
+ def _shortcut(cls, parent, app_model, component):
28
+ shortcutDialog = ShortcutDialog(parent, app_model)
29
+ key = shortcutDialog.start()
30
+ if key is not None:
31
+ app_model.shortcuts.set_component(key, component)
32
+
33
+
34
+ class ButtonObject(ImageObject):
35
+ """The class for a PushButton image component placed in the GUI"""
36
+
37
+ IMAGE_FILENAME = "images/PB.png"
38
+ BUTTON_RADIUS = 35
39
+
40
+ _BUTTON_ACTIVE_PEN = QPen(Qt.green)
41
+
42
+ def __init__(self, app_model, component, xpos, ypos):
43
+ super().__init__(app_model, component, xpos, ypos)
44
+ self.show_name(False)
45
+ self.paint_port_names(False)
46
+
47
+ def paint_component(self, painter):
48
+ super().paint_component(painter)
49
+ if self.component.active:
50
+ pen = self._BUTTON_ACTIVE_PEN
51
+ pen.setWidth(4)
52
+ painter.setPen(pen)
53
+ painter.setBrush(Qt.NoBrush)
54
+ painter.drawEllipse(
55
+ self.object_pos.x() + self.width / 2 - self.BUTTON_RADIUS,
56
+ self.object_pos.y() + self.height / 2 - self.BUTTON_RADIUS,
57
+ self.BUTTON_RADIUS * 2,
58
+ self.BUTTON_RADIUS * 2,
59
+ )
60
+
61
+ def add_context_menu_action(self, menu, parent):
62
+ _ShortcutObject.add_context_menu_action(menu, parent, self._app_model, self._component)
63
+
64
+
65
+ class OnOffSwitchObject(ImageObjectWithActiveRect):
66
+ """The class for a On/Off-Switch image component placed in the GUI"""
67
+
68
+ IMAGE_FILENAME = "images/Switch_OFF.png"
69
+ ACTIVE_IMAGE_FILENAME = "images/Switch_ON.png"
70
+
71
+ def single_click_action(self):
72
+ self._toggle()
73
+
74
+ def add_context_menu_action(self, menu, parent):
75
+ _ShortcutObject.add_context_menu_action(menu, parent, self._app_model, self._component)
76
+ toggleAction = QAction("Toggle Switch", menu)
77
+ menu.addAction(toggleAction)
78
+ toggleAction.triggered.connect(self._toggle)
79
+
80
+ def _toggle(self):
81
+ self.component.toggle()
82
+ self.repaint()
@@ -0,0 +1,32 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """A yosys component with an image as symbol the GUI"""
5
+
6
+ from PySide6.QtGui import QAction
7
+
8
+ from digsim.circuit.components.atoms import DigsimException
9
+
10
+ from ._image_objects import ImageObject
11
+
12
+
13
+ class YosysObject(ImageObject):
14
+ """The class for a Yosys image component placed in the GUI"""
15
+
16
+ IMAGE_FILENAME = "images/YOSYS.png"
17
+
18
+ def paint_component(self, painter):
19
+ self.paint_component_base(painter)
20
+ self.paint_component_name(painter)
21
+
22
+ def add_context_menu_action(self, menu, parent):
23
+ reloadAction = QAction("Reload", menu)
24
+ menu.addAction(reloadAction)
25
+ reloadAction.triggered.connect(self._reload)
26
+
27
+ def _reload(self):
28
+ try:
29
+ self.component.reload_file()
30
+ except DigsimException as exc:
31
+ self._app_model.sig_warning_log.emit("Reload Yosys Warning", str(exc))
32
+ self._app_model.model_reset()
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,6 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """All classes within digsim.app.model namespace"""
5
+
6
+ from ._model import AppModel # noqa: F401