Skip to content

Commit

Permalink
Added blog entry about @Package decorator.
Browse files Browse the repository at this point in the history
  • Loading branch information
xesscorp committed May 27, 2020
1 parent 561817c commit dddd5a7
Show file tree
Hide file tree
Showing 9 changed files with 840 additions and 32 deletions.
4 changes: 4 additions & 0 deletions beautify
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/bash

isort --recursive tests skidl setup.py
black tests skidl setup.py
169 changes: 169 additions & 0 deletions docs/_posts/2020-05-26-package-decorator.markdown
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
---
layout: post
title: Good Things Come In Packages!
date: 2020-05-27T10:01:10-05:00
author:
name: Dave Vandenbout
photo: devb-pic.jpg
email: [email protected]
description: Relax, I do this stuff for a living.
category: blog
permalink: blog/package-decorator
---

Up to now, SKiDL supported hierarchy by applying the `@subcircuit` decorator to a Python function:

```py
@subcircuit
def analog_average(in1, in2, avg):
"""Output the average of the two inputs."""

# Create two 1K resistors.
r1, r2 = 2 * Part('Device', 'R', value='1K', dest=TEMPLATE)

# Each input connects thru a resistor to the avg output.
r1[1,2] += in1, avg
r2[1,2] += in2, avg
```

Then this subcircuit is instantiated by calling the function with nets
passed as arguments:

```py
in1, in2, in3, in4, out1, out2 = Net()*6 # Make some I/O nets.

analog_average(in1, in2, out1) # One instantiation of the averager.

... Some more code ...

analog_average(in3, in4, out2) # A second instantiation.
```

It was [pointed out](https://github.com/xesscorp/skidl/issues/48) that this method
of instantiating subcircuits is quite different from what is used for parts.
Unlike the connections to a subcircuit that are all made at a single place when the
function is called, the connections to a part can be placed
at various, non-contiguous locations in the code:

```py
q_npn = Part("Device", "Q_NPN_BCE") # Instantiate a transistor.

...

q_npn['E'] += Net('GND') # Connect the emitter to ground.

...

q_npn['B'] += in1 # Connect an input to the base.

...

q_npn['C'] += out1 # Connect the output to the collector.
```

Another issue is that you can pass a part instance as an argument to a subcircuit that
connects it to the internal circuitry.
But you can't do the same thing with a subcircuit function without making changes to the
code because of the syntactic differences in how connections are made:

```py
@subcircuit
def analog_average(in1, in2, avg, r):
"""Output the average of the two inputs."""

r1, r2 = r(num_copies=2) # Create two copies of the resistor part.
r1[1,2] += in1, avg
r2[1,2] += in2, avg

# If r was a subcircuit function, this would have to be written as:
# r(in1, avg)
# r(in2, avg)
```

To make subcircuits act more like parts, the `@package` decorator has been introduced.
Just replace the `@subcircuit` decorator while keeping everything else the same:

```py
@package
def analog_average(in1, in2, avg):
r1, r2 = 2 * Part('Device', 'R', value='1K', dest=TEMPLATE)
r1[1,2] += in1, avg
r2[1,2] += in2, avg
```

Instantiating the subcircuit now occurs in two phases.
First, create instances of the subcircuit wherever they are needed:

```py
avg1 = analog_average()

...

avg2 = analog_average()
```

In the second phase, make connections to these subcircuits as if they were parts
with the names of the function parameters serving as pin names:

```py
in1, in2, in3, in4, out1, out2 = Net()*6

# Make connections. You can use either [] or . to reference the I/O.
avg1['in1'] += in1
avg1.in2 += in2
avg1['avg'] += out1

...

avg2['in1'] += in3
avg2['in2'] += in4
avg2.avg += out2
```

In addition to nets, pins, and buses, you can pass any other type of
parameter to subcircuits.
For example, `analog_average` could take a float as a `ratio` parameter to
set the amount each input contributes to the output:

```py
@package
def analog_average(in1, in2, avg, ratio):
r = Part('Device', 'R', dest=TEMPLATE)
r1 = r(value=2000 * ratio)
r2 = r(value=2000 * (1-ratio))

r1[1,2] += in1, avg
r2[1,2] += in2, avg
```

Then the subcircuit can either be instantiated with a given ratio:

```py
avg1 = analog_average(ratio=0.25)
avg1.in1 += in1
avg1.in2 += in2
avg1.avg += out1
```
or you can set the ratio outside the function call:
```py
avg2 = analog_average()
avg2.ratio = 0.25 # Use a normal assignment (=) since this is not a circuit connection.
avg2.in1 += in3
avg2.in2 += in4
avg2.avg += out2
```

A subcircuit function instantiates its circuitry when it is called.
But this doesn't happen when using a package.
Instead, the subcircuit is placed in a list and executed after the
complete circuit is finalized
(i.e., whenever `ERC()` or `generate_netlist()` is called).
The arguments passed to the function consist of the connections
and other values that were assigned to the package parameters in the preceding code.

That's about it for the `@package` decorator.
Since it's new, it hasn't seen a lot of use and there could be unknown bugs
lying in wait.
If you have questions or problems, please ask on the
[SKiDL forum](https://skidl.discourse.group/) or
raise an [issue](https://github.com/xesscorp/skidl/issues).
60 changes: 30 additions & 30 deletions docs/_site/blog/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,36 @@
<div class="small-12 medium-9 large-10 columns">


<article class="notepad-index-post post row">
<div class="small-12 medium-3 large-2 columns datetime">
<span class="notepad-post-meta">
<time datetime="2020-05-27T11:01:10-04:00">
<span class="day">
27
</span>
<span class="month-year">
May 2020
</span>
</time>
</span>
</div>
<div class="small-12 medium-9 large-10 columns">
<header class="notepad-post-header">
<h3 class="notepad-post-title">
<a href="https://xesscorp.github.io/skidl/docs/_site/blog/package-decorator">
Good Things Come In Packages!
</a>
</h3>
</header>
<section class="notepad-post-excerpt">
<p>Up to now, SKiDL supported hierarchy by applying the @subcircuit decorator to a Python function: @subcircuit def analog_average(in1, in2, avg): """Output the average of the two inputs.""" # Create two 1K resistors. r1, r2 = 2 * Part('Device', 'R', value='1K',...</p>
</section>
<div class="notepad-index-post-tags">
<a href="https://xesscorp.github.io/skidl/docs/_site/categories/index.html#blog" title="Other posts from the Blog category">Blog</a>
</div>
</div>
</article>

<article class="notepad-index-post post row">
<div class="small-12 medium-3 large-2 columns datetime">
<span class="notepad-post-meta">
Expand Down Expand Up @@ -383,36 +413,6 @@ <h3 class="notepad-post-title">
</div>
</article>

<article class="notepad-index-post post row">
<div class="small-12 medium-3 large-2 columns datetime">
<span class="notepad-post-meta">
<time datetime="2018-05-15T23:00:23-04:00">
<span class="day">
15
</span>
<span class="month-year">
May 2018
</span>
</time>
</span>
</div>
<div class="small-12 medium-9 large-10 columns">
<header class="notepad-post-header">
<h3 class="notepad-post-title">
<a href="https://xesscorp.github.io/skidl/docs/_site/blog/reuse-leds">
Reusability Ain't What It Used To Be
</a>
</h3>
</header>
<section class="notepad-post-excerpt">
<p>Sometimes you need a quick circuit that does one, specific thing. Other times, you want to create a general design that can be re-used in multiple instances. I’ll demonstrate the evolution from a specific to a general SKiDL design using...</p>
</section>
<div class="notepad-index-post-tags">
<a href="https://xesscorp.github.io/skidl/docs/_site/categories/index.html#blog" title="Other posts from the Blog category">Blog</a>
</div>
</div>
</article>


<nav class="pagination" role="navigation">

Expand Down
Loading

0 comments on commit dddd5a7

Please sign in to comment.