+
+
+ + +
+
+ +
+ +
+
+ +
+
+ +
+
+
+ + +
+ +

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', 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:

+ +
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 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:

+ +
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:

+ +
@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:

+ +
@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:

+ +
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:

+ +
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:

+ +
@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:

+ +
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:

+
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 or +raise an issue.

+ +
+
+ + + +
+
+
+
+
+ + + + + +
+
+
+
+
+ +
+
+ +
+ +
+ + +