Repository navigation
Description
This came about while thinking of other ways to create a VirtualMux that will be type hint and IDE friendly. Originally a comment on #184 but I think it is better to have an issue separate from that so it doesn't get lost.
Each signal would be a method on the resulting VirtualMux subclass. This would be a big change for existing scripts. But once the jig refactor PR lands, we could introduce something like this and scripts could choose which style to use. For new scripts, the IDE autocomplete benefits of this approach would be nice to have. (There might be a way to type-hint the current VirtualMux, but I haven't figured it out)
# existing
class Mux(VirtualMux):
pin_list = ("x0", "x1", "x2")
map_list = (
("sig1", "x0"),
("sig2", "x1"),
("sig3", "x2", "x0"),
)
#new
@dataclass
class MuxNew(VirtualMux):
sig1: Sig = signal("x0")
sig2: Sig = signal("x1")
sig3: Sig = signal("x2", "x0")
dm.jig.mux.Mux("sig2")
# becomes
dm.jig.mux.NewMux.sig2()
# For tree defined multiplexers
# __________
# a0-------------------------------| |
# ________ | |
# a1_b0----------------| |--| |
# a1_b1----------------| Mux B | | |
# (None)--| 4:1 | | |
# a1_b3----------------| x3 x2 | | |
# |________| | |
# | Mux A |
# a2-------------------------------| 4:1 |
# ________ | |
# a3_c0----------------| |--| |
# a3_c1----------------| Mux C | | |
# a3_c2----------------| 4:1 | | |
# (None)--| x5 x4 | | |
# |________| | |
# |__x1__x0__|
muxA = MuxTree("x0", "x1")
muxB = MuxTree("x2", "x3", nest=muxA)
muxC = MuxTree("x4", "x5", nest=muxA)
@dataclass
class Mux(VirtualMux):
a0: Sig = muxA()
a1_b0: Sig = muxB()
a1_b1: Sig = muxB()
muxB() # "throw away" one entry
a1_b3: Sig = muxB()
a2: Sig = muxA()
a3_c0: Sig = muxC()
a3_c1: Sig = muxC()
a3_c2: Sig = muxC()Implementation - Maybe? very not tested... Most likely bugs, but I think the concept is O.K. I think we would end up with signal returning a class instead of a function, but this maps out the general idea.
Sig = Callable[[VirtualMux, bool], None]
def signal(*pins) -> Sig:
def _func(self: VirtualMux, trigger_update: bool=False):
self._do_switch(pins, trigger_update)
_func.pins = pins
return _func
class MuxTree:
def __init__(self, *pins: tuple[Pin], nest: MuxTree) -> None:
self._pins = set(pins)
self._pin_gen = generate_bit_sets(pins)
if nest is not None:
self._fixed_pins = nest().pins
else:
self._fixed_pins = set()
def __call__(self) -> Sig:
pins = self._fixed_pins | next(self._pin_gen)
return signal(*pins)
Activity
clint-lawrence commentedon Jun 11, 2024
@daniel-montanari?
clint-lawrence commentedon Jun 17, 2024
Possible way to extend this idea to "Tree" mux definitions.
Unravelling this in code to build the signal map would be a bit of a mess, but I think it captures all the required info.
There is one weird thing. I'm stealing the
""literal as a place holder for "check the metadata". It is always a valid signal, but defined to mean "all pins off". So we can use it here as a place holder for either a mux input that isn't used, or as a mux input that "connects" to another mux. Distinguishing between those two is a matter of context and the second metadata value (i.e. the tuple of(MuxB, MuxC)in the definition ofMuxAbelow).For each instance of
Annotatedthere are two or three values:clint-lawrence commentedon Jun 17, 2024
Need to check if this has an impact on that tree definition idea, because it is relying on ordering
https://docs.python.org/3/library/typing.html#typing.get_args
daniel-montanari commentedon Jun 17, 2024
This nearly gets there. It'd be nice if we could do something like
I think that would get rid of my weird feelings about the way we subclass a thing to do basically nothing. But I get that this whole idea is bastardising the crap out of this system anyway.
The
__orig_bases__trick only works due to subclassing. You'd need another way to bind the argument of__class_getitem__to the associated__init__daniel-montanari commentedon Jun 17, 2024
Forgive me for I have sinned.
Type checkers ignore this completely and just use the inferred behaviour due to subclassing
Generic. We could useTYPE_CHECKINGif we want to lie to the type checker as well.daniel-montanari commentedon Jun 17, 2024
Looks like they changed how Annotated behaves with
get_argsbetween 3.8 and 3.10.In 3.8
__metadata__is ignored byget_args. In 3.10 it is used. I guess this makes sense ifget_argsis meant to return whatever is inside the brackets of a generic.Changing the unpack operator to allow variable length is enough to get this working on all versions.
daniel-montanari commentedon Jun 18, 2024
Made a PR for people to look at and play around with.
Not expecting it to be merged in any time soon.