Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: overloading the >> operator for connections #26

Closed
kasbah opened this issue Oct 17, 2017 · 12 comments
Closed

RFC: overloading the >> operator for connections #26

kasbah opened this issue Oct 17, 2017 · 12 comments

Comments

@kasbah
Copy link
Contributor

kasbah commented Oct 17, 2017

While working on #25 I had some thoughts that could help make circuits more readable. It may be possible to overload the >> operator in a way that turns

vin       += r1[1], r2[1]
r2[2]     += c1[1]
c1[2]     += gnd
led1['a'] += r1[2]
led1['k'] += gnd

into

vin >> r2 >> c1 >> gnd
vin >> r1 >> led1['a']; led1['k'] >> gnd 

Some things to note:

  • It needs to accept Net, Pin and Part (edit: and Bus!)
  • Giving a Part will assume it "flows" into pin 1 and out pin 2 so these are equivalent:
vin >> r1[1]; r1[2] >> gnd
vin >> r1 >> gnd

There may some blocker for making this possible in the way Python works, haven't investigated fully, but for now it would just be good to know if others agree that it would be desirable.

I don't think overloading <<, allowing connections in the other direction, would be desirable as it would make for more confusing circuit descriptions.

@kasbah
Copy link
Contributor Author

kasbah commented Oct 17, 2017

Seems like it's possible. Just made a little toy implementation:

class Net():
    def __init__(self, name):
        self.name = name
    def __rshift__(self, other):
        if isinstance(other, Part):
            print('connecting {} to {}[1]'.format(self.name, other.name))
        else:
            print('connecting {} to {}'.format(self.name, other.name))
        return other


class Pin():
    def __init__(self, name):
        self.name = name
    def __rshift__(self, other):
        if isinstance(other, Part):
            print('connecting {} to {}[1]'.format(self.name, other.name))
        else:
            print('connecting {} to {}'.format(self.name, other.name))
        return other


class Part():
    def __init__(self, name):
        self.name = name
        self.pins = [Pin('{}[1]'.format(name)), Pin('{}[2]'.format(name))]
    def __rshift__(self, other):
        if isinstance(other, Part):
            print('connecting {}[2] to {}[1]'.format(self.name, other.name))
        else:
            print('connecting {}[2] to {}'.format(self.name, other.name))
        return other
    def __getitem__(self, n):
        return self.pins[n - 1]


vin = Net('vin')
vout = Net('vout')
gnd = Net('gnd')

r1 = Part('r1')
r2 = Part('r2')
led1 = Part('led1')


vin >> r1 >> vout >> r2 >> gnd

r1 >> led1[2]; led1[1] >> gnd

# prints:
# connecting vin to r1[1]
# connecting r1[2] to vout
# connecting vout to r2[1]
# connecting r2[2] to gnd
# connecting r1[2] to led1[2]
# connecting led1[1] to gnd

@xesscorp
Copy link
Collaborator

This would only work with two-pin parts, correct?

@kasbah
Copy link
Contributor Author

kasbah commented Oct 18, 2017

The toy implementation is limited to two pins, for the actual one I propose that you can use it for multi-pin, you just have to specify the pin.

e.g.

vcc >> r1 >> u1[5] >> sw1 >> gnd

@xesscorp
Copy link
Collaborator

But you have to specify the pin where the net enters the part and the pin where it exits, correct?

@kasbah
Copy link
Contributor Author

kasbah commented Oct 20, 2017

Yes, but in the example above it "enters" and "exits" from the same pin.

What do you think of it in general? To me it's much more intuitive to write connections this way, I find it much easier to visualise current flow than netlists, but maybe it's a matter of personal preference?

@xesscorp
Copy link
Collaborator

Having a different/alternative way to express connections would be good to appeal to different people.
If you can nail down all the use cases, then go ahead and submit a PR and I'll approve it.

In the example above, the net both enters and exits pin u1[5]. What if that had been a resistor? Would vcc >> r1[1] >> ... enter and exit on resistor pin 1? Or would it still continue out of pin r1[2]? If you give one pin, does it always enter/exit on that pin? If you provide two pins (e.g., r1[1,2]) does it enter on the first and exit on the second?

@kasbah
Copy link
Contributor Author

kasbah commented Oct 20, 2017

If you specify a pin it will use the pin. If you specify a component it will pick a pin.

so:

r1 >> ... == r1[2] >> ...

... >> r1 == ... >> r1[1]

r1 >> r2 >> r3 == r1[2] >> r2[1]; r2[2] >> r3[1]

Regarding r1[1,2] I need to think about that and what to do about groups of nets/pins in general. My current thinking is that it would probably be handy to be able to connect groups in parallel but am unsure whether it's good/possible to overload >> to do that (it might mean a slice of pins needs to return a Bus).

u1[5:10] >> u2[5:10]

Should that mean:

u1[5] >> u2[5]
u1[6] >> u2[6]
...
u1[10] >> u2[10]

Maybe it would be better to use a different function or operator for that like:

u1[5:10] ** u2[5:10]

or possibly the least confusing:

parallel_connect(u1[5:10], u2[5:10])

Maybe it's best to leave it for now and not implement any functionality for groups of pins/nets yet?

@xesscorp
Copy link
Collaborator

xesscorp commented Oct 20, 2017

I don't know if you want SKiDL to "just pick a pin". That's going to be dangerous for anything but resistors, inductors and caps (think about diodes).

Maybe input and output from the same pin if there is only one listed. If two pins are listed, then enter through the first and exit from the second.

As for connecting groups of pins, SKiDL's += operator already handles that. I don't see any improvement from u1[5:10] >> u2[5:10] as compared to u1[5:10] += u2[5:10].

@kasbah
Copy link
Contributor Author

kasbah commented Oct 20, 2017

You mean instead of:

vcc >> r1 >> led['a']; led['k'] >> gnd

You have to do:

vcc >> r1[1:2] >> led1['a':'k'] >> gnd

And disallow connecting to parts? I can see your point about it preventing possible mistakes like:

vcc >> r1 >> led1 >> gnd

Still, I have to say I much prefer the succinct notation without the pins. I think 1 then 2 is a sensible default given how many two pin components, where the order doesn't matter, there are in a given design. It's easy to be explicit about the pins when it does matter.

I didn't know += did this! Definitely can stay out of this proposal then.

@xesscorp
Copy link
Collaborator

I can see the implicit flow-through syntax working with discrete resistors, inductors and non-polarized caps. But you'll need a way to warn people when they're being stupid with polarized parts like electrolytic caps and LEDs. That implies the tool has some device knowledge built into it.

Linear chains of components seem pretty rare to me. Even a resistor divider has a junction where you tap off the divided voltage. You'll need some method for referring to that point. I guess you can assume the current always enters on pin 1 and exits on pin 2, but these implicit rules make the design less transparent to the observer.

vcc >> r1 >> r2 >> gnd // Where's the tap point between r1 and r2. Is it r1[2] or r1[1]?

I think you'll have to try your syntax a bit and see where it's useful and where it's a pain, and then decide if the costs outweigh the benefits. Let me know how I can help.

@kasbah
Copy link
Contributor Author

kasbah commented Oct 25, 2017

I agree that it bares some experimentation and it would be nice to have warnings or errors on stupid behaviour. An easy one might be to allow it only on components with two pins (i.e. allow vcc >> r1, disallow vcc >> u5 and allow vcc >> u5[1]). Detecting polarized components would be a step above that.

I coming round to your point though, maybe it's not worth the effort.

Thanks for your help. Right now, it's just important for me to be able to bounce these ideas off of you and be able to ask stupid questions about your design choices (by the by I still have a stupid question open in #29).

@xesscorp
Copy link
Collaborator

I took another look at this and implemented something using the & operator to make series connections and the | operator to make parallel connections. I think this gets most of what you want except for the bus connections. You can see some examples in the section "Making Parallel and Serial Networks" here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants