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.
- digsim/__init__.py +6 -0
- digsim/app/__main__.py +12 -0
- digsim/app/cli.py +68 -0
- digsim/app/gui/__init__.py +6 -0
- digsim/app/gui/_circuit_area.py +468 -0
- digsim/app/gui/_component_selection.py +154 -0
- digsim/app/gui/_main_window.py +163 -0
- digsim/app/gui/_top_bar.py +339 -0
- digsim/app/gui/_utils.py +26 -0
- digsim/app/gui/_warning_dialog.py +46 -0
- digsim/app/gui_objects/__init__.py +7 -0
- digsim/app/gui_objects/_bus_bit_object.py +94 -0
- digsim/app/gui_objects/_buzzer_object.py +97 -0
- digsim/app/gui_objects/_component_context_menu.py +79 -0
- digsim/app/gui_objects/_component_object.py +374 -0
- digsim/app/gui_objects/_component_port_item.py +63 -0
- digsim/app/gui_objects/_dip_switch_object.py +104 -0
- digsim/app/gui_objects/_gui_note_object.py +80 -0
- digsim/app/gui_objects/_gui_object_factory.py +80 -0
- digsim/app/gui_objects/_hexdigit_object.py +53 -0
- digsim/app/gui_objects/_image_objects.py +239 -0
- digsim/app/gui_objects/_label_object.py +97 -0
- digsim/app/gui_objects/_logic_analyzer_object.py +86 -0
- digsim/app/gui_objects/_seven_segment_object.py +131 -0
- digsim/app/gui_objects/_shortcut_objects.py +82 -0
- digsim/app/gui_objects/_yosys_object.py +32 -0
- digsim/app/gui_objects/images/AND.png +0 -0
- digsim/app/gui_objects/images/Analyzer.png +0 -0
- digsim/app/gui_objects/images/BUF.png +0 -0
- digsim/app/gui_objects/images/Buzzer.png +0 -0
- digsim/app/gui_objects/images/Clock.png +0 -0
- digsim/app/gui_objects/images/DFF.png +0 -0
- digsim/app/gui_objects/images/DIP_SWITCH.png +0 -0
- digsim/app/gui_objects/images/FlipFlop.png +0 -0
- digsim/app/gui_objects/images/IC.png +0 -0
- digsim/app/gui_objects/images/LED_OFF.png +0 -0
- digsim/app/gui_objects/images/LED_ON.png +0 -0
- digsim/app/gui_objects/images/MUX.png +0 -0
- digsim/app/gui_objects/images/NAND.png +0 -0
- digsim/app/gui_objects/images/NOR.png +0 -0
- digsim/app/gui_objects/images/NOT.png +0 -0
- digsim/app/gui_objects/images/ONE.png +0 -0
- digsim/app/gui_objects/images/OR.png +0 -0
- digsim/app/gui_objects/images/PB.png +0 -0
- digsim/app/gui_objects/images/Switch_OFF.png +0 -0
- digsim/app/gui_objects/images/Switch_ON.png +0 -0
- digsim/app/gui_objects/images/XNOR.png +0 -0
- digsim/app/gui_objects/images/XOR.png +0 -0
- digsim/app/gui_objects/images/YOSYS.png +0 -0
- digsim/app/gui_objects/images/ZERO.png +0 -0
- digsim/app/images/app_icon.png +0 -0
- digsim/app/model/__init__.py +6 -0
- digsim/app/model/_model.py +210 -0
- digsim/app/model/_model_components.py +162 -0
- digsim/app/model/_model_new_wire.py +57 -0
- digsim/app/model/_model_objects.py +155 -0
- digsim/app/model/_model_settings.py +35 -0
- digsim/app/model/_model_shortcuts.py +72 -0
- digsim/app/settings/__init__.py +8 -0
- digsim/app/settings/_component_settings.py +415 -0
- digsim/app/settings/_gui_settings.py +71 -0
- digsim/app/settings/_shortcut_dialog.py +39 -0
- digsim/circuit/__init__.py +7 -0
- digsim/circuit/_circuit.py +329 -0
- digsim/circuit/_waves_writer.py +61 -0
- digsim/circuit/components/__init__.py +26 -0
- digsim/circuit/components/_bus_bits.py +68 -0
- digsim/circuit/components/_button.py +44 -0
- digsim/circuit/components/_buzzer.py +45 -0
- digsim/circuit/components/_clock.py +54 -0
- digsim/circuit/components/_dip_switch.py +73 -0
- digsim/circuit/components/_flip_flops.py +99 -0
- digsim/circuit/components/_gates.py +246 -0
- digsim/circuit/components/_hexdigit.py +82 -0
- digsim/circuit/components/_ic.py +36 -0
- digsim/circuit/components/_label_wire.py +167 -0
- digsim/circuit/components/_led.py +18 -0
- digsim/circuit/components/_logic_analyzer.py +60 -0
- digsim/circuit/components/_mem64kbyte.py +42 -0
- digsim/circuit/components/_memstdout.py +37 -0
- digsim/circuit/components/_note.py +25 -0
- digsim/circuit/components/_on_off_switch.py +54 -0
- digsim/circuit/components/_seven_segment.py +28 -0
- digsim/circuit/components/_static_level.py +28 -0
- digsim/circuit/components/_static_value.py +44 -0
- digsim/circuit/components/_yosys_atoms.py +1353 -0
- digsim/circuit/components/_yosys_component.py +232 -0
- digsim/circuit/components/atoms/__init__.py +23 -0
- digsim/circuit/components/atoms/_component.py +280 -0
- digsim/circuit/components/atoms/_digsim_exception.py +8 -0
- digsim/circuit/components/atoms/_port.py +398 -0
- digsim/circuit/components/ic/74162.json +1331 -0
- digsim/circuit/components/ic/7448.json +834 -0
- digsim/storage_model/__init__.py +7 -0
- digsim/storage_model/_app.py +58 -0
- digsim/storage_model/_circuit.py +126 -0
- digsim/synth/__init__.py +6 -0
- digsim/synth/__main__.py +67 -0
- digsim/synth/_synthesis.py +156 -0
- digsim/utils/__init__.py +6 -0
- digsim/utils/_yosys_netlist.py +134 -0
- digsim_logic_simulator-0.22.0.dist-info/METADATA +140 -0
- digsim_logic_simulator-0.22.0.dist-info/RECORD +107 -0
- digsim_logic_simulator-0.22.0.dist-info/WHEEL +5 -0
- digsim_logic_simulator-0.22.0.dist-info/entry_points.txt +2 -0
- digsim_logic_simulator-0.22.0.dist-info/licenses/LICENSE.md +32 -0
- 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
|
+
}
|