digsim-logic-simulator 0.6.0__py3-none-any.whl → 0.8.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.

@@ -1,8 +1,10 @@
1
- # Copyright (c) Fredrik Andersson, 2023-2024
1
+ # Copyright (c) Fredrik Andersson, 2023-2025
2
2
  # All rights reserved
3
3
 
4
4
  """This module contains the classes for all component ports"""
5
5
 
6
+ from __future__ import annotations
7
+
6
8
  import abc
7
9
 
8
10
  from ._digsim_exception import DigsimException
@@ -15,14 +17,14 @@ class PortConnectionError(DigsimException):
15
17
  class Port(abc.ABC):
16
18
  """The abstract base class for all ports"""
17
19
 
18
- def __init__(self, parent, name, width=1, output=False):
20
+ def __init__(self, parent, name: str, width: int = 1, output: bool = False):
19
21
  self._parent = parent # The parent component
20
- self._name = name # The name of this port
21
- self._width = width # The bit-width of this port
22
- self._output = output # Is this port an output port
23
- self._wired_ports = [] # The ports that this port drives
24
- self._value = None # The value of this port
25
- self._edge_detect_value = "X" # Last edge detect value
22
+ self._name: str = name # The name of this port
23
+ self._width: int = width # The bit-width of this port
24
+ self._output: bool = output # Is this port an output port
25
+ self._wired_ports: list[Port] = [] # The ports that this port drives
26
+ self._value: int | str | None = None # The value of this port
27
+ self._edge_detect_value: int | str | None = "X" # Last edge detect value
26
28
  self.init() # Initialize the port
27
29
 
28
30
  def init(self):
@@ -32,27 +34,27 @@ class Port(abc.ABC):
32
34
  self.update_wires("X")
33
35
 
34
36
  @property
35
- def wired_ports(self):
37
+ def wired_ports(self) -> list[Port]:
36
38
  """Get wires from thisport"""
37
39
  return self._wired_ports
38
40
 
39
41
  @property
40
- def value(self):
42
+ def value(self) -> int | str | None:
41
43
  """Get the value of the port, can be "X" """
42
44
  return self._value
43
45
 
44
46
  @value.setter
45
- def value(self, value):
47
+ def value(self, value: int | str | None):
46
48
  """Set the value of the port"""
47
49
  self.set_value(value)
48
50
 
49
51
  @property
50
- def width(self):
52
+ def width(self) -> int:
51
53
  """Get the bit-width of the port"""
52
54
  return self._width
53
55
 
54
56
  @width.setter
55
- def width(self, width):
57
+ def width(self, width: int):
56
58
  """Set the bit-width of the port, will force a disconnect if it is connected"""
57
59
  if width != self._width:
58
60
  driver = self.get_driver()
@@ -68,7 +70,7 @@ class Port(abc.ABC):
68
70
  raise PortConnectionError("Cannot get a wire")
69
71
 
70
72
  @wire.setter
71
- def wire(self, port):
73
+ def wire(self, port: PortWire):
72
74
  """Wire setter, connect this port to an input port (of same width)"""
73
75
  if port.has_driver():
74
76
  raise PortConnectionError(f"The port {port.path()}.{port.name()} already has a driver")
@@ -84,11 +86,11 @@ class Port(abc.ABC):
84
86
  port.set_driver(None)
85
87
  self._wired_ports = []
86
88
 
87
- def name(self):
89
+ def name(self) -> str:
88
90
  """Get port name"""
89
91
  return self._name
90
92
 
91
- def path(self):
93
+ def path(self) -> str:
92
94
  """Get port path, <component_name>...<component_name>"""
93
95
  return self._parent.path()
94
96
 
@@ -96,7 +98,7 @@ class Port(abc.ABC):
96
98
  """Get parent component"""
97
99
  return self._parent
98
100
 
99
- def update_wires(self, value):
101
+ def update_wires(self, value: int | str | None):
100
102
  """Update connected wires (and self._value) with value"""
101
103
  if self._value == value:
102
104
  return
@@ -104,26 +106,22 @@ class Port(abc.ABC):
104
106
  for port in self._wired_ports:
105
107
  port.value = self._value
106
108
 
107
- def get_wires(self):
108
- """Get connected ports"""
109
- return self._wired_ports
110
-
111
- def get_wired_ports_recursive(self):
109
+ def get_wired_ports_recursive(self) -> list[Port]:
112
110
  """Get all connected ports (recursive)"""
113
111
  all_wired_ports = [self]
114
112
  for port in self._wired_ports:
115
113
  all_wired_ports.extend(port.get_wired_ports_recursive())
116
114
  return all_wired_ports
117
115
 
118
- def is_output(self):
116
+ def is_output(self) -> bool:
119
117
  """Return True if this port is an output port"""
120
118
  return self._output
121
119
 
122
- def is_input(self):
120
+ def is_input(self) -> bool:
123
121
  """Return True if this port is an input port"""
124
122
  return not self._output
125
123
 
126
- def is_rising_edge(self):
124
+ def is_rising_edge(self) -> bool:
127
125
  """
128
126
  Return True if a rising edge has occured
129
127
  Note: This function can only be called once per 'update'
@@ -134,7 +132,7 @@ class Port(abc.ABC):
134
132
  self._edge_detect_value = self.value
135
133
  return rising_edge
136
134
 
137
- def is_falling_edge(self):
135
+ def is_falling_edge(self) -> bool:
138
136
  """
139
137
  Return True if a falling edge has occured
140
138
  Note: This function can only be called once per 'update'
@@ -146,14 +144,21 @@ class Port(abc.ABC):
146
144
  return falling_edge
147
145
 
148
146
  @abc.abstractmethod
149
- def set_value(self, value):
147
+ def set_value(self, value: int | str | None):
150
148
  """Set value on port"""
151
149
 
152
150
  @abc.abstractmethod
153
- def set_driver(self, port):
151
+ def set_driver(self, port: Port | None):
154
152
  """Set port driver"""
155
153
 
156
- def can_add_wire(self):
154
+ @abc.abstractmethod
155
+ def has_driver(self) -> bool:
156
+ """Return True if port has driver"""
157
+
158
+ def get_driver(self):
159
+ """Get port driver"""
160
+
161
+ def can_add_wire(self) -> bool:
157
162
  """Return True if it is possible to add a wire to this port"""
158
163
  if self.is_output():
159
164
  return True
@@ -161,14 +166,14 @@ class Port(abc.ABC):
161
166
  return True
162
167
  return False
163
168
 
164
- def disconnect(self, port):
169
+ def disconnect(self, port: Port):
165
170
  """Disconnect port if it is wired"""
166
171
  if port in self._wired_ports:
167
172
  index = self._wired_ports.index(port)
168
173
  del self._wired_ports[index]
169
174
  port.set_driver(None)
170
175
 
171
- def strval(self):
176
+ def strval(self) -> str:
172
177
  """Return value as string"""
173
178
  if self.value == "X":
174
179
  return "X"
@@ -176,7 +181,7 @@ class Port(abc.ABC):
176
181
  return f"0x{self.value:x}"
177
182
  return f"{self.value}"
178
183
 
179
- def __str__(self):
184
+ def __str__(self) -> str:
180
185
  return f"{self._parent.name()}:{self._name}={self.value}"
181
186
 
182
187
 
@@ -186,22 +191,22 @@ class PortWire(Port):
186
191
  * The port wire will instantaneously update the driven wires upon change.
187
192
  """
188
193
 
189
- def __init__(self, parent, name, width=1, output=False):
194
+ def __init__(self, parent, name: str, width: int = 1, output: bool = False):
190
195
  super().__init__(parent, name, width, output)
191
- self._port_driver = None # The port that drives this port
196
+ self._port_driver: Port | None = None # The port that drives this port
192
197
 
193
- def set_value(self, value):
198
+ def set_value(self, value: int | str | None):
194
199
  if value != self.value:
195
200
  self.update_wires(value)
196
201
 
197
- def set_driver(self, port):
202
+ def set_driver(self, port: Port | None):
198
203
  self._port_driver = port
199
204
 
200
- def get_driver(self):
205
+ def get_driver(self) -> Port | None:
201
206
  """Get driver for port"""
202
207
  return self._port_driver
203
208
 
204
- def has_driver(self):
209
+ def has_driver(self) -> bool:
205
210
  """Return True if port has driver"""
206
211
  return self._port_driver is not None
207
212
 
@@ -213,10 +218,10 @@ class PortIn(PortWire):
213
218
  * The port will update the parent component upon change.
214
219
  """
215
220
 
216
- def __init__(self, parent, name, width=1):
221
+ def __init__(self, parent, name: str, width: int = 1):
217
222
  super().__init__(parent, name, width, output=False)
218
223
 
219
- def set_value(self, value):
224
+ def set_value(self, value: int | str | None):
220
225
  super().set_value(value)
221
226
  self.parent().update()
222
227
 
@@ -228,40 +233,40 @@ class PortOutDelta(Port):
228
233
  * The port will update the parent component if the _update_parent variable is set to true.
229
234
  """
230
235
 
231
- def __init__(self, parent, name, width=1, delay_ns=1):
236
+ def __init__(self, parent, name: str, width: int = 1, delay_ns: int = 1):
232
237
  super().__init__(parent, name, width, output=True)
233
238
  self._delay_ns = delay_ns # Propagation delay for this port
234
239
  self._update_parent = False # Should this port update parent on change
235
240
 
236
- def update_parent(self, update_parent):
241
+ def update_parent(self, update_parent: bool):
237
242
  """Set update parent valiable (True/False)"""
238
243
  self._update_parent = update_parent
239
244
 
240
- def set_delay_ns(self, delay_ns):
245
+ def set_delay_ns(self, delay_ns: int):
241
246
  """Set port propagation delay"""
242
247
  self._delay_ns = delay_ns
243
248
 
244
- def set_value(self, value):
249
+ def set_value(self, value: int | str | None):
245
250
  self.parent().add_event(self, value, self._delay_ns)
246
251
 
247
- def update_port(self, value):
252
+ def update_port(self, value: int | str | None):
248
253
  """Update the port output and the connected wires"""
249
254
  self.update_wires(value)
250
255
  if self._update_parent:
251
256
  self.parent().update()
252
257
 
253
- def delta_cycle(self, value):
258
+ def delta_cycle(self, value: int | str | None):
254
259
  """Handle the delta cycle event from the circuit"""
255
260
  self.update_port(value)
256
261
 
257
- def set_driver(self, port):
262
+ def set_driver(self, port: Port | None):
258
263
  raise PortConnectionError(f"The port {self.path()}.{self.name()} cannot be driven")
259
264
 
260
- def get_driver(self):
265
+ def get_driver(self) -> Port | None:
261
266
  """Get driver for port, the output port has no driver"""
262
267
  return None
263
268
 
264
- def has_driver(self):
269
+ def has_driver(self) -> bool:
265
270
  """Return False since the port does not have a driver"""
266
271
  return False
267
272
 
@@ -274,14 +279,14 @@ class PortOutImmediate(PortOutDelta):
274
279
  * The port will update the parent component if the _update_parent variable is set to true.
275
280
  """
276
281
 
277
- def __init__(self, parent, name, width=1):
282
+ def __init__(self, parent, name: str, width: int = 1):
278
283
  super().__init__(parent, name, width)
279
284
 
280
- def set_value(self, value):
285
+ def set_value(self, value: int | str | None):
281
286
  self.parent().add_event(self, value, 0)
282
287
  super().update_port(value)
283
288
 
284
- def delta_cycle(self, value):
289
+ def delta_cycle(self, value: int | str | None):
285
290
  """
286
291
  Do nothing here, the event is just used to updates waves in Circuit class
287
292
  """
@@ -294,15 +299,15 @@ class PortWireBit(PortWire):
294
299
  The PortWireBit will update its parent (a PortMultiBitWire) upon change.
295
300
  """
296
301
 
297
- def __init__(self, parent, name, parent_port, output):
302
+ def __init__(self, parent, name: str, parent_port: PortMultiBitWire, output: bool):
298
303
  super().__init__(parent, name, 1, output)
299
304
  self._parent_port = parent_port
300
305
 
301
- def set_value(self, value):
306
+ def set_value(self, value: int | str | None):
302
307
  super().set_value(value)
303
308
  self._parent_port.update_value_from_bits()
304
309
 
305
- def get_parent_port(self):
310
+ def get_parent_port(self) -> PortMultiBitWire:
306
311
  """Get the parent PortMultiBitWire for this port"""
307
312
  return self._parent_port
308
313
 
@@ -314,8 +319,8 @@ class PortMultiBitWire(Port):
314
319
  The PortWireMultiBit will add events to the circuit upon change to update vcd output.
315
320
  """
316
321
 
317
- def __init__(self, parent, name, width, output=False):
318
- self._port_driver = None # The port that drives this port
322
+ def __init__(self, parent, name: str, width: int, output: bool = False):
323
+ self._port_driver: Port | None = None # The port that drives this port
319
324
  self._bits = []
320
325
  super().__init__(parent, name, width, output)
321
326
  for bit_id in range(self.width):
@@ -328,32 +333,32 @@ class PortMultiBitWire(Port):
328
333
  for bit in self._bits:
329
334
  bit.init()
330
335
 
331
- def set_value(self, value):
332
- if value == "X":
336
+ def set_value(self, value: int | str | None):
337
+ if value is None or isinstance(value, str):
333
338
  return
334
339
  for bit_id, bit in enumerate(self._bits):
335
340
  bit_val = (value >> bit_id) & 1
336
341
  bit.value = bit_val
337
342
 
338
- def get_wired_ports_recursive(self):
343
+ def get_wired_ports_recursive(self) -> list[Port]:
339
344
  all_wired_ports = super().get_wired_ports_recursive()
340
345
  for bit in self._bits:
341
346
  all_wired_ports.extend(bit.get_wired_ports_recursive())
342
347
  return all_wired_ports
343
348
 
344
- def set_driver(self, port):
349
+ def set_driver(self, port: Port | None):
345
350
  """Set port driver"""
346
351
  self._port_driver = port
347
352
 
348
- def get_driver(self):
353
+ def get_driver(self) -> Port | None:
349
354
  """Get port driver"""
350
355
  return self._port_driver
351
356
 
352
- def has_driver(self):
357
+ def has_driver(self) -> bool:
353
358
  """Return True if port has driver"""
354
359
  return self._port_driver is not None
355
360
 
356
- def get_bit(self, bit_id):
361
+ def get_bit(self, bit_id: int) -> Port:
357
362
  """Get bit port"""
358
363
  return self._bits[bit_id]
359
364
 
@@ -370,7 +375,7 @@ class PortMultiBitWire(Port):
370
375
  # Send event just to update waves
371
376
  self.parent().add_event(self, value, 0)
372
377
 
373
- def delta_cycle(self, value):
378
+ def delta_cycle(self, value: int | str | None):
374
379
  """
375
380
  Do nothing here, the event passed in 'update_value_from_bits'
376
381
  is just used to updates waves in Circuit class