Newer
Older
Angus Lothian
committed
Contains operations with special purposes that may be treated differently from
normal operations in an SFG.
"""
from numbers import Number
Angus Lothian
committed
from b_asic.graph_component import Name, TypeName
from b_asic.operation import (
AbstractOperation,
DelayMap,
MutableDelayMap,
MutableResultMap,
)
Angus Lothian
committed
from b_asic.port import SignalSourceProvider
class Input(AbstractOperation):
Angus Lothian
committed
Marks an input port to an SFG.
Its value will be updated on each iteration when simulating the SFG.
"""
Angus Lothian
committed
"""Construct an Input operation."""
super().__init__(
input_count=0,
output_count=1,
Angus Lothian
committed
self.set_param("value", 0)
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
def evaluate(self):
return self.param("value")
@property
def value(self) -> Number:
"""Get the current value of this input."""
return self.param("value")
@value.setter
def value(self, value: Number) -> None:
"""Set the current value of this input."""
self.set_param("value", value)
) -> Tuple[
Tuple[Tuple[float, float], ...], Tuple[Tuple[float, float], ...]
]:
(
(-0.5, 0),
(-0.5, 1),
(-0.25, 1),
(0, 0.5),
(-0.25, 0),
(-0.5, 0),
),
(
(-0.5, 0),
(-0.5, 1),
(-0.25, 1),
(0, 0.5),
(-0.25, 0),
(-0.5, 0),
),
def get_input_coordinates(self) -> Tuple[Tuple[float, float], ...]:
# doc-string inherited
return tuple()
def get_output_coordinates(self) -> Tuple[Tuple[float, float], ...]:
# doc-string inherited
return ((0, 0.5),)
Angus Lothian
committed
class Output(AbstractOperation):
Angus Lothian
committed
Marks an output port to an SFG.
The SFG will forward its input to the corresponding output signal
destinations.
"""
self,
src0: Optional[SignalSourceProvider] = None,
name: Name = Name(""),
Angus Lothian
committed
"""Construct an Output operation."""
super().__init__(
input_count=1,
output_count=0,
input_sources=[src0],
latency_offsets={"in0": 0},
)
Angus Lothian
committed
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
def evaluate(self, _):
return None
) -> Tuple[
Tuple[Tuple[float, float], ...], Tuple[Tuple[float, float], ...]
]:
((0, 0), (0, 1), (0.25, 1), (0.5, 0.5), (0.25, 0), (0, 0)),
((0, 0), (0, 1), (0.25, 1), (0.5, 0.5), (0.25, 0), (0, 0)),
def get_input_coordinates(self) -> Tuple[Tuple[float, float], ...]:
# doc-string inherited
return ((0, 0.5),)
def get_output_coordinates(self) -> Tuple[Tuple[float, float], ...]:
# doc-string inherited
return tuple()
Angus Lothian
committed
class Delay(AbstractOperation):
Angus Lothian
committed
Represents one unit of delay in a circuit, typically a clock cycle.
Can be thought of as a register or a D flip-flop.
"""
def __init__(
self,
src0: Optional[SignalSourceProvider] = None,
initial_value: Number = 0,
Angus Lothian
committed
"""Construct a Delay operation."""
input_count=1,
output_count=1,
name=Name(name),
input_sources=[src0],
Angus Lothian
committed
self.set_param("initial_value", initial_value)
@classmethod
def type_name(cls) -> TypeName:
Angus Lothian
committed
def evaluate(self, a):
return self.param("initial_value")
def current_output(
self, index: int, delays: Optional[DelayMap] = None, prefix: str = ""
) -> Optional[Number]:
Angus Lothian
committed
if delays is not None:
return delays.get(
self.key(index, prefix), self.param("initial_value")
)
Angus Lothian
committed
return self.param("initial_value")
def evaluate_output(
self,
index: int,
input_values: Sequence[Number],
results: Optional[MutableResultMap] = None,
delays: Optional[MutableDelayMap] = None,
prefix: str = "",
bits_override: Optional[int] = None,
truncate: bool = True,
) -> Number:
Angus Lothian
committed
if index != 0:
raise IndexError(
f"Output index out of range (expected 0-0, got {index})"
)
Angus Lothian
committed
if len(input_values) != 1:
raise ValueError(
"Wrong number of inputs supplied to SFG for evaluation"
f" (expected 1, got {len(input_values)})"
)
Angus Lothian
committed
key = self.key(index, prefix)
value = self.param("initial_value")
if delays is not None:
value = delays.get(key, value)
delays[key] = (
self.truncate_inputs(input_values, bits_override)[0]
if truncate
else input_values[0]
)
Angus Lothian
committed
if results is not None:
results[key] = value
return value
@property
def initial_value(self) -> Number:
"""Get the initial value of this delay."""
return self.param("initial_value")
@initial_value.setter
def initial_value(self, value: Number) -> None:
"""Set the initial value of this delay."""
self.set_param("initial_value", value)