KBDD Reference Guide
KBDD Reference Guide
As a starting point, if you type the help command into kbdd, this is what will be
printed, as a “quick reference” to what commands kbdd offers:
1We gratefully acknowledge Prof. Randy Bryant of CMU for his permission to use
his kbdd software package for our University of Illinois MOOC on VLSI CAD.
Here is this same information, but with a bit more explanation about what is
happening with each command available in kbdd:
Consider the logic network below. In this example, a simple 1-bit adder circuit for
the carry-out cout has a NOR gate incorrectly where there should be an OR gate, like
this:
We can employ the repair steps, via quantification, etc., as in the lecture video and
notes on Computational Boolean Algebra. The basic recipe is:
1. Build a correct BDD for the function we want, Cout.
2. Build a BDD for the incorrect logic, but replace the suspect gate – the input
NOR – with a 4:1 multiplexor (MUX), with new inputs d0 d1 d2 d3 as the MUX
data inputs.
3. Exclusive NOR (EXNOR) the correct and to-be-repaired functions. This new
function Z can be satisfied only if the d inputs are set correctly to let the MUX
mimic the correct gate.
4. Universally quantify away the real logic input (a,b,cin) here, so that the Z
function depends only on the MUX d inputs.
5. Check is there is a satisfying assignment to the d inputs; if so, we have found
a viable gate repair.
The following shows an example of a session with kbdd. Inputs are in normal font
(these are what you would type into a plain textfile, and upload to our Coursera
cloud-based version of kbdd). kbdd outputs are blue, kbdd’s prompts for input
shown in bold as KBDD:
Kbdd Example Session for Adder Carry-out Repair
KBDD: # input variables
KBDD: boolean a b cin d0 d1 d2 d3
KBDD: #
KBDD: # define the correct equation for the adder’s carry out
KBDD: eval cout a&b + (a+b)&cin
cout: a&b + (a+b)&cin
KBDD: #
KBDD: # define the incorrect version of this equation (just for fun)
KBDD: eval wrong a&b + (!(a+b))&cin
wrong: a&b + (!(a+b))&cin
KBDD: #
KBDD: # define the to-be-repaired version with the MUX
KBDD: eval repair a&b + (d0&!a&!b + d1&!a&b + d2&a&!b + d3&a&b)&cin
repair: a&b + (d0&!a&!b + d1&!a&b + d2&a&!b + d3&a&b)&cin
KBDD: #
KBDD: # make the Z function that compares the right version of
KBDD: # the network and the version with the MUX replacing the
KBDD: # suspect gate (this is EXNOR of cout and repair functions)
KBDD: eval Z repair&cout + !repair&!cout
Z: repair&cout + !repair&!cout
KBDD: # universally quantify away the non-mux vars: a b cin
KBDD: quantify u ForallZ Z a b cin
KBDD: #
KBDD: # let’s ask kbdd to show an equation for this quantified function
KBDD: sop ForallZ
!d0 & d1 & d2
KBDD: #
KBDD: # what values of the d’s make this function == 1?
KBDD: satisfy ForallZ
Variables: d0 d1 d2
011
KBDD: #
KBDD: # that’s it!
KBDD: quit
%
As always, it is important to use your brain to analyze what the software tool is
telling you. Observer that kbdd says that a satisfying assignment of the MUX inputs
is this:
Variables: d0 d1 d2
011
This means d3’s value does not matter. So, in fact, there are two solutions: d0 d1 d2
d3 = 0111, and 0110. These specify and OR and an EXOR gate, respectively, as
feasible repairs of the network.
kbdd has basic n-bit adders built in, so this is very convenient. But, there is a bug in
the online “help” output for this version of kbdd, for the syntax for the adder
command. The example shown here clears up exactly how to use this:
It is important to note that kbdd is using an additional “trick” that we did not
discuss in lecture. This trick is something called negation arcs. In digital design,
suppose we have a function F, and we want to build logic for the complement F’. We
might optimize F’ directly as gates. Or, we might just build F itself, and then send its
output through a simple inverter gate. We would like to choose the option that gives
us the fewest logic gates. One can apply a similar idea to BDDs. Sometimes, it is
easiest to build the BDD for F’ directly. But sometimes it is easier to just build F, and
then indicate in the data structure that we have “inverted it”. This is the idea of the
negation arc: it is exactly like a simple inverter gate. We put an inversion bubble on
the edge leaving a BDD node, and the bubble means “interpret the BDD to which this
edge points as being inverted”. It turns out that a simple set of Shannon factor tricks,
and some basic DeMorgan complement laws, can be used to build the rules for how
this can work. Nicely enough, one again creates canonical structures: a function F
makes one and only one BDD, and always the same BDD. The complement bubbles
just arrange themselves in the right places. The big advantage is that one can save,
on average, about half the nodes in the BDD. The big disadvantage (and this is
rather minor) is that BDDs become rather hard to “read”, visually, as graphs.
For our BDD example, the printout with parentheses and big numbers, has this
interpretation:
(a0:1753429896
(b0:1753429864
(c0:1753429784)
![c0:1753429784])
![b0:1753429864])
We can also show another example to illustrate that we don’t always need negation
arcs. This BDD has a more familiar structure:
KBDD: boolean a b c
KBDD: eval F !a + b&c
F: !a + b&c
KBDD: bdd F
(a:1812523160
(b:1812523176
(c:1812523096)
[0])
[1])