diff --git a/edg/abstract_parts/Capacitor.py b/edg/abstract_parts/Capacitor.py index 81878526e..4f89f65d5 100644 --- a/edg/abstract_parts/Capacitor.py +++ b/edg/abstract_parts/Capacitor.py @@ -323,11 +323,12 @@ def add_derated_row(row: PartsTableRow) -> Optional[Dict[PartsTableColumn, Any]] def _row_generate(self, row: PartsTableRow) -> None: """This one is weird. Because this is the last in the class order, this is called last. So the top subclass needs explicit logic to handle parallel capacitors.""" - super()._row_generate(row) + PartsTableSelector._row_generate(self, row) # ignore Capacitor _row_generate if row[self.PARALLEL_COUNT] == 1: + self.assign(self.actual_voltage_rating, row[self.VOLTAGE_RATING]) + self.assign(self.actual_capacitance, row[self.CAPACITANCE]) self.assign(self.actual_derated_capacitance, row[self.DERATED_CAPACITANCE]) else: - self.assign(self.actual_part, f"{row[self.PARALLEL_COUNT]}x {row[self.PART_NUMBER_COL]}") self.assign(self.actual_voltage_rating, row[self.VOLTAGE_RATING]) self.assign(self.actual_capacitance, row[self.PARALLEL_CAPACITANCE]) self.assign(self.actual_derated_capacitance, row[self.PARALLEL_DERATED_CAPACITANCE]) @@ -338,7 +339,7 @@ def _make_parallel_footprints(self, row: PartsTableRow) -> None: ... -class DummyCapacitorFootprint(DummyDevice, Capacitor, FootprintBlock): +class DummyCapacitorFootprint(Capacitor, DummyDevice, FootprintBlock): """Dummy capacitor that takes in all its parameters (footprint, value, etc) and does not do any computation. Used as the leaf block for generating parallel capacitors. diff --git a/edg/abstract_parts/Connectors.py b/edg/abstract_parts/Connectors.py index 8d07f565a..461605fd1 100644 --- a/edg/abstract_parts/Connectors.py +++ b/edg/abstract_parts/Connectors.py @@ -46,6 +46,10 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.connect(self.conn.sig, self.a) self.connect(self.conn.gnd, self.gnd) + self.assign(self.actual_frequency_rating, (0, float("inf") * Henry)) + self.assign(self.actual_impedance, (0, float("inf") * Ohm)) + self.assign(self.actual_power_rating, (0, float("inf") * Watt)) + @abstract_block class UflConnector(RfConnector): diff --git a/edg/abstract_parts/IdealIoController.py b/edg/abstract_parts/IdealIoController.py index 9ee1479a4..5228e74e1 100644 --- a/edg/abstract_parts/IdealIoController.py +++ b/edg/abstract_parts/IdealIoController.py @@ -102,3 +102,4 @@ def generate(self) -> None: self.i2s.append_elt(I2sController(dio_model), elt) self.assign(self.pwr.current_draw, io_current_draw_builder) + self.assign(self.actual_pin_assigns, []) diff --git a/edg/abstract_parts/Neopixel.py b/edg/abstract_parts/Neopixel.py index 4d85ed899..3b6d0739a 100644 --- a/edg/abstract_parts/Neopixel.py +++ b/edg/abstract_parts/Neopixel.py @@ -3,6 +3,7 @@ from ..electronics_interfaces import * +@abstract_block class Neopixel(Light, Block): """Abstract base class for individually-addressable, serially-connected Neopixel-type (typically RGB) LEDs and defines the pwr/gnd/din/dout interface.""" diff --git a/edg/abstract_parts/PartsTablePart.py b/edg/abstract_parts/PartsTablePart.py index 558d4a46e..6507c0d39 100644 --- a/edg/abstract_parts/PartsTablePart.py +++ b/edg/abstract_parts/PartsTablePart.py @@ -100,7 +100,7 @@ def generate(self) -> None: @abstract_block -class SelectorFootprint(PartsTablePart): +class SelectorFootprint(Block): """Mixin that allows a specified footprint, for Blocks that automatically select a part.""" def __init__( diff --git a/edg/abstract_parts/SelectorArea.py b/edg/abstract_parts/SelectorArea.py index bc8dc1851..803394e4b 100644 --- a/edg/abstract_parts/SelectorArea.py +++ b/edg/abstract_parts/SelectorArea.py @@ -9,7 +9,7 @@ @abstract_block -class SelectorArea(PartsTablePart): +class SelectorArea(Block): """A base mixin that defines a filter_area range specification for blocks that automatically select parts. Provides no implementation, only defines the specification parameter. diff --git a/edg/abstract_parts/SwitchingVoltageRegulator.py b/edg/abstract_parts/SwitchingVoltageRegulator.py index 58f8b6e3e..26db0b5be 100644 --- a/edg/abstract_parts/SwitchingVoltageRegulator.py +++ b/edg/abstract_parts/SwitchingVoltageRegulator.py @@ -81,6 +81,7 @@ def contents(self) -> None: ) self.pwr_out.init_from(VoltageSource(voltage=effective_output_voltage)) self.reset.init_from(DigitalSink()) + self.assign(self.actual_frequency, RangeExpr.EMPTY) @abstract_block_default(lambda: IdealBoostConverter) @@ -113,6 +114,7 @@ def contents(self) -> None: ) self.pwr_out.init_from(VoltageSource(voltage=effective_output_voltage)) self.reset.init_from(DigitalSink()) + self.assign(self.actual_frequency, RangeExpr.EMPTY) @abstract_block_default(lambda: BuckBoostConverter) @@ -121,7 +123,10 @@ class BuckBoostConverter(SwitchingVoltageRegulator): class IdealBuckBoostConverter(IdealVoltageRegulator, BuckBoostConverter): - pass + @override + def contents(self) -> None: + super().contents() + self.assign(self.actual_frequency, RangeExpr.EMPTY) class DiscreteBuckBoostConverter(BuckBoostConverter): diff --git a/edg/abstract_parts/test_kicad_import_netlist.py b/edg/abstract_parts/test_kicad_import_netlist.py index 2e4a85122..e7c7ccdb8 100644 --- a/edg/abstract_parts/test_kicad_import_netlist.py +++ b/edg/abstract_parts/test_kicad_import_netlist.py @@ -3,7 +3,7 @@ # to avoid re-defining NetBlock, this makes specific imports instead of 'from . import *' from ..core import * -from ..electronics_model import Passive, FootprintBlock +from ..electronics_model import Passive, FootprintBlock, Ohm, Volt, Watt, DummyDevice from ..electronics_interfaces.test_netlist import NetlistTestCase, Net, net_pin, net_block from ..electronics_interfaces.test_kicad_import_blackbox import KiCadBlackboxBlock from .Resistor import Resistor @@ -24,7 +24,7 @@ def __init__(self) -> None: (self.dummyout,), _ = self.chain(self.dut.out, self.Block(PassiveDummy())) -class DummyResistor(Resistor, FootprintBlock): +class DummyResistor(Resistor, DummyDevice, FootprintBlock): def __init__(self) -> None: super().__init__(Range.all()) self.footprint( @@ -35,6 +35,9 @@ def __init__(self) -> None: "2": self.b, }, ) + self.assign(self.actual_resistance, (0, 0) * Ohm) + self.assign(self.actual_power_rating, (0, 0) * Watt) + self.assign(self.actual_voltage_rating, (0, 0) * Volt) class KiCadImportBlackboxTestCase(unittest.TestCase): diff --git a/edg/circuits/test_opamp.py b/edg/circuits/test_opamp.py index f48f3216b..01d42b37e 100644 --- a/edg/circuits/test_opamp.py +++ b/edg/circuits/test_opamp.py @@ -22,6 +22,8 @@ class TestResistor(Resistor): def contents(self) -> None: super().contents() self.assign(self.actual_resistance, self.resistance) + self.assign(self.actual_power_rating, (0, 0) * Watt) + self.assign(self.actual_voltage_rating, (0, 0) * Volt) class AmplifierTestTop(Block): diff --git a/edg/circuits/test_switching_converters.py b/edg/circuits/test_switching_converters.py index 52181cc1b..212136e8c 100644 --- a/edg/circuits/test_switching_converters.py +++ b/edg/circuits/test_switching_converters.py @@ -155,6 +155,7 @@ def contents(self) -> None: self.assign(self.actual_inductance, self.inductance) self.assign(self.actual_current_rating, (0, 1.5) * Amp) self.assign(self.actual_frequency_rating, Range.all()) + self.assign(self.actual_resistance_dc, (0, 0) * Ohm) class BuckPowerPathTestTop(DesignTop): diff --git a/edg/core/Blocks.py b/edg/core/Blocks.py index 4d8512ab9..a45054168 100644 --- a/edg/core/Blocks.py +++ b/edg/core/Blocks.py @@ -10,7 +10,7 @@ from .. import edgir from .Array import BaseVector, Vector -from .Binding import AssignBinding, NameBinding +from .Binding import AssignBinding, NameBinding, InitParamBinding from .ConstraintExpr import ConstraintExpr, BoolExpr, ParamBinding, AssignExpr, StringExpr, BoolLike from .Core import ( Refable, @@ -304,6 +304,7 @@ def __init__(self) -> None: Connection, List[Connection] ]() # for net joins, joined connect -> prior connects self._constraints: List[ConstraintExpr] = [] + self._assigns = IdentityDict[ConstraintExpr, ConstraintExpr]() # target -> assign constraint self._name = StringExpr()._bind(NameBinding(self)) @@ -362,6 +363,10 @@ def _add_doc_metadata(self) -> None: metadata_dict[self._name_of(port)] = self._port_docs[port] self._docs = self.Metadata(metadata_dict) + @classmethod + def _is_abstract(cls) -> bool: + return (cls, AbstractBlockProperty) in cls._elt_properties + def _populate_def_proto_block_base(self, pb: edgir.BlockLikeTypes) -> None: """Populates the structural parts of a block proto: parameters, ports, superclasses""" assert ( @@ -369,7 +374,7 @@ def _populate_def_proto_block_base(self, pb: edgir.BlockLikeTypes) -> None: or self._elaboration_state == BlockElaborationState.post_generate ) - if (self.__class__, AbstractBlockProperty) in self._elt_properties: + if self._is_abstract(): assert isinstance(pb, edgir.HierarchyBlock) pb.is_abstract = True pb.is_mixin = False @@ -430,6 +435,56 @@ def _populate_def_proto_port_init(self, pb: edgir.BlockLikeTypes, ref_map: Refab ref_map, ) + def _collect_unassigned_params(self) -> List[List[str]]: + """Walks through all params and checks that they have been assigned. + TODO: return List[ConstraintExpr] when param names can be resolved.""" + if (self.__class__, AbstractBlockProperty) in self._elt_properties: + return [] # abstract blocks do not need assigned parameters + + unassigned: List[List[str]] = [] + + # TODO instead of filtering by binding, init should have assign record + for param in self._parameters: + if ( + param not in self._assigns + and param.initializer is None + and not isinstance(param.binding, InitParamBinding) + ): + unassigned.append([self._name_of(param)]) + + for port in self._ports: + unassigned.extend(self._collect_unassigned_port_params(port, [self._name_of(port)])) + + return unassigned + + def _collect_unassigned_port_params(self, container_port: BasePort, path: List[str]) -> List[List[str]]: + if container_port in self._connects_by_port: + # TODO check for absence of assignments + return [] # connected boundary ports inherit parameters + + unassigned: List[List[str]] = [] + + if isinstance(container_port, Port): + for port in container_port._ports: + unassigned.extend(self._collect_unassigned_port_params(port, path + [container_port._name_of(port)])) + + for param in container_port._parameters: + if param not in self._assigns and param.initializer is None: + unassigned.append(path + [container_port._name_of(param)]) + elif isinstance(container_port, Vector): + if container_port._elts is not None: + for name, elt in container_port._elts.items(): + unassigned.extend(self._collect_unassigned_port_params(elt, path + [name])) + else: + raise ValueError(f"unsupported port type {container_port}") + + return unassigned + + def _check_params_assigned(self) -> None: + unassigned = self._collect_unassigned_params() + if unassigned: + raise MissingParameterError(self, unassigned) + def _populate_def_proto_block_contents(self, pb: edgir.BlockLikeTypes, ref_map: Refable.RefMapType) -> None: """Populates the contents of a block proto: constraints""" assert ( @@ -437,6 +492,8 @@ def _populate_def_proto_block_contents(self, pb: edgir.BlockLikeTypes, ref_map: or self._elaboration_state == BlockElaborationState.post_generate ) + self._check_params_assigned() + for i, constraint in enumerate(self._constraints): name = self._name_of(constraint) constraint._populate_expr_proto(edgir.add_pair(pb.constraints, name), ref_map) @@ -531,6 +588,10 @@ def assign( self._constraints.append(constraint) self._namer.add_expected(constraint, SourceLocator.from_caller(), default_prefix="anon_constr") + if target in self._assigns: + raise OverassignParameterError(self, target) + self._assigns[target] = constraint + if name: # TODO unify naming API with everything else? self._namer.add_name(constraint, name) diff --git a/edg/core/Generator.py b/edg/core/Generator.py index 19e3fdde2..3bfe68eca 100644 --- a/edg/core/Generator.py +++ b/edg/core/Generator.py @@ -43,13 +43,15 @@ def generator_param(self, *params: ConstraintExpr) -> None: ) for param in params: if not isinstance(param, ConstraintExpr): - raise EdgTypeError(f"generator_param(...) param", param, ConstraintExpr) + raise EdgTypeError( + f"generator_param(...) param {self._name_of(param, debug=True)}", param, ConstraintExpr + ) if param.binding is None: raise BlockDefinitionError(type(self), "generator_param(...) param must be bound") if not isinstance(param.binding, (InitParamBinding, AllocatedBinding, IsConnectedBinding)): raise BlockDefinitionError( type(self), - "generator_param(...) param must be an __init__ param, port requested, or port is_connected", + f"generator_param(...) param {self._name_of(param, debug=True)} must be an __init__ param, port requested, or port is_connected", ) self._generator_params_list.append(param) @@ -92,6 +94,23 @@ def generate(self) -> None: # Generator serialization and parsing # + @override + def _check_params_assigned(self) -> None: + # the block is only complete when generating, don't check for missing params before then + if self._elaboration_state != BlockElaborationState.post_generate: + return + super()._check_params_assigned() + + @override + def _collect_unassigned_port_params(self, container_port: BasePort, path: List[str]) -> List[List[str]]: + # generators can inspect ports for connected-ness, if not connected, it does not need an assignment + if self._elaboration_state == BlockElaborationState.post_generate: + if isinstance(container_port, Port): + port_connected = container_port.is_connected() + if port_connected in self._generator_param_values and not self.get(port_connected): + return [] # port is not connected, so no assignment needed + return super()._collect_unassigned_port_params(container_port, path) + @override def _def_to_proto(self) -> edgir.HierarchyBlock: self._namer.resolve_names() diff --git a/edg/core/HdlUserExceptions.py b/edg/core/HdlUserExceptions.py index c7bc7285f..087d5c7c6 100644 --- a/edg/core/HdlUserExceptions.py +++ b/edg/core/HdlUserExceptions.py @@ -1,7 +1,7 @@ -from typing import Any, Type, Union, Tuple, TYPE_CHECKING +from typing import Any, Type, Union, Tuple, TYPE_CHECKING, List if TYPE_CHECKING: - from edg import BaseBlock + from edg import BaseBlock, ConstraintExpr class EdslUserError(Exception): @@ -61,3 +61,24 @@ class ChainError(BlockDefinitionError): class ElementNamingError(BlockDefinitionError): """Error for when an element has an invalid (missing, duplicated) name""" + + +class MissingParameterError(EdslUserError): + """Error if a block is missing an (output) parameter assignment / value""" + + def __init__(self, block: "BaseBlock", param_paths: List[List[str]]) -> None: + params_str = ", ".join([".".join(path) for path in param_paths]) + super().__init__( + f"{type(block).__name__} parameters {params_str} missing assignment", + "assign a value to the parameter", + ) + + +class OverassignParameterError(EdslUserError): + """Error if a block is assigned a parameter value more than once""" + + def __init__(self, block: "BaseBlock", param: "ConstraintExpr") -> None: + super().__init__( + f"{type(block).__name__} parameter {block._name_of(param, debug=True)} has conflicting assignment (assigned multiple times)", + "remove an assignment", + ) diff --git a/edg/core/HierarchyBlock.py b/edg/core/HierarchyBlock.py index bdd8df545..47997bb35 100644 --- a/edg/core/HierarchyBlock.py +++ b/edg/core/HierarchyBlock.py @@ -499,6 +499,26 @@ def _populate_def_proto_hierarchy(self, pb: edgir.HierarchyBlock, ref_map: Refab ref_map, ) + @override + def _collect_unassigned_params(self) -> List[List[str]]: + unassigned = super()._collect_unassigned_params() + + if (self.__class__, AbstractBlockProperty) in self._elt_properties: + return [] # abstract blocks do not need assigned parameters + + # TODO instead of filtering by binding, init should have assign record + + for block in self._blocks: + for param in block._parameters: + if ( + param not in self._assigns + and isinstance(param.binding, InitParamBinding) + and (isinstance(param.binding, InitParamBinding) and param.binding.value is None) + ): + unassigned.append([self._name_of(block), block._name_of(param)]) + + return unassigned + # TODO make this non-overriding? @override def _def_to_proto(self) -> edgir.HierarchyBlock: diff --git a/edg/core/Link.py b/edg/core/Link.py index fc01e621f..ceee93799 100644 --- a/edg/core/Link.py +++ b/edg/core/Link.py @@ -12,7 +12,7 @@ from .Core import Refable, non_library from .HdlUserExceptions import UnconnectableError from .IdentityDict import IdentityDict -from .Ports import Port +from .Ports import Port, BasePort class LinkMeta(BaseBlockMeta): @@ -97,3 +97,8 @@ def _def_to_proto(self) -> edgir.Link: @override def _elaborated_def_to_proto(self) -> edgir.Link: return cast(edgir.Link, super()._elaborated_def_to_proto()) + + @override + def _collect_unassigned_port_params(self, container_port: BasePort, path: List[str]) -> List[List[str]]: + # link ports should not have params assigned and this is a no-op + return [] diff --git a/edg/core/MultipackBlock.py b/edg/core/MultipackBlock.py index e0b64c466..61c6fedb3 100644 --- a/edg/core/MultipackBlock.py +++ b/edg/core/MultipackBlock.py @@ -1,12 +1,13 @@ from __future__ import annotations -from typing import NamedTuple, Optional, Union, List, Tuple, Generic, Callable, overload +import warnings +from typing import NamedTuple, Optional, Union, List, Tuple, Generic, Callable, overload, Any, override from typing_extensions import TypeVar from deprecated import deprecated from .Array import Vector from .ArrayExpr import ArrayExpr, ArrayBoolExpr, ArrayStringExpr, ArrayRangeExpr, ArrayFloatExpr, ArrayIntExpr -from .Binding import InitParamBinding +from .Binding import ParamBinding from .Blocks import BlockElaborationState from .HdlUserExceptions import BlockDefinitionError, EdgTypeError from .IdentityDict import IdentityDict @@ -14,6 +15,7 @@ from .ConstraintExpr import ConstraintExpr, BoolExpr, IntExpr, FloatExpr, RangeExpr, StringExpr from .Ports import BasePort, Port from .HierarchyBlock import Block, BlockPrototype +from ..core.IdentitySet import IdentitySet class PackedBlockAllocate(NamedTuple): @@ -48,8 +50,8 @@ class PackedBlockParam(NamedTuple): # a parameter replicated from an array of b class PackedBlockArray(Generic[PackedBlockElementType]): - """A container "block" (for multipack packing only) for an arbitrary-length array of Blocks. - This is meant to be analogous to Vector (port arrays), though there isn't an use case for this in general + """A container "block" (for multipack packing only) for an arbitrary-length array of abstract Blocks. + This is meant to be analogous to Vector (port arrays), though there isn't a use case for this in general (non-multipack) core infrastructure yet.""" def __init__(self, tpe: PackedBlockElementType): @@ -138,6 +140,8 @@ def __init__(self) -> None: self._packed_connects_by_packed_block = IdentityDict[ PackedBlockTypes, IdentityDict[BasePort, PackedPortTypes] ]() + # TODO can this be deduplicated with above? + self._packed_connected_ports = IdentitySet[BasePort]() # exterior ports involved in packed connections # packed block -> (self param -> packed param) (reverse of assign direction) self._packed_assigns_by_packed_block = IdentityDict[ PackedBlockTypes, IdentityDict[ConstraintExpr, PackedParamTypes] @@ -147,21 +151,37 @@ def __init__(self) -> None: PackedBlockTypes, IdentityDict[ConstraintExpr, UnpackedParamTypes] ]() + @override + def _collect_unassigned_port_params(self, container_port: BasePort, path: List[str]) -> List[List[str]]: + if container_port in self._packed_connected_ports: + # packed ports delegate their implementations + return [] + return super()._collect_unassigned_port_params(container_port, path) + PackedPartType = TypeVar("PackedPartType", bound=Union[Block, PackedBlockArray]) def PackedPart(self, tpe: PackedPartType) -> PackedPartType: """Adds a block type that can be packed into this block. The block is a "virtual block" that will not appear in the design tree.""" - if isinstance(tpe, BlockPrototype): - tpe_cls = tpe._tpe + if isinstance(tpe, PackedBlockArray): + unpacked_tpe: Any = tpe._tpe + elif isinstance(tpe, (Block, BlockPrototype)): + unpacked_tpe = tpe else: - tpe_cls = tpe.__class__ - - if not issubclass(tpe_cls, (Block, PackedBlockArray)): raise EdgTypeError(f"PackedPart(...) param", tpe, Block) if self._elaboration_state != BlockElaborationState.init: raise BlockDefinitionError(type(self), "can only define multipack in init") + if isinstance(unpacked_tpe, Block): + tpe_cls = type(unpacked_tpe) + elif isinstance(unpacked_tpe, BlockPrototype): + tpe_cls = unpacked_tpe._tpe + else: + raise ValueError("unexpected unpacked_tpe") + + if tpe_cls._is_abstract(): + raise BlockDefinitionError(type(self), "multipack PackedPart must not be abstract") + elt = tpe._bind(self) # TODO: does this actually need to be bound? self._namer.add_expected(elt, SourceLocator.from_caller()) self._packed_connects_by_packed_block[elt] = IdentityDict[BasePort, PackedPortTypes]() @@ -179,12 +199,14 @@ def packed_connect(self, exterior_port: BasePort, packed_port: PackedPortTypes) block_parent = packed_port._block_parent() assert isinstance(block_parent, Block) self._packed_connects_by_packed_block[block_parent][exterior_port] = packed_port + self._packed_connected_ports.add(exterior_port) elif isinstance(packed_port, PackedBlockPortArray): assert isinstance(exterior_port, Vector), "can only connect vector from packed port array" assert type(exterior_port._elt_sample) == type( packed_port.port ), "packed_connect ports must be of the same type" self._packed_connects_by_packed_block[packed_port.parent][exterior_port] = packed_port + self._packed_connected_ports.add(exterior_port) else: raise TypeError() @@ -192,6 +214,7 @@ def packed_connect(self, exterior_port: BasePort, packed_port: PackedPortTypes) @overload def PackedExport(self, packed_port: PackedPortType, *, optional: bool = False) -> PackedPortType: ... + @overload def PackedExport( self, packed_port: PackedBlockPortArray[PackedPortType], *, optional: bool = False @@ -230,14 +253,19 @@ def packed_assign(self, self_param: ConstraintExpr, packed_param: PackedParamTyp @overload def PackedParameter(self, packed_param: PackedParamType) -> PackedParamType: ... + @overload def PackedParameter(self, packed_param: PackedBlockParamArray[BoolExpr]) -> ArrayBoolExpr: ... + @overload def PackedParameter(self, packed_param: PackedBlockParamArray[IntExpr]) -> ArrayIntExpr: ... + @overload def PackedParameter(self, packed_param: PackedBlockParamArray[FloatExpr]) -> ArrayFloatExpr: ... + @overload def PackedParameter(self, packed_param: PackedBlockParamArray[RangeExpr]) -> ArrayRangeExpr: ... + @overload def PackedParameter(self, packed_param: PackedBlockParamArray[StringExpr]) -> ArrayStringExpr: ... @@ -246,9 +274,9 @@ def PackedParameter(self, packed_param: PackedParamTypes) -> ConstraintExpr: Combines self.Parameter(...) with self.packed_assign(...), and additionally compatible with generators where self.Parameter(...) would error out.""" if isinstance(packed_param, ConstraintExpr): - new_param = type(packed_param)()._bind(InitParamBinding(self)) + new_param = type(packed_param)()._bind(ParamBinding(self)) elif isinstance(packed_param, PackedBlockParamArray): - new_param = ArrayExpr.array_of_elt(packed_param.param)._bind(InitParamBinding(self)) + new_param = ArrayExpr.array_of_elt(packed_param.param)._bind(ParamBinding(self)) else: raise TypeError() self.packed_assign(new_param, packed_param) diff --git a/edg/core/ScalaCompilerInterface.py b/edg/core/ScalaCompilerInterface.py index 25c91ada6..734bc9d7d 100644 --- a/edg/core/ScalaCompilerInterface.py +++ b/edg/core/ScalaCompilerInterface.py @@ -72,10 +72,9 @@ def get_value( return self._values.get(localpath.SerializeToString(), None) def append_values(self, values: List[Tuple[edgir.LocalPath, edgir.ValueLit]]) -> None: - """Append solved values to this design, such as from a refinement pass""" + """Append / replaces solved values to this design, such as from a refinement pass""" for value_path, value_value in values: value_path_str = value_path.SerializeToString() - assert value_path_str not in self._values self._values[value_path_str] = edgir.valuelit_to_lit(value_value) def get_connected_link_port(self, block_port: edgir.LocalPath) -> Optional[edgir.LocalPath]: diff --git a/edg/core/test_assertion.py b/edg/core/test_assertion.py index 679afce35..bd09d1d0b 100644 --- a/edg/core/test_assertion.py +++ b/edg/core/test_assertion.py @@ -9,18 +9,7 @@ def __init__(self) -> None: self.require(BoolExpr._to_expr_type(False)) -class TestAssertionMissingBlock(Block): - def __init__(self) -> None: - super().__init__() - self.missing = self.Parameter(BoolExpr()) - self.require(self.missing) - - class AssertionTestCase(unittest.TestCase): def test_failure(self) -> None: with self.assertRaises(CompilerCheckError): ScalaCompiler.compile(TestAssertionFailureBlock) - - def test_missing(self) -> None: - with self.assertRaises(CompilerCheckError): - ScalaCompiler.compile(TestAssertionMissingBlock) diff --git a/edg/core/test_block.py b/edg/core/test_block.py index 6aa99b799..b8e320588 100644 --- a/edg/core/test_block.py +++ b/edg/core/test_block.py @@ -11,7 +11,7 @@ class TestBlockBase(Block): def __init__(self) -> None: super().__init__() - self.base_float = self.Parameter(FloatExpr()) + self.base_float = self.Parameter(FloatExpr(0.0)) self.base_port = self.Port(TestPortBase()) # required to test required constraint self.base_port_constr = self.Port(TestPortBase(self.base_float), optional=True) self.base_port_optional = self.Port(TestPortBase(), optional=self.base_port.is_connected()) @@ -84,9 +84,9 @@ def test_optional_required_constraint(self) -> None: self.assertEqual(self.pb.constraints[1].value, expected_constr) def test_port_init(self) -> None: - self.assertEqual(self.pb.constraints[2].name, "(init)base_port_constr.float_param") + self.assertEqual(self.pb.constraints[3].name, "(init)base_port_constr.float_param") self.assertEqual( - self.pb.constraints[2].value, edgir.AssignRef(["base_port_constr", "float_param"], ["base_float"]) + self.pb.constraints[3].value, edgir.AssignRef(["base_port_constr", "float_param"], ["base_float"]) ) @@ -144,17 +144,17 @@ def test_param_def(self) -> None: self.assertTrue(self.pb.params[3].value.HasField("array")) def test_superclass_init(self) -> None: - self.assertEqual(self.pb.constraints[2].name, "(init)base_port_constr.float_param") + self.assertEqual(self.pb.constraints[3].name, "(init)base_port_constr.float_param") self.assertEqual( - self.pb.constraints[2].value, edgir.AssignRef(["base_port_constr", "float_param"], ["base_float"]) + self.pb.constraints[3].value, edgir.AssignRef(["base_port_constr", "float_param"], ["base_float"]) ) def test_port_init(self) -> None: - self.assertEqual(self.pb.constraints[3].name, "(init)port_lit.float_param") + self.assertEqual(self.pb.constraints[5].name, "(init)port_lit.float_param") def test_param_init(self) -> None: - self.assertEqual(self.pb.constraints[4].name, "(init)range_init") - self.assertEqual(self.pb.constraints[4].value, edgir.AssignLit(["range_init"], Range(-4.2, -1.3))) + self.assertEqual(self.pb.constraints[7].name, "(init)range_init") + self.assertEqual(self.pb.constraints[7].value, edgir.AssignLit(["range_init"], Range(-4.2, -1.3))) expected_assign = edgir.ValueExpr() expected_assign.assign.dst.CopyFrom(edgir.LocalPathList(["array_init"])) @@ -162,14 +162,14 @@ def test_param_init(self) -> None: expected_array.vals.add().CopyFrom(edgir.lit_to_expr(False)) expected_array.vals.add().CopyFrom(edgir.lit_to_expr(True)) expected_array.vals.add().CopyFrom(edgir.lit_to_expr(False)) - self.assertEqual(self.pb.constraints[5].name, "(init)array_init") - self.assertEqual(self.pb.constraints[5].value, expected_assign) + self.assertEqual(self.pb.constraints[8].name, "(init)array_init") + self.assertEqual(self.pb.constraints[8].value, expected_assign) expected_assign = edgir.ValueExpr() expected_assign.assign.dst.CopyFrom(edgir.LocalPathList(["array_empty"])) expected_assign.assign.src.array.SetInParent() - self.assertEqual(self.pb.constraints[6].name, "(init)array_empty") - self.assertEqual(self.pb.constraints[6].value, expected_assign) + self.assertEqual(self.pb.constraints[9].name, "(init)array_empty") + self.assertEqual(self.pb.constraints[9].value, expected_assign) def test_docs(self) -> None: self.assertEqual(self.pb.meta.members.node["_docs"].members.node[""].text_leaf, "Test docstring") diff --git a/edg/core/test_block_errors.py b/edg/core/test_block_errors.py index c379816fc..348984aa9 100644 --- a/edg/core/test_block_errors.py +++ b/edg/core/test_block_errors.py @@ -2,6 +2,7 @@ from typing_extensions import override + from . import * from .HdlUserExceptions import * from .test_common import TestPortSource, TestBlockSource, TestBlockSink @@ -89,7 +90,7 @@ def __init__(self) -> None: def test_unnamed_param(self) -> None: with self.assertRaises(ElementNamingError) as exc: self.UnnamedParamBlock()._elaborated_def_to_proto() - self.assertIn("86", str(exc.exception)) + self.assertIn("87", str(exc.exception)) class DuplicateNameBlock(Block): def __init__(self) -> None: @@ -112,3 +113,112 @@ def test_duplicate_anon_name(self) -> None: with self.assertRaises(ElementNamingError) as exc: self.DuplicateAnonNameBlock()._elaborated_def_to_proto() self.assertIn("anon_constr0", str(exc.exception)) + + +class HasParamInnerBlock(Block): + def __init__(self, in_param: IntLike) -> None: + super().__init__() + self.in_param = self.ArgParameter(in_param) + + +class HasParamLink(Link): + def __init__(self) -> None: + super().__init__() + self.source = self.Port(HasParamPort.empty()) + + +class HasParamPort(Port[HasParamLink]): + link_type = HasParamLink + + def __init__(self, param: IntLike = 0) -> None: + super().__init__() + self.param = self.Parameter(IntExpr(param)) + + +class MissingParamTestCase(unittest.TestCase): + + class MissingParamBlock(Block): + def __init__(self) -> None: + super().__init__() + self.param = self.Parameter(IntExpr()) # value never defined + + def test_missing_param(self) -> None: + with self.assertRaises(MissingParameterError): + self.MissingParamBlock()._elaborated_def_to_proto() + + class OverassignParamBlock(Block): + def __init__(self) -> None: + super().__init__() + self.param = self.Parameter(IntExpr()) + self.assign(self.param, 1) + self.assign(self.param, 2) + + def test_overassign_param(self) -> None: + with self.assertRaises(OverassignParameterError): + self.OverassignParamBlock()._elaborated_def_to_proto() + + class OverassignInitializerParamBlock(Block): + """This has a conflicting assign between the initializer and an explicit assign statement.""" + + def __init__(self) -> None: + super().__init__() + self.param = self.Parameter(IntExpr(1)) + self.assign(self.param, 2) + + def test_overassign_initializer_param(self) -> None: + with self.assertRaises(OverassignParameterError): + self.OverassignInitializerParamBlock()._elaborated_def_to_proto() + + class MissingParamInnerBlock(Block): + """This block defines an arg-param but does not define an output parameter value.""" + + def __init__(self, in_param: IntLike) -> None: + super().__init__() + self.in_param = self.ArgParameter(in_param) + self.param = self.Parameter(IntExpr()) + + def test_missing_param_inner(self) -> None: + with self.assertRaises(MissingParameterError): + self.MissingParamInnerBlock(0)._elaborated_def_to_proto() + + class MissingParamContainerBlock(Block): + """This block contains a child that defines an arg-param but does not define an output parameter value.""" + + def __init__(self) -> None: + super().__init__() + self.inner = self.Block(HasParamInnerBlock(IntExpr())) + + def test_missing_param_container(self) -> None: + with self.assertRaises(MissingParameterError): + self.MissingParamContainerBlock()._elaborated_def_to_proto() + + class MissingParamPortBlock(Block): + def __init__(self) -> None: + super().__init__() + self.port = self.Port(HasParamPort(IntExpr())) + + def test_missing_param_port(self) -> None: + with self.assertRaises(MissingParameterError): + self.MissingParamPortBlock()._elaborated_def_to_proto() + + class MissingParamVectorBlock(Block): + def __init__(self) -> None: + super().__init__() + self.port = self.Port(Vector(HasParamPort.empty())) + self.port.append_elt(HasParamPort(2), "0") + self.port.append_elt(HasParamPort(IntExpr()), "1") # missing value + self.port.defined() + + def test_missing_param_vector(self) -> None: + with self.assertRaises(MissingParameterError): + self.MissingParamVectorBlock()._elaborated_def_to_proto() + + class MissingParamLink(Link): + def __init__(self) -> None: + super().__init__() + self.source = self.Port(TestPortSource(), optional=True) + self.param = self.Parameter(IntExpr()) + + def test_missing_param_link(self) -> None: + with self.assertRaises(MissingParameterError): + self.MissingParamLink()._elaborated_def_to_proto() diff --git a/edg/core/test_block_portvector.py b/edg/core/test_block_portvector.py index a777cfade..4cdecac38 100644 --- a/edg/core/test_block_portvector.py +++ b/edg/core/test_block_portvector.py @@ -30,8 +30,8 @@ def __init__(self) -> None: class TestBlockPortVectorExport(TestBlockPortVectorBase): def __init__(self) -> None: super().__init__() - vector0 = self.vector.append_elt(TestPortSink()) - vector1 = self.vector.append_elt(TestPortSink()) + vector0 = self.vector.append_elt(TestPortSink.empty()) + vector1 = self.vector.append_elt(TestPortSink.empty()) self.block0 = self.Block(TestBlockSink()) self.exported0 = self.connect(self.block0.sink, vector0) self.block1 = self.Block(TestBlockSink()) @@ -41,7 +41,7 @@ def __init__(self) -> None: class TestBlockPortVectorBridged(TestBlockPortVectorBase): def __init__(self) -> None: super().__init__() - vector_port = self.vector.append_elt(TestPortSink()) + vector_port = self.vector.append_elt(TestPortSink.empty()) self.block0 = self.Block(TestBlockSink()) self.block1 = self.Block(TestBlockSink()) self.conn = self.connect(self.block0.sink, self.block1.sink, vector_port) diff --git a/edg/core/test_bundle.py b/edg/core/test_bundle.py index c7498a917..c51024191 100644 --- a/edg/core/test_bundle.py +++ b/edg/core/test_bundle.py @@ -9,9 +9,9 @@ class TestBundle(Port): def __init__( self, - float_param: FloatLike = FloatExpr(), - a_float_param: FloatLike = FloatExpr(), - b_float_param: FloatLike = FloatExpr(), + float_param: FloatLike = 0.0, + a_float_param: FloatLike = 0.0, + b_float_param: FloatLike = 0.0, ) -> None: super().__init__() diff --git a/edg/core/test_compiled_design_export.py b/edg/core/test_compiled_design_export.py index ad39bfa71..5f44f35e5 100644 --- a/edg/core/test_compiled_design_export.py +++ b/edg/core/test_compiled_design_export.py @@ -1,10 +1,25 @@ import unittest -from typing import cast +from typing import cast, override from . import * from .CompiledDesignExport import CompiledPort +class ParamErrorsBlock(Block): + def __init__(self) -> None: + super().__init__() + self.param_a = self.Parameter(FloatExpr()) + self.param_b = self.Parameter(FloatExpr()) + + @override + def contents(self) -> None: + super().contents() + self.assign(self.param_a, self.param_b + 1.0) + self.assign(self.param_b, self.param_a + 1.0) + + self.require(self.param_a == 1.0) + + class CompiledDesignExportTestCase(unittest.TestCase): def test_hierarchy(self) -> None: from .test_hierarchy_block import TopHierarchyBlock @@ -34,9 +49,6 @@ def test_param_values(self) -> None: self.assertEqual(result.links["link"].params["range_intersection"].value, (5.0, 10.0)) def test_param_error(self) -> None: - from .test_simple_expr_eval import TestEvalExprErrorBlock - - compiled = ScalaCompiler.compile(TestEvalExprErrorBlock, ignore_errors=True) + compiled = ScalaCompiler.compile(ParamErrorsBlock, ignore_errors=True) result = CompiledDesignExportTransform(compiled).transform() - self.assertIn("overassign", cast(str, result.params["overassign_float"].error)) - self.assertEqual(result.params["overassign_float"].value, None) + self.assertEqual(result.params["param_a"].value, None) diff --git a/edg/core/test_elaboration_common.py b/edg/core/test_elaboration_common.py index fa932b12b..2a553dbd8 100644 --- a/edg/core/test_elaboration_common.py +++ b/edg/core/test_elaboration_common.py @@ -33,7 +33,7 @@ def __init__(self) -> None: class TestPortBase(Port[TestLink]): link_type = TestLink - def __init__(self, float_param: FloatLike = FloatExpr()) -> None: + def __init__(self, float_param: FloatLike = 0.0) -> None: super().__init__() self.float_param = self.Parameter(FloatExpr(float_param)) @@ -41,9 +41,9 @@ def __init__(self, float_param: FloatLike = FloatExpr()) -> None: class TestPortSource(TestPortBase): def __init__( self, - float_param_limit: RangeLike = RangeExpr(), - range_param: RangeLike = RangeExpr(), - float_param: FloatLike = FloatExpr(), + float_param_limit: RangeLike = RangeExpr.ALL, + range_param: RangeLike = Range(0, 0), + float_param: FloatLike = 0.0, ) -> None: super().__init__(float_param) self.float_param_limit = self.Parameter(RangeExpr(float_param_limit)) @@ -53,17 +53,19 @@ def __init__( class TestPortBridge(PortBridge): def __init__(self) -> None: super().__init__() - self.outer_port = self.Port(TestPortSink()) self.inner_link = self.Port(TestPortSource()) - - self.assign(self.outer_port.float_param, self.inner_link.link().float_param_sink_sum) - self.assign(self.outer_port.range_limit, self.inner_link.link().range_param_sink_common) + self.outer_port = self.Port( + TestPortSink( + float_param=self.inner_link.link().float_param_sink_sum, + range_limit=self.inner_link.link().range_param_sink_common, + ) + ) class TestPortSink(TestPortBase): bridge_type = TestPortBridge - def __init__(self, range_limit: RangeLike = RangeExpr(), float_param: FloatLike = FloatExpr()) -> None: + def __init__(self, range_limit: RangeLike = RangeExpr.ALL, float_param: FloatLike = 0.0) -> None: super().__init__(float_param) self.range_limit = self.Parameter(RangeExpr(range_limit)) diff --git a/edg/core/test_generator.py b/edg/core/test_generator.py index 877e519cc..b451b300e 100644 --- a/edg/core/test_generator.py +++ b/edg/core/test_generator.py @@ -94,7 +94,7 @@ def __init__(self) -> None: class TestPortSource(Port[TestLink]): link_type = TestLink - def __init__(self, float_value: FloatLike = FloatExpr()) -> None: + def __init__(self, float_value: FloatLike = 0.0) -> None: super().__init__() self.float_param = self.Parameter(FloatExpr(float_value)) @@ -102,7 +102,7 @@ def __init__(self, float_value: FloatLike = FloatExpr()) -> None: class TestPortSink(Port[TestLink]): link_type = TestLink - def __init__(self, range_value: RangeLike = RangeExpr()) -> None: + def __init__(self, range_value: RangeLike = Range(0.0, 0.0)) -> None: super().__init__() self.range_param = self.Parameter(RangeExpr(range_value)) @@ -152,7 +152,7 @@ def __init__(self) -> None: class GeneratorInnerConnect(GeneratorBlock): def __init__(self) -> None: super().__init__() - self.port = self.Port(TestPortSource(), optional=True) + self.port = self.Port(TestPortSource.empty(), optional=True) @override def generate(self) -> None: diff --git a/edg/core/test_generator_portvector.py b/edg/core/test_generator_portvector.py index c8bfca0b2..9b73bf1df 100644 --- a/edg/core/test_generator_portvector.py +++ b/edg/core/test_generator_portvector.py @@ -53,7 +53,7 @@ def test_initializer(self) -> None: class InnerBlockInvalid(Block): def __init__(self) -> None: super().__init__() - self.ports = self.Port(Vector(TestPortSink())) + self.ports = self.Port(Vector(TestPortSink.empty())) self.ports.append_elt(TestPortSink(), "haha") diff --git a/edg/core/test_initializer.py b/edg/core/test_initializer.py index 8d9f2cac6..90da7ea20 100644 --- a/edg/core/test_initializer.py +++ b/edg/core/test_initializer.py @@ -14,7 +14,7 @@ def __init__(self) -> None: class TestInternalBlock(Block): - def __init__(self, inner_param: FloatLike = 3.0, bundle_param: FloatLike = FloatExpr()) -> None: + def __init__(self, inner_param: FloatLike = 3.0, bundle_param: FloatLike = 5.0) -> None: super().__init__() self.inner_bundle = self.Port(TestBundle(bundle_param, 0, 24), optional=True) self.inner_param = inner_param @@ -51,51 +51,67 @@ class InitializerTestCase(unittest.TestCase): def test_initializer(self) -> None: pb = TestSingleInitializerBlock()._elaborated_def_to_proto() - self.assertEqual(len(pb.constraints), 3) + self.assertEqual(len(pb.constraints), 5) self.assertEqual(pb.constraints[0].name, "(init)bundle_port.float_param") self.assertEqual(pb.constraints[0].value, edgir.AssignLit(["bundle_port", "float_param"], 42.0)) self.assertEqual(pb.constraints[1].name, "(init)bundle_port.a.float_param") self.assertEqual(pb.constraints[1].value, edgir.AssignLit(["bundle_port", "a", "float_param"], 1.0)) - self.assertEqual(pb.constraints[2].name, "(init)bundle_port.b.float_param") - self.assertEqual(pb.constraints[2].value, edgir.AssignLit(["bundle_port", "b", "float_param"], -1.0)) + self.assertEqual(pb.constraints[2].name, "(init)bundle_port.a.range_limit") + self.assertEqual(pb.constraints[2].value, edgir.AssignLit(["bundle_port", "a", "range_limit"], RangeExpr.ALL)) + self.assertEqual(pb.constraints[3].name, "(init)bundle_port.b.float_param") + self.assertEqual(pb.constraints[3].value, edgir.AssignLit(["bundle_port", "b", "float_param"], -1.0)) + self.assertEqual(pb.constraints[4].name, "(init)bundle_port.b.range_limit") + self.assertEqual(pb.constraints[4].value, edgir.AssignLit(["bundle_port", "b", "range_limit"], RangeExpr.ALL)) def test_nested_initializer(self) -> None: pb = TestNestedBlock()._elaborated_def_to_proto() - self.assertEqual(len(pb.constraints), 5) + self.assertEqual(len(pb.constraints), 7) self.assertEqual(pb.constraints[0].name, "(init)outer_bundle.float_param") self.assertEqual(pb.constraints[0].value, edgir.AssignLit(["outer_bundle", "float_param"], 21.0)) self.assertEqual(pb.constraints[1].name, "(init)outer_bundle.a.float_param") self.assertEqual(pb.constraints[1].value, edgir.AssignLit(["outer_bundle", "a", "float_param"], 1.0)) - self.assertEqual(pb.constraints[2].name, "(init)outer_bundle.b.float_param") - self.assertEqual(pb.constraints[2].value, edgir.AssignLit(["outer_bundle", "b", "float_param"], -1.0)) - self.assertEqual(pb.constraints[3].name, "(init)inner.inner_param") - self.assertEqual(pb.constraints[3].value, edgir.AssignLit(["inner", "inner_param"], 62.0)) - self.assertEqual(pb.constraints[4].name, "(init)inner.bundle_param") - self.assertEqual(pb.constraints[4].value, edgir.AssignLit(["inner", "bundle_param"], 31.0)) + self.assertEqual(pb.constraints[2].name, "(init)outer_bundle.a.range_limit") + self.assertEqual(pb.constraints[2].value, edgir.AssignLit(["outer_bundle", "a", "range_limit"], RangeExpr.ALL)) + self.assertEqual(pb.constraints[3].name, "(init)outer_bundle.b.float_param") + self.assertEqual(pb.constraints[3].value, edgir.AssignLit(["outer_bundle", "b", "float_param"], -1.0)) + self.assertEqual(pb.constraints[4].name, "(init)outer_bundle.b.range_limit") + self.assertEqual(pb.constraints[4].value, edgir.AssignLit(["outer_bundle", "b", "range_limit"], RangeExpr.ALL)) + self.assertEqual(pb.constraints[5].name, "(init)inner.inner_param") + self.assertEqual(pb.constraints[5].value, edgir.AssignLit(["inner", "inner_param"], 62.0)) + self.assertEqual(pb.constraints[6].name, "(init)inner.bundle_param") + self.assertEqual(pb.constraints[6].value, edgir.AssignLit(["inner", "bundle_param"], 31.0)) def test_nested_inner(self) -> None: pb = TestInternalBlock()._elaborated_def_to_proto() - self.assertEqual(len(pb.constraints), 3) # should not generate initializers for constructors + self.assertEqual(len(pb.constraints), 5) self.assertEqual(pb.constraints[0].name, "(init)inner_bundle.float_param") self.assertEqual(pb.constraints[0].value, edgir.AssignRef(["inner_bundle", "float_param"], ["bundle_param"])) # don't care about value of literal initializers self.assertEqual(pb.constraints[1].name, "(init)inner_bundle.a.float_param") - self.assertEqual(pb.constraints[2].name, "(init)inner_bundle.b.float_param") + self.assertEqual(pb.constraints[2].name, "(init)inner_bundle.a.range_limit") + self.assertEqual(pb.constraints[3].name, "(init)inner_bundle.b.float_param") + self.assertEqual(pb.constraints[4].name, "(init)inner_bundle.b.range_limit") def test_default_initializer(self) -> None: pb = TestDefaultBlock()._elaborated_def_to_proto() - self.assertEqual(len(pb.constraints), 1) + self.assertEqual(len(pb.constraints), 2) self.assertEqual(pb.constraints[0].name, "(init)inner.inner_param") self.assertEqual(pb.constraints[0].value, edgir.AssignLit(["inner", "inner_param"], 3.0)) + self.assertEqual(pb.constraints[1].name, "(init)inner.bundle_param") + self.assertEqual(pb.constraints[1].value, edgir.AssignLit(["inner", "bundle_param"], 5.0)) def test_multiple_initializer(self) -> None: pb = TestMultipleInstantiationBlock()._elaborated_def_to_proto() - self.assertEqual(len(pb.constraints), 2) + self.assertEqual(len(pb.constraints), 4) self.assertEqual(pb.constraints[0].name, "(init)inner1.inner_param") self.assertEqual(pb.constraints[0].value, edgir.AssignLit(["inner1", "inner_param"], 3.0)) - self.assertEqual(pb.constraints[1].name, "(init)inner2.inner_param") - self.assertEqual(pb.constraints[1].value, edgir.AssignLit(["inner2", "inner_param"], 3.0)) + self.assertEqual(pb.constraints[1].name, "(init)inner1.bundle_param") + self.assertEqual(pb.constraints[1].value, edgir.AssignLit(["inner1", "bundle_param"], 5.0)) + self.assertEqual(pb.constraints[2].name, "(init)inner2.inner_param") + self.assertEqual(pb.constraints[2].value, edgir.AssignLit(["inner2", "inner_param"], 3.0)) + self.assertEqual(pb.constraints[3].name, "(init)inner2.bundle_param") + self.assertEqual(pb.constraints[3].value, edgir.AssignLit(["inner2", "bundle_param"], 5.0)) diff --git a/edg/core/test_port_bridge.py b/edg/core/test_port_bridge.py index 2bbf96cda..0a80d860f 100644 --- a/edg/core/test_port_bridge.py +++ b/edg/core/test_port_bridge.py @@ -13,13 +13,13 @@ def setUp(self) -> None: self.pb = TestPortBridge()._elaborated_def_to_proto() def test_contains_param(self) -> None: - self.assertEqual(self.pb.ports[0].name, "outer_port") - self.assertEqual(self.pb.ports[0].value.lib_elem.target.name, "edg.core.test_elaboration_common.TestPortSink") - self.assertEqual(self.pb.ports[1].name, "inner_link") - self.assertEqual(self.pb.ports[1].value.lib_elem.target.name, "edg.core.test_elaboration_common.TestPortSource") + self.assertEqual(self.pb.ports[0].name, "inner_link") + self.assertEqual(self.pb.ports[0].value.lib_elem.target.name, "edg.core.test_elaboration_common.TestPortSource") + self.assertEqual(self.pb.ports[1].name, "outer_port") + self.assertEqual(self.pb.ports[1].value.lib_elem.target.name, "edg.core.test_elaboration_common.TestPortSink") def test_constraints(self) -> None: - self.assertEqual(len(self.pb.constraints), 2) + self.assertEqual(len(self.pb.constraints), 5) constraints = list(map(lambda pair: pair.value, self.pb.constraints)) expected_constr = edgir.ValueExpr() diff --git a/edg/core/test_simple_const_prop.py b/edg/core/test_simple_const_prop.py index fbcbc4db8..8acfb8db0 100644 --- a/edg/core/test_simple_const_prop.py +++ b/edg/core/test_simple_const_prop.py @@ -7,11 +7,11 @@ class TestConstPropInternal(Block): - def __init__(self) -> None: + def __init__(self, float_param: FloatLike, range_param: RangeLike) -> None: super().__init__() - self.float_param = self.Parameter(FloatExpr()) - self.range_param = self.Parameter(RangeExpr()) + self.float_param = self.ArgParameter(float_param) + self.range_param = self.ArgParameter(range_param) class TestParameterConstProp(Block): @@ -32,9 +32,7 @@ def contents(self) -> None: self.assign(self.range_const, Range(1.0, 42.0)) self.assign(self.range_param, self.range_const) - self.block = self.Block(TestConstPropInternal()) - self.assign(self.block.float_param, self.float_param) - self.assign(self.block.range_param, self.range_param) + self.block = self.Block(TestConstPropInternal(self.float_param, self.range_param)) class ConstPropTestCase(unittest.TestCase): @@ -68,32 +66,31 @@ def __init__(self) -> None: class TestPortConstPropPort(Port[TestPortConstPropLink]): link_type = TestPortConstPropLink - def __init__(self) -> None: + def __init__(self, float_param: FloatLike = 0.0) -> None: super().__init__() - self.float_param = self.Parameter(FloatExpr()) + self.float_param = self.Parameter(FloatExpr(float_param)) class TestPortConstPropInnerBlock(Block): - def __init__(self) -> None: + def __init__(self, float_param: FloatLike = 0.0) -> None: super().__init__() - self.port = self.Port(TestPortConstPropPort(), optional=True) + self.port = self.Port(TestPortConstPropPort(float_param), optional=True) class TestPortConstPropOuterBlock(Block): - def __init__(self) -> None: + def __init__(self, inner_float_param: FloatLike = 0.0) -> None: super().__init__() - self.inner = self.Block(TestPortConstPropInnerBlock()) - self.port = self.Port(TestPortConstPropPort()) + self.inner = self.Block(TestPortConstPropInnerBlock(inner_float_param)) + self.port = self.Port(TestPortConstPropPort.empty()) self.connect(self.inner.port, self.port) class TestPortConstPropTopBlock(Block): def __init__(self) -> None: super().__init__() - self.block1 = self.Block(TestPortConstPropInnerBlock()) - self.block2 = self.Block(TestPortConstPropOuterBlock()) # dummy, just to infer a connection + self.block1 = self.Block(TestPortConstPropInnerBlock(3.5)) + self.block2 = self.Block(TestPortConstPropOuterBlock(0.0)) # dummy, just to infer a connection self.link = self.connect(self.block1.port, self.block2.port) - self.assign(self.block1.port.float_param, 3.5) class ConstPropPortTestCase(unittest.TestCase): @@ -115,8 +112,7 @@ def test_connected_link(self) -> None: class TestDisconnectedTopBlock(Block): def __init__(self) -> None: super().__init__() - self.block1 = self.Block(TestPortConstPropInnerBlock()) - self.assign(self.block1.port.float_param, 3.5) + self.block1 = self.Block(TestPortConstPropInnerBlock(3.5)) class DisconnectedPortTestCase(unittest.TestCase): @@ -142,16 +138,16 @@ def __init__(self) -> None: class TestPortConstPropBundle(Port[TestPortConstPropBundleLink]): link_type = TestPortConstPropBundleLink - def __init__(self) -> None: + def __init__(self, elt1_float_value: FloatLike = 0.0, elt2_float_value: FloatLike = 0.0) -> None: super().__init__() - self.elt1 = self.Port(TestPortConstPropPort()) - self.elt2 = self.Port(TestPortConstPropPort()) + self.elt1 = self.Port(TestPortConstPropPort(elt1_float_value)) + self.elt2 = self.Port(TestPortConstPropPort(elt2_float_value)) class TestPortConstPropBundleInnerBlock(Block): - def __init__(self) -> None: + def __init__(self, elt1_float_value: FloatLike, elt2_float_value: FloatLike) -> None: super().__init__() - self.port = self.Port(TestPortConstPropBundle()) + self.port = self.Port(TestPortConstPropBundle(elt1_float_value, elt2_float_value)) class TestPortConstPropBundleTopBlock(Block): @@ -160,13 +156,10 @@ def __init__(self) -> None: @override def contents(self) -> None: - self.block1 = self.Block(TestPortConstPropBundleInnerBlock()) - self.block2 = self.Block(TestPortConstPropBundleInnerBlock()) # dummy, just to infer a connection + self.block1 = self.Block(TestPortConstPropBundleInnerBlock(3.5, 6.0)) + self.block2 = self.Block(TestPortConstPropBundleInnerBlock(0.0, 0.0)) # dummy, just to infer a connection self.link = self.connect(self.block1.port, self.block2.port) - self.assign(self.block1.port.elt1.float_param, 3.5) - self.assign(self.block1.port.elt2.float_param, 6.0) - class ConstPropBundleTestCase(unittest.TestCase): @override diff --git a/edg/core/test_simple_expr_eval.py b/edg/core/test_simple_expr_eval.py index df72cb3b6..1b68c2df8 100644 --- a/edg/core/test_simple_expr_eval.py +++ b/edg/core/test_simple_expr_eval.py @@ -28,27 +28,6 @@ def test_sum(self) -> None: self.assertEqual(self.compiled.get_value(["sum_range"]), Range(9.0, 14.0)) -class TestEvalExprErrorBlock(Block): - def __init__(self) -> None: - super().__init__() - self.overassign_float = self.Parameter(FloatExpr()) - - @override - def contents(self) -> None: - self.assign(self.overassign_float, 1.0) - self.assign(self.overassign_float, 2.0) - - -class EvalExprErrorTestCase(unittest.TestCase): - @override - def setUp(self) -> None: - self.compiled = ScalaCompiler.compile(TestEvalExprErrorBlock, ignore_errors=True) - - def test_sum(self) -> None: - self.assertEqual(len(self.compiled.errors), 1) - self.assertIsInstance(self.compiled.get_value(["overassign_float"]), edgir.ErrorValue) - - class TestReductionLink(Link): def __init__(self) -> None: super().__init__() diff --git a/edg/electronics_interfaces/SpiPort.py b/edg/electronics_interfaces/SpiPort.py index 3c3a8d4f8..974271894 100644 --- a/edg/electronics_interfaces/SpiPort.py +++ b/edg/electronics_interfaces/SpiPort.py @@ -55,7 +55,6 @@ def __init__(self, model: Optional[DigitalBidir] = None, *, frequency_limit: Ran self.miso = self.Port(DigitalSink.from_bidir(model)) self.frequency_limit = self.Parameter(RangeExpr(frequency_limit)) - self.mode = self.Parameter(RangeExpr()) # modes supported, in [0, 3] TODO: what about sparse modes? class SpiPeripheral(Port[SpiLink]): @@ -72,7 +71,6 @@ def __init__(self, model: Optional[DigitalBidir] = None, *, frequency_limit: Ran # TODO: (?) CS is defined separately self.frequency_limit = self.Parameter(RangeExpr(frequency_limit)) # range of acceptable frequencies - self.mode_limit = self.Parameter(RangeExpr()) # range of acceptable modes, in [0, 3] # legacy names diff --git a/edg/electronics_interfaces/test_bom.py b/edg/electronics_interfaces/test_bom.py index c8cb9121a..6ec172184 100644 --- a/edg/electronics_interfaces/test_bom.py +++ b/edg/electronics_interfaces/test_bom.py @@ -44,15 +44,15 @@ def test_basic_bom(self) -> None: self.assertEqual(bom_csv_dict[0]["Designator"], "C1") self.assertEqual(bom_csv_dict[0]["Footprint"], "Capacitor_SMD:C_0603_1608Metric") self.assertEqual(bom_csv_dict[0]["Quantity"], "1") - self.assertEqual(bom_csv_dict[0]["PNP Rotation Offset"], "") # unspecified - self.assertEqual(bom_csv_dict[0]["PNP Offset Y"], "") # unspecified - self.assertEqual(bom_csv_dict[0]["PNP Offset X"], "") # unspecified + self.assertEqual(bom_csv_dict[0]["PNP Rotation Offset"], "0.0") # unspecified + self.assertEqual(bom_csv_dict[0]["PNP Offset Y"], "0.0") # unspecified + self.assertEqual(bom_csv_dict[0]["PNP Offset X"], "0.0") # unspecified self.assertEqual(bom_csv_dict[1]["Designator"], "R1") self.assertEqual(bom_csv_dict[1]["Footprint"], "Resistor_SMD:R_0603_1608Metric") self.assertEqual(bom_csv_dict[1]["Quantity"], "1") - self.assertEqual(bom_csv_dict[1]["PNP Rotation Offset"], "") # unspecified - self.assertEqual(bom_csv_dict[1]["PNP Offset Y"], "") # unspecified - self.assertEqual(bom_csv_dict[1]["PNP Offset X"], "") # unspecified + self.assertEqual(bom_csv_dict[1]["PNP Rotation Offset"], "0.0") # unspecified + self.assertEqual(bom_csv_dict[1]["PNP Offset Y"], "0.0") # unspecified + self.assertEqual(bom_csv_dict[1]["PNP Offset X"], "0.0") # unspecified def test_multisink_bom(self) -> None: # test aggregation of similar components diff --git a/edg/electronics_interfaces/test_kicad_import_blackbox.py b/edg/electronics_interfaces/test_kicad_import_blackbox.py index c8e7373c0..c32a28d90 100644 --- a/edg/electronics_interfaces/test_kicad_import_blackbox.py +++ b/edg/electronics_interfaces/test_kicad_import_blackbox.py @@ -14,9 +14,9 @@ class KiCadBlackboxBlock(KiCadSchematicBlock): def __init__(self) -> None: super().__init__() - self.pwr = self.Port(Passive.empty()) - self.gnd = self.Port(Passive.empty()) - self.out = self.Port(Passive.empty()) + self.pwr = self.Port(Passive()) + self.gnd = self.Port(Passive()) + self.out = self.Port(Passive()) self.import_kicad(self.file_path("resources", "test_kicad_import_blackbox.kicad_sch")) diff --git a/edg/electronics_interfaces/test_multipack_netlist.py b/edg/electronics_interfaces/test_multipack_netlist.py index 2ca61fb45..100d0aa4f 100644 --- a/edg/electronics_interfaces/test_multipack_netlist.py +++ b/edg/electronics_interfaces/test_multipack_netlist.py @@ -8,16 +8,11 @@ from .test_netlist import TestFakeSource, TestFakeSink, TestBaseFakeSink, NetlistTestCase, Net, net_pin, net_block -class TestFakeSinkElement(TestBaseFakeSink): - # just exists to not be an abstract part - pass - - class TestPackedSink(MultipackBlock): def __init__(self) -> None: super().__init__() - self.elements = self.PackedPart(PackedBlockArray(TestFakeSinkElement())) + self.elements = self.PackedPart(PackedBlockArray(TestBaseFakeSink())) self.pos = self.PackedExport(self.elements.ports_array(lambda x: x.pos)) self.neg = self.PackedExport(self.elements.ports_array(lambda x: x.neg)) diff --git a/edg/electronics_model/CircuitBlock.py b/edg/electronics_model/CircuitBlock.py index fa40b7c21..d4a27bca2 100644 --- a/edg/electronics_model/CircuitBlock.py +++ b/edg/electronics_model/CircuitBlock.py @@ -29,7 +29,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.fp_mfr = self.Parameter(StringExpr()) self.fp_part = self.Parameter(StringExpr()) self.fp_value = self.Parameter(StringExpr()) - self.fp_refdes = self.Parameter(StringExpr()) + self.fp_refdes = self.Parameter(StringExpr("")) # dummy value, replaced during compilation self.fp_refdes_prefix = self.Parameter(StringExpr()) self.fp_pnp_rot = self.Parameter(FloatExpr()) @@ -144,9 +144,15 @@ def footprint( # PNP rotation is left explicitly unassigned if not defined if pnp_rot is not None: self.assign(self.fp_pnp_rot, pnp_rot) + else: + self.assign(self.fp_pnp_rot, 0.0) + if pnp_offset is not None: self.assign(self.fp_pnp_offset_x, pnp_offset[0]) self.assign(self.fp_pnp_offset_y, pnp_offset[1]) + else: + self.assign(self.fp_pnp_offset_x, 0.0) + self.assign(self.fp_pnp_offset_y, 0.0) @non_library diff --git a/edg/parts/analog/Comparator_Lmv331.py b/edg/parts/analog/Comparator_Lmv331.py index c7fdd04f3..b6fb9e021 100644 --- a/edg/parts/analog/Comparator_Lmv331.py +++ b/edg/parts/analog/Comparator_Lmv331.py @@ -42,6 +42,7 @@ def contents(self) -> None: pnp_rot=180, ) self.assign(self.lcsc_part, "C7976") + self.assign(self.actual_basic_part, False) class Lmv331(Comparator): diff --git a/edg/parts/connector/Fpc.py b/edg/parts/connector/Fpc.py index 0407c9b3b..dd43dc526 100644 --- a/edg/parts/connector/Fpc.py +++ b/edg/parts/connector/Fpc.py @@ -104,6 +104,7 @@ def contents(self) -> None: def generate(self) -> None: super().generate() self.conn = self.Block(Fpc050Top(self.length)) + self.assign(self.actual_length, self.conn.actual_length) length = self.get(self.length) assert length > 0, "explicit length required" for pin in self.get(self.pins.requested()): diff --git a/edg/parts/connector/UsbPorts.py b/edg/parts/connector/UsbPorts.py index 6c1f054d0..b1607e38c 100644 --- a/edg/parts/connector/UsbPorts.py +++ b/edg/parts/connector/UsbPorts.py @@ -245,6 +245,8 @@ def contents(self) -> None: part="TPD2E009", datasheet="https://www.ti.com/lit/ds/symlink/tpd2e009.pdf", ) + self.assign(self.lcsc_part, "C2871371") + self.assign(self.actual_basic_part, False) class Pesd5v0x1bt(UsbEsdDiode, FootprintBlock, JlcPart): diff --git a/edg/parts/display/oled/Er_Oled_096_1_1.py b/edg/parts/display/oled/Er_Oled_096_1_1.py index c9e6e96b7..b98ceafe3 100644 --- a/edg/parts/display/oled/Er_Oled_096_1_1.py +++ b/edg/parts/display/oled/Er_Oled_096_1_1.py @@ -126,7 +126,9 @@ def __init__(self) -> None: self.i2c = self.Port( I2cTarget(DigitalBidir.empty(), addresses=[0x3C], frequency_limit=(0, 400) * kHertz), optional=True ) - self.generator_param(self.spi.is_connected(), self.dc.is_connected(), self.i2c.is_connected()) + self.generator_param( + self.spi.is_connected(), self.cs.is_connected(), self.dc.is_connected(), self.i2c.is_connected() + ) @override def contents(self) -> None: diff --git a/edg/parts/display/oled/Er_Oled_096_1c.py b/edg/parts/display/oled/Er_Oled_096_1c.py index 5004066a5..4152a7d36 100644 --- a/edg/parts/display/oled/Er_Oled_096_1c.py +++ b/edg/parts/display/oled/Er_Oled_096_1c.py @@ -121,7 +121,9 @@ def __init__(self) -> None: self.i2c = self.Port( I2cTarget(DigitalBidir.empty(), addresses=[0x3C], frequency_limit=(0, 400) * kHertz), optional=True ) - self.generator_param(self.spi.is_connected(), self.dc.is_connected(), self.i2c.is_connected()) + self.generator_param( + self.spi.is_connected(), self.cs.is_connected(), self.dc.is_connected(), self.i2c.is_connected() + ) @override def contents(self) -> None: diff --git a/edg/parts/interface/IoExpander_Pca9554.py b/edg/parts/interface/IoExpander_Pca9554.py index 9e8be919e..a7e6c0884 100644 --- a/edg/parts/interface/IoExpander_Pca9554.py +++ b/edg/parts/interface/IoExpander_Pca9554.py @@ -87,6 +87,7 @@ def generate(self) -> None: pnp_rot=-90, ) self.assign(self.lcsc_part, "C86803") + self.assign(self.actual_basic_part, False) class Pca9554(IoExpander, PinMappable): diff --git a/edg/parts/interface/IoExpander_Pcf8574.py b/edg/parts/interface/IoExpander_Pcf8574.py index a23e9ef40..72c28991e 100644 --- a/edg/parts/interface/IoExpander_Pcf8574.py +++ b/edg/parts/interface/IoExpander_Pcf8574.py @@ -86,6 +86,7 @@ def generate(self) -> None: pnp_rot=-90, ) self.assign(self.lcsc_part, "C86832") + self.assign(self.actual_basic_part, False) class Pcf8574(IoExpander, PinMappable): diff --git a/edg/parts/interface/RfModules.py b/edg/parts/interface/RfModules.py index afa3e5bb4..d8cd5896a 100644 --- a/edg/parts/interface/RfModules.py +++ b/edg/parts/interface/RfModules.py @@ -67,7 +67,7 @@ def contents(self) -> None: ) -class Xbee_S3b(Interface, Radiofrequency, FootprintBlock): +class Xbee_S3b(Interface, Radiofrequency): """XBee-PRO 900HP, product numbers XBP9B-*""" def __init__(self) -> None: diff --git a/edg/parts/interface/UsbUart_Cp2102.py b/edg/parts/interface/UsbUart_Cp2102.py index 66373ee69..aa9a76a8c 100644 --- a/edg/parts/interface/UsbUart_Cp2102.py +++ b/edg/parts/interface/UsbUart_Cp2102.py @@ -95,7 +95,7 @@ def __init__(self) -> None: self.assign(self.actual_basic_part, True) -class Cp2102(Interface, PinMappable): +class Cp2102(Interface): """USB-UART converter""" def __init__(self) -> None: diff --git a/edg/parts/logic/Logic_74Ahct.py b/edg/parts/logic/Logic_74Ahct.py index 840fb21df..193707fae 100644 --- a/edg/parts/logic/Logic_74Ahct.py +++ b/edg/parts/logic/Logic_74Ahct.py @@ -51,6 +51,7 @@ def contents(self) -> None: pnp_rot=-90, ) self.assign(self.lcsc_part, "C842287") + self.assign(self.actual_basic_part, False) class L74Ahct1g125(Interface, GeneratorBlock): diff --git a/edg/parts/microcontroller/Ice40up.py b/edg/parts/microcontroller/Ice40up.py index 649397c61..e4ddbadca 100644 --- a/edg/parts/microcontroller/Ice40up.py +++ b/edg/parts/microcontroller/Ice40up.py @@ -7,7 +7,7 @@ from ..connector.Headers import PinHeader127DualShrouded -class Ice40TargetHeader(ProgrammingConnector, FootprintBlock): +class Ice40TargetHeader(ProgrammingConnector): """Custom programming header for iCE40 loosely based on the SWD pinning""" def __init__(self) -> None: diff --git a/edg/parts/microcontroller/nRF52840.py b/edg/parts/microcontroller/nRF52840.py index 6a3573bff..69ace6ad4 100644 --- a/edg/parts/microcontroller/nRF52840.py +++ b/edg/parts/microcontroller/nRF52840.py @@ -667,7 +667,6 @@ class Feather_Nrf52840( IoController, WrapperSubboardBlock, GeneratorBlock, - FootprintBlock, ): """Feather nRF52840 socketed dev board as either power source or sink""" diff --git a/edg/parts/power/LedDriver_Tps92200.py b/edg/parts/power/LedDriver_Tps92200.py index 84f727ad1..a37cca6c9 100644 --- a/edg/parts/power/LedDriver_Tps92200.py +++ b/edg/parts/power/LedDriver_Tps92200.py @@ -5,7 +5,7 @@ class Tps92200_Device(InternalSubcircuit, JlcPart, FootprintBlock): - def __init__(self, peak_output_current: FloatLike): + def __init__(self): super().__init__() self.gnd = self.Port(Ground(), [Common]) @@ -70,7 +70,7 @@ def __init__( ) -> None: super().__init__() - self.ic = self.Block(Tps92200_Device(FloatExpr())) + self.ic = self.Block(Tps92200_Device()) self.gnd = self.Export(self.ic.gnd, [Common]) self.pwr = self.Export(self.ic.vin, [Power]) self.pwm = self.Export(self.ic.dim) diff --git a/edg/parts/power/converter/LinearRegulators.py b/edg/parts/power/converter/LinearRegulators.py index f948c1bcc..45f6879ca 100644 --- a/edg/parts/power/converter/LinearRegulators.py +++ b/edg/parts/power/converter/LinearRegulators.py @@ -573,7 +573,6 @@ class Lp5907_Device( InternalSubcircuit, LinearRegulatorDevice, SelectorFootprint, - PartsTablePart, JlcPart, GeneratorBlock, FootprintBlock, @@ -587,7 +586,7 @@ def __init__(self, output_voltage: RangeLike): self.assign(self.actual_dropout, (50, 250) * mVolt) self.output_voltage = self.ArgParameter(output_voltage) - self.generator_param(self.output_voltage, self.part, self.filter_footprints) + self.generator_param(self.output_voltage, self.filter_footprints) self.en = self.Port( DigitalSink( @@ -707,9 +706,7 @@ def contents(self) -> None: self.connect(self.pwr_out, self.ic.pwr_out, self.out_cap.pwr) -class Tlv757p_Device( - InternalSubcircuit, LinearRegulatorDevice, PartsTablePart, JlcPart, GeneratorBlock, FootprintBlock -): +class Tlv757p_Device(InternalSubcircuit, LinearRegulatorDevice, JlcPart, GeneratorBlock, FootprintBlock): def __init__(self, output_voltage: RangeLike): super().__init__() @@ -718,7 +715,7 @@ def __init__(self, output_voltage: RangeLike): self.assign(self.actual_quiescent_current, (0.1, 40) * uAmp) # shutdown to worst-case ground current self.output_voltage = self.ArgParameter(output_voltage) - self.generator_param(self.output_voltage, self.part) + self.generator_param(self.output_voltage) self.en = self.Port(DigitalSink(voltage_limits=(0, 5.5) * Volt, input_thresholds=(0.3, 1) * Volt)) diff --git a/edg/parts/power/motor/Bldc_Drv8313.py b/edg/parts/power/motor/Bldc_Drv8313.py index 56e10c8d4..79d930705 100644 --- a/edg/parts/power/motor/Bldc_Drv8313.py +++ b/edg/parts/power/motor/Bldc_Drv8313.py @@ -107,6 +107,7 @@ def contents(self) -> None: pnp_rot=-90, ) self.assign(self.lcsc_part, "C92482") + self.assign(self.actual_basic_part, False) class Drv8313(BldcDriver, GeneratorBlock): diff --git a/edg/parts/power/motor/MotorDriver_Drv8833.py b/edg/parts/power/motor/MotorDriver_Drv8833.py index 95f5005f1..6dd123315 100644 --- a/edg/parts/power/motor/MotorDriver_Drv8833.py +++ b/edg/parts/power/motor/MotorDriver_Drv8833.py @@ -100,6 +100,7 @@ def contents(self) -> None: pnp_rot=-90, ) self.assign(self.lcsc_part, "C50506") + self.assign(self.actual_basic_part, False) class Drv8833(BrushedMotorDriver, GeneratorBlock): diff --git a/edg/parts/sensor/DistanceArray_Vl53l5cx.py b/edg/parts/sensor/DistanceArray_Vl53l5cx.py index b7a897932..5f88e96ca 100644 --- a/edg/parts/sensor/DistanceArray_Vl53l5cx.py +++ b/edg/parts/sensor/DistanceArray_Vl53l5cx.py @@ -86,7 +86,7 @@ def contents(self) -> None: self.assign(self.actual_basic_part, False) -class Vl53l5cx(DistanceSensor, Resettable, GeneratorBlock): +class Vl53l5cx(DistanceSensor, GeneratorBlock): """Time-of-flight 8x8 multizone laser ranging sensor, up to 4m. Requires using the ST API, does not have a defined register map. Exposed pad must be thermally connected to GND. diff --git a/edg/vendor_parts/Leds.py b/edg/vendor_parts/Leds.py index 4a7209e32..ab2d88a4d 100644 --- a/edg/vendor_parts/Leds.py +++ b/edg/vendor_parts/Leds.py @@ -17,6 +17,7 @@ def contents(self) -> None: }, part="LED", ) + self.assign(self.actual_color, "") class ThtLed(Led, FootprintBlock): @@ -32,6 +33,7 @@ def contents(self) -> None: }, part="LED", ) + self.assign(self.actual_color, "") class Smt0606RgbLed(RgbLedCommonAnode, JlcPart, FootprintBlock): diff --git a/edg/vendor_parts/generic/GenericCapacitor.py b/edg/vendor_parts/generic/GenericCapacitor.py index 08978977c..9b4c82563 100644 --- a/edg/vendor_parts/generic/GenericCapacitor.py +++ b/edg/vendor_parts/generic/GenericCapacitor.py @@ -164,6 +164,9 @@ def select_package(nominal_capacitance: float, voltage: Range) -> Optional[str]: self.c[i] = self.Block(cap_model) self.connect(self.c[i].pos, self.pos) self.connect(self.c[i].neg, self.neg) + + self.footprint("", "", {}) # no footprint, but needed to satisfy required params + else: value = ESeriesUtil.choose_preferred_number(nominal_capacitance, ESeriesUtil.SERIES[24], 0) assert value is not None, "cannot select a preferred number" diff --git a/edg/vendor_parts/generic/GenericResistor.py b/edg/vendor_parts/generic/GenericResistor.py index 8c2196bfc..751779e6b 100644 --- a/edg/vendor_parts/generic/GenericResistor.py +++ b/edg/vendor_parts/generic/GenericResistor.py @@ -64,6 +64,7 @@ def generate(self) -> None: if not suitable_packages: raise ValueError("no suitable resistor packages") + self.assign(self.actual_voltage_rating, Range.all()) # ideal resistor self.assign(self.actual_resistance, selected_range) self.assign(self.actual_power_rating, Range.zero_to_upper(suitable_packages[0][0])) diff --git a/edg/vendor_parts/jlc/JlcCapacitor.py b/edg/vendor_parts/jlc/JlcCapacitor.py index 33368cfee..35d2aa8a1 100644 --- a/edg/vendor_parts/jlc/JlcCapacitor.py +++ b/edg/vendor_parts/jlc/JlcCapacitor.py @@ -118,7 +118,10 @@ def _row_generate(self, row: PartsTableRow) -> None: if row[self.PARALLEL_COUNT] == 1: super()._row_generate(row) # creates the footprint else: - TableCapacitor._row_generate(self, row) # skips creating the footprint in PartsTableSelectorFootprint + TableDeratingCapacitor._row_generate( + self, row + ) # skips creating the footprint in PartsTableSelectorFootprint + self.assign(self.lcsc_part, "") self.assign(self.actual_basic_part, True) # dummy value self._make_parallel_footprints(row) @@ -140,6 +143,8 @@ def _make_parallel_footprints(self, row: PartsTableRow) -> None: self.connect(self.c[i].pos, self.pos) self.connect(self.c[i].neg, self.neg) + self.footprint("", "", {}) # no footprint, but needed to satisfy required params + class JlcDummyCapacitor(JlcPart, DummyCapacitorFootprint): """Dummy capacitor that additionally has JLC part fields""" diff --git a/examples/test_swd_debugger.py b/examples/test_swd_debugger.py index f5703ad8a..969cc5b00 100644 --- a/examples/test_swd_debugger.py +++ b/examples/test_swd_debugger.py @@ -6,7 +6,7 @@ from .util import run_test_board -class SwdCortexSourceHeader(ProgrammingConnector, FootprintBlock): +class SwdCortexSourceHeader(ProgrammingConnector): def __init__(self) -> None: super().__init__() @@ -33,7 +33,7 @@ def contents(self) -> None: ) -class SwdCortexSourceTagConnect(ProgrammingConnector, FootprintBlock): +class SwdCortexSourceTagConnect(ProgrammingConnector): def __init__(self) -> None: super().__init__()