[L3] Digital circuits are Analog circuits (SPICE subcircuits)

NAND gate (NOT-AND) is a logical gate which outputs false only if both inputs are true:

* NAND LOGICAL TABLE *
* a b * out
***********
* 0 0 * 1 *
* 0 1 * 1 *
* 1 0 * 1 *
* 1 1 * 0 *
***********

We can implement a NAND gate using the following schematics. Please use models from the previous exercise.

.lib 'cmos180n.lib' tm

* NAND logic gate
*********************************************************
*   D G  S   B for nmos
m3 (out a 1 vss)    nmosmod w=10u  l=10u  m=1
m4 (1 b vss vss)    nmosmod w=10u  l=10u  m=1

*   S G D B for pmos
m1 (vdd a out vdd)    pmosmod w=10u  l=10u  m=1
m2 (vdd b out vdd)    pmosmod w=10u  l=10u  m=1
*********************************************************

We have to add power supply and signal inputs as well.

* Logic input
va (a 0) dc=0
vb (b 0) dc=0

* Power Supply
vdd (vdd 0) dc=1.5
vss (vss 0) dc=-1.5

We can check the NAND truth table now. Remember, that logical 1 in this technology (using positive and negative supply) is 1.5 V and logical 0 is -1.5 V.

.control
echo Operating point va=vb=0
op
print out

echo OP Analysis va=-1.5 vb=-1.5
let @va[dc]=-1.5
let @vb[dc]=-1.5
op
print out

echo OP Analysis va=-1.5 vb=1.5
let @va[dc]=-1.5
let @vb[dc]=1.5
op
print out

echo OP Analysis va=1.5 vb=-1.5
let @va[dc]=1.5
let @vb[dc]=-1.5
op
print out

echo OP Analysis va=+1.5 vb=+1.5
let @va[dc]=1.5
let @vb[dc]=1.5
op
print out

.endc

Perform a DC sweep on A or B input and see how output changes. Apply time-domain pulses and observe output.

Half-adder

Now consider a half-adder made only of NAND gates. We need five of them and we will rather not encode them transistor-vise.

Subcircuit

Create a file nand_subckt.cir:

*Empty line

.lib 'cmos180n.lib' tm

*            _sub-circuit_name
*           /         _nodes-to-be-accessible-from-the-outer-world 
*                    /(in this order!)
*          /        / 
*         /  /--------------/    
.subckt nand a b out vdd vss
*   D G  S   B for nmos
m3 (out a 1 vss)    nmosmod w=1u  l=1u  m=1
m4 (1 b vss vss)    nmosmod w=1u  l=1u  m=1

*   S G D B for pmos
m1 (vdd a out vdd)    pmosmod w=1u  l=1u  m=1
m2 (vdd b out vdd)    pmosmod w=1u  l=1u  m=1
.ends

You can now build a higher-level circuit like this:

xnand1 (a b 1 vdd vss) nand
xnand2 (a 1 2 vdd vss) nand

x stands for external subcircuit and is followed by instance name. In parentheses nodes are given - the order corresponds to connections in subcircuit definition (1 in higher level circuit is connected to out in NAND subcircuit.  

For example, xnand2 has signal a connected to its internal a input, signal from node 1, connected to its internal b and node 2 is connected to NAND internal out.

Our half-adder can now look like:

.include  'nand_subckt.cir'

* NAND logic gate
*********************************************************
* a device beginning with x -> external -> subcircuit 
xnand1 (a b 1 vdd vss) nand
xnand2 (a 1 2 vdd vss) nand
xnand3 (1 b 3 vdd vss) nand
xnand4 (2 3 sum vdd vss) nand
xnand5 (1 1 carry vdd vss) nand
*********************************************************
* Power Supply
vdd (vdd 0) dc=1.5
vss (vss 0) dc=-1.5
*********************************************************
* Signal/logic input
va (a 0) dc=0
vb (b 0) dc=0
*********************************************************

.end

Where nand_subckt.cir is a file that contains the subcircuit definition, residing in the same folder.

Subcircuits can be parameterized, meaning, they can receive parameters that set up properties of included devices, for example:

.subckt nand_param a b out vdd vss param: wn=2 ln=1 wp=4 lp=1
* NAND logic gate
*********************************************************
*   D G  S   B for nmos
m3  (out a 1 vss) nmosmod w={wn*0.18u} l={ln*0.18u} m=1
m4  (1 b vss vss) nmosmod w={wn*0.18u} l={ln*0.18u} m=1

*   S G  D   B for pmos
m1  vdd a out vdd pmosmod w={wp*0.18u} l={lp*0.18u} m=1
m2  vdd b out vdd pmosmod w={wp*0.18u} l={lp*0.18u} m=1
*********************************************************
.ends

Our nand_param (parameterized NAND) takes four parameters: width of a NMOS wn, length of a NMOS ln, width of a PMOS pw and length of a PMOS lp. When you inspect further, you will see that actual W and L are being calculated with a formula, such as {wn*0.180n}, which basically gives you a multiplication of the smallest possible width in the 180nm CMOS technology.

Using a nand_param subcircuit now creates every NMOS being w={2*0.18u} l={1*0.18u} and every PMOS being w={4*0.18u} l={1*0.18u} .

Now, this will be true for every nand_param used across the circuit definition, that do not have parameters set SPECIFICALLY. In the Half-adder definition, one can set parameters for EACH instance of the NAND gate like this:

* NAND logic gate
*********************************************************
xnand1 (a b 1 vdd vss) nand_param wn=10 ln=10 wp=20 lp=20
xnand2 (a 1 2 vdd vss) nand_param
xnand3 (1 b 3 vdd vss) nand_param
xnand4 (2 3 sum vdd vss) nand_param
xnand5 (1 1 carry vdd vss) nand_param
*********************************************************

Now only xnand1 instance has significantly larger transistors and the rest have their default value, as specified in a subcircuit.

In our LAB session we tested our circuits truth table. Files are available here: