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,18 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """Module with the LED component"""
5
+
6
+ from .atoms import CallbackComponent, PortIn
7
+
8
+
9
+ class Led(CallbackComponent):
10
+ """LED component class"""
11
+
12
+ def __init__(self, circuit, name=None, callback=None):
13
+ super().__init__(circuit, name, callback)
14
+ self.add_port(PortIn(self, "I"))
15
+
16
+ @property
17
+ def active(self):
18
+ return self.I.has_driver() and self.I.value == 1
@@ -0,0 +1,60 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """Module with Logic Analyzer component"""
5
+
6
+ from .atoms import CallbackComponent, PortOutDelta, PortWire
7
+
8
+
9
+ class LogicAnalyzer(CallbackComponent):
10
+ """Logic Analyzer component class"""
11
+
12
+ PORTLIST = ["A", "B", "C", "D", "E", "F", "G", "H"]
13
+
14
+ def __init__(self, circuit, name=None, sample_rate=100):
15
+ super().__init__(circuit, name)
16
+ self.data_dict = {}
17
+ for portname in self.PORTLIST:
18
+ self.add_port(PortWire(self, portname))
19
+ self.data_dict[portname] = [0] * 100
20
+ self._feedback = PortOutDelta(self, "feedback")
21
+ self._feedback.update_parent(True)
22
+ self.parameter_set("sample_rate", sample_rate)
23
+ self.reconfigure()
24
+
25
+ def default_state(self):
26
+ self._feedback.value = 1
27
+
28
+ def update(self):
29
+ if self._feedback.value == 1:
30
+ self._feedback.value = 0
31
+ else:
32
+ self._feedback.value = 1
33
+
34
+ for portname in self.PORTLIST:
35
+ self.data_dict[portname].pop(0)
36
+ value = 1 if self.port(portname).value == 1 else 0
37
+ self.data_dict[portname].append(value)
38
+ super().update()
39
+
40
+ def reconfigure(self):
41
+ sample_rate = self.parameter_get("sample_rate")
42
+ period_ns = int(1000000000 / sample_rate)
43
+ self._feedback.set_delay_ns(period_ns)
44
+
45
+ def signal_data(self):
46
+ """Get the logic analyzer signal data"""
47
+ return self.data_dict
48
+
49
+ @classmethod
50
+ def get_parameters(cls):
51
+ return {
52
+ "sample_rate": {
53
+ "type": "int",
54
+ "min": 10,
55
+ "max": 100,
56
+ "default": 20,
57
+ "description": "Sample rate in Hz",
58
+ "reconfigurable": True,
59
+ },
60
+ }
@@ -0,0 +1,42 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """
5
+ This module implements a 64kByte synchronous memory
6
+ with 8-bit memory bus and 16-bit address bus.
7
+ It cam be prefilled with binary data from 'rom_filename'
8
+ starting at 'rom_address'.
9
+ """
10
+
11
+ from digsim.circuit.components.atoms import Component, PortIn, PortOutDelta, PortWire
12
+
13
+
14
+ class Mem64kByte(Component):
15
+ """64kByte synchronous memory class"""
16
+
17
+ def __init__(self, circuit, rom_filename=None, rom_address=0):
18
+ super().__init__(circuit, "Memory")
19
+ self.add_port(PortIn(self, "clk"))
20
+ self.add_port(PortWire(self, "Address", width=16))
21
+ self.add_port(PortWire(self, "DataIn", width=8))
22
+ self.add_port(PortWire(self, "WE"))
23
+ self.add_port(PortOutDelta(self, "DataOut", width=8))
24
+ self._mem_array = [0] * 65536
25
+ if rom_filename is not None:
26
+ with open(rom_filename, mode="rb") as rom:
27
+ romdata = rom.read()
28
+ for idx, byte in enumerate(romdata):
29
+ self._mem_array[rom_address + idx] = byte
30
+
31
+ def update(self):
32
+ rising_edge = self.clk.is_rising_edge()
33
+ if not rising_edge or self.Address.value == "X":
34
+ return
35
+ addr = self.Address.value
36
+ we = self.WE.value
37
+ if we == 1:
38
+ datain = self.DataIn.value
39
+ self._mem_array[addr] = datain
40
+ else:
41
+ dataout = self._mem_array[addr]
42
+ self.DataOut.value = dataout
@@ -0,0 +1,37 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """
5
+ This module implements a synchronous memory mapped stdout output
6
+ with 8-bit memory bus and 16-bit address bus.
7
+ The address is listens to can be changed with the 'address' parameter.
8
+ """
9
+
10
+ from digsim.circuit.components.atoms import Component, PortIn, PortWire
11
+
12
+
13
+ class MemStdOut(Component):
14
+ """Synchronous memory mapped stdout class"""
15
+
16
+ def __init__(self, circuit, address=0x8000):
17
+ super().__init__(circuit, "MemStdOut")
18
+ self._address = address
19
+ self.add_port(PortIn(self, "clk"))
20
+ self.add_port(PortWire(self, "Address", width=16))
21
+ self.add_port(PortWire(self, "DataIn", width=8))
22
+ self.add_port(PortWire(self, "WE"))
23
+ self._str = ""
24
+
25
+ def update(self):
26
+ rising_edge = self.clk.is_rising_edge()
27
+ if self.WE.value == 0 or self.Address.value != self._address:
28
+ return
29
+ if rising_edge:
30
+ datain = self.DataIn.value
31
+ if datain == 0x0A:
32
+ print(f"StringOutput [line]: '{self._str}'")
33
+ self._str = ""
34
+ else:
35
+ inchar = chr(datain)
36
+ print(f"StringOutput [char]: '{inchar}'")
37
+ self._str += inchar
@@ -0,0 +1,25 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """Components that only exist in the model"""
5
+
6
+ from .atoms import Component
7
+
8
+
9
+ class Note(Component):
10
+ """Note component"""
11
+
12
+ def __init__(self, circuit, name=None, text=""):
13
+ super().__init__(circuit, name)
14
+ self.parameter_set("text", text)
15
+
16
+ @classmethod
17
+ def get_parameters(cls):
18
+ return {
19
+ "text": {
20
+ "type": "str",
21
+ "default": "Write something here...",
22
+ "description": "Note text",
23
+ "reconfigurable": True,
24
+ },
25
+ }
@@ -0,0 +1,54 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """An On/Off Switch component"""
5
+
6
+ import logging
7
+
8
+ from .atoms import CallbackComponent, PortOutDelta
9
+
10
+
11
+ class OnOffSwitch(CallbackComponent):
12
+ """On/Off Switch component class"""
13
+
14
+ def __init__(self, circuit, name=None, start_on=False):
15
+ super().__init__(circuit, name)
16
+ portout = PortOutDelta(self, "O", delay_ns=0)
17
+ self.add_port(portout)
18
+ portout.update_parent(True)
19
+ self._on = False
20
+ if start_on:
21
+ logging.warning("Setting 'start_on' has been removed")
22
+
23
+ def _set(self, state):
24
+ self._on = state
25
+ self.O.value = 1 if state else 0
26
+
27
+ def default_state(self):
28
+ self._set(False)
29
+
30
+ self.turn_off()
31
+
32
+ def turn_on(self):
33
+ """Turn on the switch"""
34
+ self.O.value = 1
35
+ self._on = True
36
+
37
+ def turn_off(self):
38
+ """Turn off the switch"""
39
+ self._set(False)
40
+
41
+ def toggle(self):
42
+ """Toggle the switch"""
43
+ self._set(not self._on)
44
+
45
+ def onpress(self):
46
+ self.toggle()
47
+
48
+ @property
49
+ def has_action(self):
50
+ return True
51
+
52
+ @property
53
+ def active(self):
54
+ return self._on
@@ -0,0 +1,28 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """Module with 7-segment LED component"""
5
+
6
+ from .atoms import CallbackComponent, PortIn
7
+
8
+
9
+ class SevenSegment(CallbackComponent):
10
+ """7-segment LED component class"""
11
+
12
+ PORTLIST = ["A", "B", "C", "D", "E", "F", "G", "dot"]
13
+
14
+ def __init__(self, circuit, name=None):
15
+ super().__init__(circuit, name)
16
+ for portname in self.PORTLIST:
17
+ self.add_port(PortIn(self, portname))
18
+
19
+ def segments(self):
20
+ """Get the active segments"""
21
+ segments = ""
22
+ for portname in self.PORTLIST:
23
+ if self.port(portname).value == 1:
24
+ if portname == "dot":
25
+ segments += "."
26
+ else:
27
+ segments += portname
28
+ return segments
@@ -0,0 +1,28 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """Module with the Static Logic components"""
5
+
6
+ from .atoms import Component, PortOutDelta
7
+
8
+
9
+ class VDD(Component):
10
+ """VDD / Logic1 component class"""
11
+
12
+ def __init__(self, circuit, name=None):
13
+ super().__init__(circuit, name)
14
+ self.add_port(PortOutDelta(self, "O", delay_ns=0))
15
+
16
+ def default_state(self):
17
+ self.O.value = 1
18
+
19
+
20
+ class GND(Component):
21
+ """GND / Logic0 component class"""
22
+
23
+ def __init__(self, circuit, name=None):
24
+ super().__init__(circuit, name)
25
+ self.add_port(PortOutDelta(self, "O", delay_ns=0))
26
+
27
+ def default_state(self):
28
+ self.O.value = 0
@@ -0,0 +1,44 @@
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
+ # All rights reserved
3
+
4
+ """Module with the Static Leve component"""
5
+
6
+ from .atoms import Component, PortOutImmediate
7
+
8
+
9
+ class StaticValue(Component):
10
+ """Static value component class"""
11
+
12
+ def __init__(self, circuit, name=None, width=1, value=0):
13
+ super().__init__(circuit, name)
14
+ self.parameter_set("width", width)
15
+ self.parameter_set("value", value)
16
+ self.add_port(PortOutImmediate(self, "O", width=width))
17
+
18
+ def default_state(self):
19
+ self.O.value = self.parameter_get("value")
20
+
21
+ def reconfigure(self):
22
+ self.O.value = self.parameter_get("value")
23
+
24
+ @property
25
+ def active(self):
26
+ return self.parameter_get("width") == 1 and self.parameter_get("value") == 1
27
+
28
+ @classmethod
29
+ def get_parameters(cls):
30
+ return {
31
+ "value": {
32
+ "type": "width_pow2",
33
+ "default": 0,
34
+ "description": "Static value",
35
+ "reconfigurable": True,
36
+ },
37
+ "width": {
38
+ "type": "int",
39
+ "min": 1,
40
+ "max": 16,
41
+ "default": 1,
42
+ "description": "Static value bitwidth",
43
+ },
44
+ }