Incremental Switching Factor Calculation for Power ... by Christine H. Tran

Incremental Switching Factor Calculation for Power Estimation by

Christine H. Tran

Author

Submitted to the Department of Electrical Engineering and Computer Science in Partial Fulfillment of the Requirements for the Degree of

Master of Engineering in Electrical Engineering and Computer Science at the Massachusetts Institute of Technology

May 23, 2001

© 2001 Christine H. Tran. All rights reserved.

The author hereby grants to M.I.T. permission to reproduce and distribute publicly paper and electronic copies of this thesis and to grant others the right to do so.

Certified by

-

Certified by

Accepted by

Department of Electrical Engineering and Computer Science

May 23, 2001

A

David Hathaway

IBM Thesis Supervisor

/

/

Srinivas Devadas

M.I.T. Thesis Sunuvisor

Chairman, Department

Arthur C. Smith

Committee on Graduate Theses

BARKER

MASSA CHUSETTS JMSTITTE

OF TECHNOLOGY

JUL 3

1

2002

LIBRARIES

Incremental Switching Factor Calculation for Power Estimation by

Christine H. Tran

Submitted to the

Department of Electrical Engineering and Computer Science

May 23, 2001

In Partial Fulfillment of the Requirements for the Degree of

Master of Engineering in Electrical Engineering and Computer Science

ABSTRACT

The thesis improves upon current power calculation methods by introducing an incremental analysis method. This method is useful for circuits that are continually being refined or redesigned by computer-aided design tools such as power logic optimizers.

Incremental analysis only recomputes the power for the subsections of the circuit that are affected by a circuit design modification, rather than recalculating the power for the entire circuit. Our test results show that the more modifications made to a circuit, the amount of time saved by using an incremental calculator increases significantly. Thus, our application is very efficient and suitable for power computation for low power logic optimizations

Thesis Supervisor: David Hathaway

Title: Senior Technical Staff Member, IBM

Thesis Supervisor: Srinivas Devadas

Title: Professor, Department of Electrical Engineering & Computer Science

ACKNOWLEDGEMENTS

The author would like to thank David Hathaway of IBM for his guidance, time, and expertise throughout the duration of the thesis, without which this thesis project would not have been possible. The author would also like to thank John Cohn of IBM for his constant assistance before and during the project. The members of the IBM Electronic

Design and Automation team provided valuable technical support and resources. The author is also appreciative of Srinivas Devadas for his time in evaluating the thesis.

The author wholeheartedly thanks her parents for all of their love and support.

3

TABLE OF CONTENTS

1 INTRODUCTION

1.1 Power Calculation Algorithms

1.1.1 Dynamic vs. Static Approach

1.1.2 Assumptions

1.1.3 Prior Research

1.2 Our Contribution

1.3 Background

1.3.1 Binary Decision Diagrams

1.3.2 Schneider, Schlichtmann, Wurth Algorithm

2 IMPLEMENTATION

2.1 Interface

2.1.1 Modes

2.1.2 Error Handling

2.1.3 Calculation Wait-Mode

2.2 Data Structures

2.2.1 IBM Data Structures

2.2.1.1 Keywords

2.2.2 BDD Data Structures

2.2.3 Application Data Structures

2.2.3.1 Mode Data Structure

2.2.3.2 Primary Input Data Structure

2.2.3.3 Primary Input Data Structure Alternatives

2.2.3.4 Net Data Structure

2.2.3.5 Proto-box Data Structure

2.2.3.6 TCL and Data Structures

2.4 Queueing and Levelization

2.4.1 Queue Data Structure

2.4.2 Queue Data Structure Justification

2.4.2 Callbacks

2.5 Recursive Algorithm

2.5.1 Applying the Formula

2.5.1.1 State Probability Calculation

2.6 Integration of Queueing and Recursive Algorithm

2.6.1 Two-Procedure Recursion

4

33

34

34

35

36

28

28

31

32

37

37

38

41

42

43

24

25

26

27

28

46

51

58

58

60

9

10

9

11

12

14

15

16

19

3

4

2.7 Initialization

2.7.1 Global BDD Table

2.8 Primary Input Probabilities

2.8.1 Default Mode Probabilities

2.9 Checkpoints

2.9.1 Data Holder Data Structure

2.9.2 Duplication

2.9.3 Generating Reports

2.9.4 Checkpoint Deletion

2.9.5 Checkpoint Triggers

2.9.6 Updates

2.9.7 Net Creation

2.9.8 Net Deletions

2.10 Cuts

2.10.1 Criteria

2.10.2 Cut Data Structure

2.10.3 Cut Implementation

2.10.4 Creating Cuts

2.10.5 Probability Maintenance

2.11 Expansion Views

2.11.1 Expansion Box Mapping

2.11.2 Chained Expansion Boxes

2.11.3 Caching

2.12 Latches

IMPROVEMENTS

TESTING

5 RESULTS AND CONCLUSION

REFERENCES

APPENDIX

Appendix A: Data Structures

Appendix B: Usage

Appendix C: C Command Reference

5

93

101

101

102

105

94

99

73

74

76

77

67

68

70

71

72

81

83

84

78

80

81

62

63

64

66

85

87

89

89

90

92

Appendix D: TCL Test Scripts auxfunctions.tcl primary-test.tcl multiple-change.tcl

Appendix E: Source Code swaux.C swcalc.C swcallback.C swscheckpoint.C swcursor.C sw-global.C swinit.C swmode.C swnetdata.C swnlist.C sw-pidata.C swplist.C sw-protodata.C sw-queue.C switching-dll.C swswitching.h switching.h

111

111

117

120

124

124

181

184

191

196

168

169

173

174

158

160

164

165

125

139

145

155

6

LIST OF FIGURES

Figure 1.3.1a BDD representations of various functions...........................................16

Figure 1.3.1b Calculating state probability of an AND function .................

Figure 1.3.1c Examples of BDD orderings..............................................................

17

17

Figure 1.3.1d 2 different BDD orderings for a b OR ac.............................................18

Figure 1.3.le D efinition of co-factors ....................................................................... 19

Figure 1.3.2a (a) XOR circuit (b) BDD representation .............................................

Figure 1.3.2b Present- and Next-state BDDs ............................................................

20

20

Figure 2.1.1 a An example of modes and initial probabilities for primary inputs ..... 27

Figure 2.2. 1a An example of a def-box to usage-box mapping .................................. 29

Figure 2.2. 1b An example circuit with EDA definitions ...........................................

Figure 2.2. 1c Examples of source and sink pins ........................................................

30

31

Figure 2.2.1.1a Example code for using keywords....................................................32

Figure 2.2.2a An ROBDD and a general BDD data structure layout.........................33

Figure 2.4.2a Source end disconnected .....................................................................

Figure 2.4.2b Sink end disconnected .......................................................................

44

44

Figure 2.5a Traversing through a circuit by net-pin-usage box-pin-net loop ........... 46

Figure 2.6. 1a Steps for the net reconnection............................................................ 61

Figure 2.6. 1b Example scenario where "q" represents queued nets ............................ 62

Figure 2.9. 1a Example checkpoint structure instance ............................................... 69

Figure 2.9.3a Report data structure ........................................................................... 72

Figure 2.9.4a Deleting a checkpoint ......................................................................... 73

Figure 2. 1Oa Cuts: creating semi-independent circuits.............................................79

Figure 2. 1Ob Cuts: respective BDD representations of cuts ...................................... 80

Figure 2.10.3a Example circuit and BDDs before cut..................................................82

Figure 2.10.3b Example circuit and BDDs after cut ...................................................

Figure 2.11a Expansion boxes................................................................................

83

87

7

LIST OF TABLES

Table 5a

Table 5b

Table 5c

Table 5d

Table 5e

Comparison of run time in real seconds .............................................

Error rates for BDD threshold of 20....................................................95

Error rates for BDD threshold of 50....................................................95

94

Times & error rates for a change at a randomly-picked net of level 1......96

Times & error rates for changes to 10 randomly picked nets of level 1 ...97

8

1 Introduction

The optimization of low power circuits has recently become an important issue for engineers, due in part to the increase in popularity of wireless and handheld devices that rely on limited battery sources. In addition, other technologies, such as high performance servers, need to control their power consumption because of overheating concerns. For greater profitability in the low power market, designers should decrease the average time for a design cycle. To that end, a key goal is to develop more efficient and accurate optimizing tools. Computer-aided design programs, in particular, are a set of tools that can significantly affect the rollout time. Several of these applications assist with power optimization, which is a step-by-step process that tweaks circuit characteristics to minimize power consumption. Each modification requires power recalculations to determine whether or not the change decreased the power output. A fundamental element in these programs is the algorithm used to calculate the power for a circuit. Since many modifications may be applied to one circuit, there may be a substantial accumulation of time-savings by using more efficient algorithms to calculate power.

1.1 Power Calculation Algorithms

Therefore, our focus is to develop a method to calculate power in a novel and more efficient manner. We will first concentrate on strictly combinational CMOS circuits in which the switching power dominates. In these cases, the standard summation equation over all signals in the circuit is signal

-Ci VDD2f E(i) i 2

(1.1)

9

in which VDD is the voltage supply, Ci is the total input capacitance to signal i, andf is the frequency of the clocked circuit. Equation 1.1 ignores the contribution of leakage and cross-current power. Ci,

VDD

2 , andf are easily derivable from existing formulas. E(i), the switching activity of signal i, is more complicated to calculate. Switching activity, also referred to as switching probability, switching factor, or transition probability, represents the probability that the signal will switch values from one cycle to the next, i.e. the probability that a signal i has a value of 1 at one cycle and changes to a value of 0 upon the next cycle, or vice versa. The switching activity for a signal is dependent on data from the signal's inputs, thus switching activity calculations may require averaging over inputs. This problem has provoked much research and investigation into finding accurate and fast solutions.

1.1.1 Dynamic vs. Static Approach

The solutions that have been produced may be divided into two categories. The first category typically involves simulating the circuit with a number of different input sequences to estimate switching activity. Using simulations is referred to as a dynamic approach. Since simulating all possible combinations of input values may take an unreasonable amount of time, it is important to find a good set of sample input sequences that maximize calculation accuracy. Several algorithms have been proposed to solve this problem, such as a weighted max-satisfiability approach'.

The second category uses what is called a static approach rather than simulation.

The approach relies on probabilistic formulas or similar equations to calculate switching activity based on the logical function of the given circuit.

The advantage of a dynamic approach is that given a good set of input sequences,

10

the results may be very accurate. If higher accuracy rates are desired, larger sets of sequences must be simulated, thereby increasing run time. On the other hand, the static approach does not rely on input sequences, so the run-time can be much shorter. Also, probabilistic equations may produce accurate results as well, though generally not as accurate as simulation results.

1.1.2 Assumptions

Because our goal emphasizes efficiency more than accuracy, we will take the static route. There are several key assumptions and models that play a role in the accuracy and performance of static methods. One of the more significant assumptions affecting accuracy regards the time delay characteristics of the gates and signals. The three most common delay models encountered in static approaches are zero-delay, unitdelay, and general-delay. Zero delay models assume that gate transitions happen instantaneously. In unit-delay models, each gate has a delay value of one. General delay models allow for an infinite range of delay values. Zero delay is the simplest of the three models and research implementing zero-delay models usually performs faster. However, the tradeoff is the accuracy. Unit and general delay models allow for multiple transitions within a cycle and thus analyze signal glitching. Because a higher number of transitions cause more power to be used, glitching activity can cause a significant increase in power consumption. Therefore these two models are more realistic. The models may also account for slower switching times due to larger fan-in or fan-out nodes of gates, which also affects transition probabilities.

Fan-out signals also play a part in another assumption, which deals with spatial correlation. Spatial correlation is a measure of the logical dependencies between signals

11

within a circuit. Fan-out signals of gates may eventually converge as input signals into another gate. This behavior complicates probability calculations for a gate because intermediary inputs cannot be assumed to be independent. If one were to assume there was no reconvergence, in other words that there was no spatial correlation, the accuracy would be decreased. Accuracy is also dependent on the assumption of temporal correlations, which describe the relationship of the state of a signal from one cycle to the next. If temporal correlation is not taken into account, then signals are assumed to be temporally independent. This signifies that the next state of a signal does not depend on its current state. Since this characteristic may not be true in many cases, an assumption of temporal independence may also lead to inaccuracies.

Independence issues affect primary inputs as well. By assuming that primary inputs are mutually independent, probability equations can often be reduced to a simpler form and thus decrease the calculation time. However, mutually dependent primary inputs can significantly impact the switching probabilities of fan-out signalsp1]

1.1.3 Prior Research

The issues above present interesting problems for researchers to tackle. The following section will compare five different approaches to the switching activity problem. Each research performs calculations either globally or through incremental propagation. Incremental propagation involves equations that can be computed for a given signal, based on equation results from the signal's immediate fan-in input signals.

A global calculation computes a solution by accumulating information from all signals within the circuit for use at one time. Global calculations may suffer from a limit on time and memory resources for very large circuits. However, the payoff is typically a more

12

accurate result.

A common static switching activity calculation technique is the use of correlation coefficients to describe the dependencies between signals. Marculescul

1 1 et. al. derived complex probabilistic equations using pairwise correlation coefficients coupled with the notions of conditional independence and isotropy. The research accounted for temporal and spatial correlation and primary input independence. The results were quite accurate in this research field due to these considerations, given that a zero-delay model was assumed. Although incremental propagation was implemented, the application ran slower than average.

Uchino[ 2

1 et. al. also incorporated the idea of correlation coefficients in their

Boolean Approximation Method, but computed these values using a version of Taylor's expansion formula. The simplifying assumptions of a zero-delay model and independent primary inputs were used. The results had a low error rate in comparison with simulations and the algorithm run-time was relatively fast. This effort also used incremental propagation.

In contrast to the two approaches mentioned above, Ghosh[31 et. al relied on a general delay model. The research used symbolic simulation, a method that is able to examine glitching by finding the set of Boolean conditions that cause it. It is able to calculate the probability of each gate switching at any particular time point based on the

Boolean function. In addition, the formulas were extended to handle sequential circuits as well as combinational circuits. The application was accurate given that independent primary inputs were assumed.

Another general delay model approach was introduced by Theodoridis 4

1 et al.

13

Their equations were based on Markov stochastic processes. The research also assumed independent primary inputs. It is the only one of our examined research papers that used global calculations.

The last paper we will describe relies heavily on the use of binary decision diagrams (BDDs), which are data structures we will discuss in section 1.3.1. The algorithm presented by Schneider 5

1 et al. computes one Boolean function at each gate, which is used to compute the switching probability. Given the assumptions of a zerodelay model and independent primary inputs, the program is able to produce exact probabilistic answers for small circuits. The error rate is reasonable, and an important advantage of the application is its simplicity. This research will be discussed in more detail in section 1.3.

1.2 Our Contribution

Upon examination of the prior research, we note that none of the efforts focused on streamlining switching activity calculation specifically for logic optimization. An important consideration of logic optimization is that when a structural modification is applied, the overall function of the circuit should not change. Actually, the modification should only affect the switching activity of dependent signals, which signifies that there may be a boundary encompassing all affected signals in the circuit. Because the power calculation formula allows us to calculate the power of each signal individually, the power of unaffected signals remains unchanged. Consequently for efficiency purposes, we would only need to recalculate the switching activities of signals lying within the boundary. We would thus save time by avoiding the unnecessary recalculation of other

14

switching activities.

Therefore we would like to introduce an algorithm that serves as an incremental switching activity calculator. Incremental in this sense refers to the idea that appropriate individual signal switching values are updated with each single circuit modification during optimization. Our goal is to use an existing switching activity algorithm as a base, and build upon it the mechanisms to achieve incremental calculation. Since we are aiming to divide the circuit into affected and unaffected regions based on each signal's logic function, we focus on programs whose equations rely on Boolean functions.

Algorithms that depend on correlation coefficients, such as those of Marculescu or

Uchino, would be too complicated to extend for incrementality. Ghosh's approach also appears difficult to extend. The simplicity and quickness of the method of Schneider, et.

al makes it a good candidate for our algorithm.

The positive impact of such an application to the CAD community can be supported by research demonstrating the effectiveness of logic optimizations (as opposed to component resizing, etc.) on reducing power consumption. For example, S. Iman et.al 6

1 discussed the use of don't care sets to optimize net logic functions for low power.

1.3 Background

We will describe the Schneider, et. al 5 into the specifics, we would like to give a brief description of binary decision diagrams, a data structure well suited for use in [5] as well as in many other CAD applications. Karl

Brace et. al 7

3 presented a breakthrough in the use of BDDs by developing a package of

BDD procedures that are highly efficient.

15

1.3.1 Binary Decision Diagrams

Binary decision diagrams are a form of binary trees which can be mapped to any

Boolean function. Each BDD node corresponds to a variable of the function as shown in the following figure.

f=((Wand 0) or (w and 1)

0/

OW

\

0 1

0

1 0

f= X. (Y-

= x-.-

0 +y( 0 +z. 1)))+ x- (2- 0 +z -1)

Z+ X- z

=z-

(x+X-y

=z-(x+y)

-----, nodes

0 1

0 yZ

1

0 z

0/ \i

0 1

0

0

1

1 w-,* terminal nodes

Figure 1.3.1a BDD representations of various functions

BDDs are particularly helpful in representing logic circuits and solving circuit problems, such as combinational logic verification"'

0

1. As shown in figure 1.3.1b, each primary input to the circuit is mapped to a variable of the Boolean function. The probability that a logic circuit would output a high, or one, can be calculated knowing the state probability of each variable, or input to the circuit, by traversing the BDD tree.

Figure 1.3. lb demonstrates a simple example. We will use an expanded form of this method to calculate the switching probability, or equivalently the switching factor, which we will discuss in section 1.3.2.

16

a -a

AND

b -- f f=a-b

0.7

0.4 0.6

A ,

p (a=1)=0.3

p (b=1)=0.6

p (a - b)=

0.7 *p()+ 0.3 0.4

*p(O)+

0

.3 * 0.6 *p(l)

0.18

Figure 1.3.1b Calculating state probability of an AND function

Binary decision diagrams come in many forms. A specific form of BDD used in many efficient BDD packages is called a reduced ordered BDD (ROBDD)'14 . A BDD is ordered when all paths from the root node to any of the leaves have the same variable ordering, with each variable occurring at most once on each path (see figure 1.3.1c). A

BDD is reduced when each node represents a unique function. The variable ordering gives ROBDDs the property such that any two functions that have the same variable ordering and the same ROBDD must be the same function. Therefore an efficient BDD package would impose one variable ordering pattern on all BDDs that it creates. It would then be able to quickly perform evaluations such as checking the equality of two functions by checking the equality of their respective ROBDDs.

orderedBDD

0 z

0 1

A~ i

I-

X c urorderedBDD

0/

X

-

<'< xe

1 0 z

0

$

1

0 z z y

0'

0 1 0 1 different order

Figure 1.3.1c Examples of BDD orderings

It is possible to change the ordering scheme at any time as long as it remains

17

uniform throughout the entire BDD space. This means that all BDDs must follow the same scheme. The change is known as dynamic reordering, and is a helpful procedure to invoke after periods in which a large number of BDD manipulations occur. The problem with ordered BDDs is that despite the efficiency of canonicity, no one ordering is guaranteed to produce minimally sized trees (see figure 1.3. 1d). Propagation of a large

BDD tree may nullify any expedience gained by the ROBDD properties. Therefore dynamic reordering investigates the current BDD space and attempts to find an ordering through permutations that will reduce the BDD sizes. If successful, the package will reorder all BDDs. This process will be transparent to the user, since reorderings will have no effect on the BDD logic functions. The negative impact of ordering constraints will be discussed in more detail in section 2.10.

ordering: a, b, c

00

0 b ab

1

C

0

0 1

ordering: b, a, c a

1

0 a

0 1

Figure 1.3.1d 2 different BDD orderings for a b OR ac

The structure of a BDD is based on the Shannon Expansion theorem, in which a function F of a variable x can be represented by F(x) = x * F(x) + x * F(x). Assuming that the root variable of a BDD is x, the left subtree, or low child, represents the function after the variable x is set to 0, and the right subtree, or high child, represents the function after the variable x is set to 1 (see Figure 1.3. le). Each node of the BDD follows the same pattern. The low child's representative function can also be referred to as the

18

negative cofactor of the BDD with respect to x, because the function is being factored with x = 0. Similarly, the function of the high child can be referred to as the positive cofactor.

tree respresents

F negatively cofactored with respect to a

0 b

0

1

Cofactors a

0

..

positively c

.cofactored

1

1 r .

hichil d lo child

Figure 1.3.1e Definition of co-factors

1.3.2 Schneider, Schlichtmann, Wurth Algorithm

BDDs play a very important role in the algorithm developed by Schneider, et. al.

The following section will describe the theory of the research. It assumes zero-delay gates and independent primary inputs, but takes into account spatial and temporal correlations among internal signals within the combinational circuit.

To begin, every signal is associated with two isomorphic binary decision diagrams that represents the signal's logic function. One BDD is denoted as "presentstate", representing the signal at an arbitrary time t = to, and the second BDD is denoted as "next-state", representing the signal one clock cycle later at time t = to + T.

Essentially, two instances of the circuit are created and assigned different names to each primary input, as seen in figure 1.3.2b. Thus, one primary input from our original circuit maps to two different BDD variables.

19

X

1

X

2

~

0 r

0

Al

1

0 1

1

(b) (a)

Source: Schneider, Schlichtmann, Wurth

151

© IEEE

Figure 1.3.2a (a) XOR circuit (b) BDD representation

X

2

X20 0

0

1

X2

0

0 rA

1 present-state BDD next-state BDD

Figure 1.3.2b Present- and Next-state BDDs

Given the present-state BDD and the next-state BDD, the next step is to calculate the probability that the present-state and the next-state have different values. This is equivalent to the probability that a transition has occurred from one cycle to the next. As a means to calculate the probability, we first generate a function that describes the transition characteristics of the signal's function by retrieving the exclusive-or manipulation of the state functions. By doing so, we result in a transition function BDD in which all paths that lead to the '1' terminal node produce all possible input sequences that trigger a transition between two cycles. This follows because an exclusive-or is 1 if its inputs are different, and in our case the inputs are the present and next states

We would like to propagate probability equations through this transition function

20

BDD in a similar manner as was done to find the state probability of a function in figure

1.3. lb. Instead of calculating the state probability, the goal here is to calculate the switching probability. The complication is that the state probability only relies on one state for its simple equations, but the transition function is composed of two states, the present and next. Schneider, et. al's algorithm applies one-lag Markov chains to derive two-state probability equations.

At this point is still unclear how to directly apply the equations to the transition

BDD for a resulting switching probability. Shannon's expansion formula is used to provide a recursive procedure to perform the calculation as demonstrated in the following paragraphs.

Given that variables xo, x

1

, ... xn represent all of the other internal signals that y depends on, f(x) is defined to be the Boolean function for y. n is the total number of all of y's fan-in primary inputs. Therefore, the Boolean function of change, labelled Tf, is equivalent tof(x") D f(xt). The switching probability E(y) is thus p(Tf= 1), or p(T).

The ROBDD representing Tf is labeled the TFBDD.

The notation Tf is understood to be the function Tf cofactored with respect to the variable xi. By Shannon's expansion formula and cofactoring with respect to variable xi,

0

Tf = xioTf

Xi

+ X 0Tf

.

results in

By repeating the same procedure but cofactoring with respect to variable xi

T

Tf

Tf

=

xi xi TTf XiXi + xi g Tf ' +

7

Tf

+ X x Tf

X

.

21

Noting that the terms x

0 xi, x

1

T, x.ixiT and j X are mutually disjoint because only one of the terms can be true at any one time for a pair of input vectors, the probability p(Tf=xi xiT

Tf

Xi X +Xi xi TfIi+Xoxi Tf xixi + x TTf i) can be rewritten as p(xi" x

1

Xi~T+PXOV

Tf x)

+ p

T

TT0

Tfx?4) + p( xi Tf xi) +

(

_ f

Tf i0X

Furthermore, since the primary inputs are assumed mutually independent, p(TJ) = p(xi xi T) p(Tf

XIOXT

) + p(xi x

T

) p( Tf ?xT) + p( xiO ) p( Tf

XI

) + p(x

0

X )p(Tf Xi' )

Using the one-lag Markov chain formulas, for a variable xi at time point t 0 and to +

T, the probabilities are as follows: p(xi T

)= p( xi T)

= E(xi)/2 p(xxi x

) = p(xi) -

E(xi)/2 p( x ) =

1 p(xi) E(xi)I2 where p(xi) is the initial state probability of the input corresponding to variable xi, and E(xi) is the initial switching factor or probability.

The following figure illustrates how an example TFBDD is computed.

22

E(y) =

E[f(x)]

= p(T) = [p(x

1

Ox

1

T) + p(X

0

XT)] p(h1)+

[p(x

1

X ) + p(xO x )] p(h

2

) p(hi) = [p(x

2 x

2

T) + p(x20 x

2

T )] p(O)

+ [p(x2

0 x2T

)+p(x x2 )] p(l)

0 1 p(h

2

) = [p(x

2 ox

2

) + p( x

2

0 x

2

T

)] p(O)

+ [p(x

2

X

2

T) + p(X

2

Ox

2

T)] p(1)

Source: Schneider, Schlichtmann, Wurth [5@ IEEE

Figure 1.3.2c TFBDD of y [(1 x

2

0

) e

(xi x

2

T)]

Figure 1.3.2d Recursive computation

We must be careful that the variable xi immediately follows variable xiY in the ROBDD variable ordering so that when the XOR of the present and next-state functions are computed the two variables will appear adjacent to each other in the resulting ROBDD as exemplified in figure 1.3.2c. It is not uncommon that when the TFBDD is computed, some variables may disappear from the resulting function, signifying that the switching function is not dependent on those variables. The following figures illustrate the possible cases that can occur and how the probabilities are calculated given those cases:

23

0

X10 Tf

S

* S

Source: Schneider, Schlichtmann, Wurth

O ~)

@' IEEE

S

P xT p(x?x

7

) p(X~)

(a) (b) xi(d) xT x10 p(Xx~ p(x?x9) x pSx) p(xpiX p(x?xj

7

PSx) P(xO)

(c)

Source: Schneider, Schlichtmann, Wurth [5

IEEE

Figure 1.3.2f Probabilities of the

5 cases

2 Implementation

(e)

The next sections will concentrate on the implementation and design issues. In the first section, we will explain how we expect the user (be it a program or an actual person) to interface with the application. Following this, we will describe our data

24

structures. Then we will examine the key concepts that our incremental ability relies on, and the algorithms that were created to perform our application duties. Afterwards we will discuss the flow of the procedures and important details that contribute to the effectiveness of our implementation.

2.1

Interface

The development of our application makes use of valuable tools in the IBM EDA

(Electronic Design and Automation group) software suite. Those that are most relevant to our endeavor are the Booledozer and PowerCalc applications. PowerCalc provides procedures to compute power for a given circuit through both simulation and static methods. However, the static power calculator is inaccurate due to a wrongful assumption. Booledozer is a logic manipulation utility that is used to transform circuits.

A specific EDA application that we adapted many of our incremental concepts[

15

1 from is Einstimer, a static timing tool that assists in reporting time delays and constraints for circuits. Although our algorithm follows a different logic than is used in the timing application, several of its methods are directly applicable to our case.

As is standard with IBM EDA programs, we used the C language for development while including TCL code to communicate with other programs. A specific package called Ci allows TCL scripts to import and export information from and to C-compiled programs. EDA programmers had adapted the TCL shell to fit their specific needs into a command-line driven interpreter called Nutshell, which is used to run most of the EDA tools. The tools, written in C, are compiled as dynamically linked libraries (DLLs) and can be loaded individually into a Nutshell session in order for the user to call the tool

25

procedures. Our interface takes in a circuit file as input from the user and allows the user to make changes to the circuit using Booledozer procedures and query about switching activity values.

2.1.1 Modes

In designing the interface we aimed to accommodate the most common usages of the switching factor calculator. As observed in practice, several power calculations may be performed for the same circuit with different sets of primary input statistics. This procedure allows the user to compare the power variance between different modes of operation for a circuit. For example, a circuit that is in a "running" mode may have higher primary input switching probabilities than that same circuit in an "idle" mode. For the convenience of the user, we incorporated the notion of "modes" within our application model. Therefore, in addition to the input of the circuit itself, the user would provide definitions of one or more modes for the circuit.

For each one of those modes, the user must assign a set of state and switching probabilities for all primary inputs of the circuit. The user may also define a default switching and state probability for a mode. All primary inputs that do not have their probabilities explicitly defined by the user will inherit these default values.

26

Mode run idle standby

Switching Prob. Static Prob.

P P2 P3 RI P2 P3

0.6 0.8 0.8 0.5 0.6 0.5

0.1 0.2 0.3 0.2 0.1 0.2

0.2 0.1 0.0 0.1 0.1 0.0

P1

P2 p3 )

AND

NOT

Figure 2.1.1a An example of modes and initial probabilities for primary inputs

Given this setup, the user has a natural method for requesting the switching factor for a particular mode.

2.1.2 Error Handling

To ensure accuracy within our application, we need to account for the possibility of errors. Unfortunately, there are no standard procedures in error handling within the

EDA tool suite. Considering that our program is built on the C language, the common use of exceptions in object-oriented languages such as Java would have been too complicated for our purposes. Instead, we developed the interface such that all functions and procedures would have a return value of a Boolean type. The value would be false if an error or inconsistency occurred during any step of the procedure. If this were the case, an error message would be printed to the standard error file. If the error was severe enough to inhibit any following actions to proceed in a reasonable manner, the procedure may force an abnormal exit of the entire tool. Otherwise, the calling procedure will handle the false return value appropriately. On the other hand, a true return value indicates that the procedure ran smoothly. Other return values are stored in pass-byreference parameters.

27

2.1.3 Calculation Wait-Mode

Another design issue concerns the strategy used for performing the calculations.

Once the primary input probabilities are assigned, it is possible to begin calculating all switching factors immediately. However, we decided to operate in a wait mode using the philosophy that calculations should be computed only if the user initiates them. This technique avoids extraneous processing time that may be a waste if the user never needs certain calculated values. Basically, when a logic optimization step is performed, no action is taken until the user explicitly queries for a switching factor computation on a net.

2.2

Data Structures

Our data structures were designed to maximize efficiency while guaranteeing full compatibility with existing IBM data structures. We will give a brief overview of IBM's data structures and those of the BDD package, and then continue with our own definitions. A comprehensive view of data structures can be found in Appendix A.

2.2.1 IBM Data Structures

To implement and extend this algorithm for our purposes, we will use IBM EDA software definitions, which are programmed in C++. The following will describe the

EDA model.

Logic circuits are parsed by gate and signals into a "netlist" description. This description is in turn encoded into text file format that can be read and translated by various IBM EDA tools. The circuit is separated into three components: Boxes, nets, and pins. Boxes are high-level containers of logic functions, such as AND/OR/NOT gates.

28

Nets are equivalent to the circuit signals, or wires, that connect each box. Pins are the interfaces between the nets and the boxes.

Boxes themselves are divided in a hierarchal manner. Our interests concern three main types of boxes: a prototype box (proto-box), definition box (def-box), and a usage box. One proto-box exists for each circuit. The proto-box contains all boxes, nets, and pins for the circuit, and also handles the primary inputs and outputs. A def-box is a skeleton of a logic block and its components. A def-box can be completely defined by one or more Boolean equations representing the box's function(s) and the specification of input and output pins of the logic block. For example, as shown in figure 2.2. 1a, the definition box of a 2-input "AND" gate would name two input pins "A" and "B" as well as an output pin "C", with the function being "C=A&B". Proto-boxes essentially are specialized def-boxes and in fact are defined under the same data structure. Usage boxes are instances of def-boxes. In a circuit with 3 "AND" gates, there would be 3 usage boxes mapping to each instance, and 1 definition box describing the AND gate. Note that although usage boxes have different names than the definition box, each usage box pin customarily retains the name of its def-box pin counterpart.

DEF-BOX (AND gate)

B

Figure 2.2.1a An example of a def-box to usage-box mapping

29

proCo-im 62npu:) ugo i ptpm

A-proto-pin primsy inpAs;

, sfwe i NOT b 3xesis Toxhy n

- -- Uage bo .

pwto-bax

Figure 2.2.1b An example circuit with EDA definitions

A set of pre-defined def-boxes for common gates such as the AND/OR/NOT gates as well as components such as latches and registers are stored for use in the software library. The name for these boxes is Technology-Independent Blocks (TIBs).

They are found in a specially formatted file known as an SRULE file. The file is composed of entries, one for each def-box containing pin definitions and equations, as well as other characteristics. Users may define their own SRULE files in addition to the standard TIB.SRULE file.

Nets are straightforward; however, nets that are primary inputs or outputs are featured as "proto-nets" because they are connected to the proto-box.

Pins also fall into two categories, though at the most basic level all pins are structurally identical. One type is a proto-pin, which is any pin that connects to a primary input or output net. The second type is a usage-pin, which is located on a usage box. If two pins are connected by a net, the pin at the end of the net closest to the primary inputs is said to be the "source" pin, and the pin closest to the primary outputs is called the

"sink" pin.

30

source pin for bold net sinkpinsfor bold net

AND

OR

) t NOT

Figure 2.2.1c Examples of source and sink pins

Each of the VIM data structures is a C++ structure and is most often referred to via pointers. We will label pointers to the structures in capital letters, for example a

"struct net*" is aliased as "NET". The NET, PROTOBOX, DEFBOX, USAGEBOX,

PROTOPIN, and USAGEPIN pointers are the most commonly used within our implementation.

2.2.1.1 Keywords

A useful aspect of the IDM development is the availability for users to create additional fields on the box, net, and pin data structures. Each new field is defined in a variable called a keyword. The definition requires the user to specify the name of the variable, the data type, and which data structure to add the variable to. Afterwards, the user can use the new variable or field through existing keyword procedures. See listing

2.2.1.1a for an example of how keywords are utilized.

31

KEYWORDDEF keyubox num inputs;

KEYWORDDEF key-pboxlinkedlist;

KEYWORDDEF key-pbox numnets;

// creating keywords keyubox-num-outputs = locateorcreatekeyword-def (CLASUSAGEBOX, "keyubox num inputs",

VARTYPEINTEGER, C); set keyworddefaultvalue(key uboxnumoutputs, -1, C);

// keywords on a proto box keypbox linkedlist = locateorcreatekeyworddef (CLASPROTOBOX, "keypbox-linkedlist",

VARTYPEUNKNOWN, C); setkeyworddefaultvalue(keypboxlinkedlist, NULL, C); keypbox-numnets = locateorcreate_keyworddef (CLASPROTOBOX, "keypbox num-nets",

VARTYPE_INTEGER, C);

... (later in the code)

// storing a value into keywords using USAGEBOX ub set keyword value (ub, keyubox-num inputs, 2, C);

// retrieving a keyword value for PROTO_BOX pb

// C is a global context that is already provided locate keyword value (pb, keypboxlinkedlist, &11, C);

Figure 2.2.1.1a Example code for using keywords

Keywords can be of any type: integer, character, or a void * for generic types.

2.2.2 BDD Data Structures

Booledozer includes a BDD package adapted from [7]. The package includes its own garbage collection and hash table functionality. The structure is listed in figure

2.2.2a.

The BDD package also allows users to add data fields to the BDD data structure.

The user must specify the amount of memory needed by the new fields on initializing the package. After this is defined, the amount of memory cannot be adjusted. The consequence of this constraint will be discussed in Section 2.7.

32

0

0

.

X -10-

1

---

31 30 29 .. O 9 variable ID # E

1 8 1 7 65A..

M refcount then link link next auxl (genera_purpose) optional userdata bits

Figure 2.2.2a An ROBDD and a general BDD data structure layout

A BDD function is represented by a pointer to a BDD tree. Each node of the tree is associated with a BDD variable. Each variable is uniquely defined by a number. In figure 2.2.2a we describe the BDD for the XOR function which maps to the circuit in figure 1.3.2a. Notice that variable ID #1 maps to one of our primary inputs, x

1

. In the

BDD space for our application, all variable ID numbers will be associated with some primary input.

In section 1.3.1 we discussed the benefits of dynamic reordering. However, dynamic reordering may pose a serious problem because Schneider, et. al's algorithm hinges on present- and next-state variables being next to each other in the ordering. If a reordering separates the variables then the calculations would be chaotic. Fortunately, the BDD package includes a routine that allows us to group variables that we need to keep together should a reordering occur. Groups will be reordered rather than individual variables.

2.2.3 Application Data Structures

The following sections will detail our data structures and their design, as well alternatives. First we will discuss our structure to represent modes. Following this, we

33

will describe data structures used to store information about primary inputs, nets, and the entire circuit in general.

2.2.3.1 Mode Data Structure

The mode data structure is simple, containing four data fields. Three of the fields store the literal name of the mode and the default switching and state probabilities for the mode. The fourth field is a unique ID number. All modes are numbered sequentially beginning with zero. Other data structures, such as the primary input data structure, refer to individual modes using the unique identifier.

2.2.3.2 Primary Input Data Structure

Primary input data structures store information for one primary input. The data includes initial state and switching probabilities. These probabilities are stored in an array, whose length is the number of existing modes. Each array element is a secondary data structure, whose four fields are one switching probability, one state probability, one

Boolean value indicating whether the switching probability is derived from default mode values, and another Boolean value that indicates the default status of the state probability.

For efficiency, the switching probability is stored as half its value because the probability equations always refer to its halved value. The Boolean values are initially true until the user explicitly specifies switching or state probabilities for this primary input for the associated mode.

The array offset number of each element corresponds to which mode the element is related to. For example, the second element in this array contains the initial probabilities of the primary input under the mode identified by the number two.

We also need to store BDD information about this primary input. Each primary

34

input is represented by two BDD variables as discussed in section 1.3.2 for present- and next-states. Therefore we have two fields storing the ID numbers of the present- and next- state variables.

We appended this primary input data structure to the IDM's proto-pin data structure using keywords, which were discussed in section 2.2.1.1. The variable name of the keyword is keywordprotopidata.

Although traditionally primary inputs cannot be located internally within the circuit, the program allows for users to define primary inputs within the circuit, at usage box pins. The user may wish to do so because the user may be aware of circuit details that cause these internal pins to behave like primary inputs. For example, nets leading into certain usage pins may actually be independent from any fan-in input nets.

Therefore, we appended the primary input data structure into a field for the usage-pin data structure as well, under the keyword keywordusage-pidata. Usage pins that are not representing primary inputs will have this field be empty.

2.2.3.3 Primary Input Data Structure Alternatives

This section will discuss alternative data structure solutions and tradeoffs. The main issue concerns how to distinguish between primary input probabilities that rely on default values and those that do not, i.e. those that are explicitly defined by the user. The difference is important because we allow the user to change default mode probabilities at any time during the program run, and we would need to find and update all primary input probabilities that rely on the changed defaults.

Our current configuration stores Boolean values on every probability value. An alternative would be to keep a linked list for each mode of all primary inputs that are

35

using the mode defaults. This may be a space concern if there are many primary inputs that use defaults, because pointers in linked lists require more memory than Boolean values, which are one bit each. However, performance-wise, the linked list should be at an advantage because default changes require a simple traversal of the linked lists to find which primary inputs to update. For the Boolean approach, we would need to examine the Boolean values of all primary inputs to determine whether it relies on a default value.

Since we do not anticipate default probability updates to occur often, we chose the spacesaving approach.

Another alternative concerns which IDM data structure we store our primary input data structure with. We could have easily stored it on the net data structure, since all primary inputs are connected to a net. However, pins are much more stable than nets because they are bound to the proto-box. Nets may be disconnected from boxes and moved in a completely different area on the circuit. Users expect to define initial probability values at a specific primary input; our decision to refer the input to a net or to a pin is insignificant in their point of view. A user may manipulate a net without realizing the effect on primary input information. To prevent complications from such mishaps, we store the primary input data on pins.

2.2.3.4 Net Data Structure

This paragraph will detail the data structure to store information for nets. Each net represents a logic function. Based on Schneider, et. al's algorithm, each net should then store two function BDDs for two states. Also, we would like to cache switching factor values on the net, so that multiple queries on the same net would only require one calculation. The cache would be an array, which stores values for each mode. We will

36

add this data structure to IDM's net data structure, using the keyword keywordnetdata.

2.2.3.5 Proto-box Data Structure

This application may work with multiple circuits or proto-boxes at a time.

Therefore we need a compact data structure for each circuit that can reach all related circuit information. In particular it should be able to access all associated modes, primary input data, and net data.

We can make a linked list of all primary input data structures for a proto-box.

This is convenient upon deletion of the proto-box because we have a mechanism of deleting all associated primary input data. Net data can also be stored in the same manner for similar reasons. Since we are accessing modes by their identifying number, it is most suitable to store modes in an array. All of this information will be stored for a protobox, and added to the IDM protojbox data structure under the keyword keyword-protodata.

2.2.3.6 TCL and Data Structures

Our data structures were partially developed based on their interaction with the

TCL user interface. The goal was to compact the information into as few objects as possible so that the user would not have to be responsible for very many data objects.

The protodata keyword for the proto-box already contains a large set of circuit-specific information. On examining the user interface (see Appendix C) it is apparent that the user will often need to provide a mode as a parameter. Because a mode is specific to only one proto-box, it is logical to add a link to the proto-box keyword data into the mode data structure. This way, the user should only need to keep track of the user's modes, which will inherently contain information about the circuit. The link is also efficient

37

because we avoid a keyword lookup on a given proto-box of a circuit to access protodata related to a mode that the user supplies.

2.4 Queueing and Levelization

The key goal of our incremental switching factor calculator is to determine which nets need to be recalculated following a logic modification. As demonstrated in section

1.3.2, the switching probability relies on only two factors: the logic function represented

by the net, which is encoded into a BDD, and initial primary input probability values.

Therefore, the only nets that need to be recalculated after a physical circuit change are those nets whose logic function also changed. The main focus is to efficiently determine all nets that have undergone a function change.

This requires the caching of the net function in the form of its BDD for each net, so that we can compare the function before and after a modification. The cached BDD will be stored in a field in the net data structure.

The general scheme of our incremental application will be the following.

Initially, each net would have their switching factor computed. As this is occurring, each net would also simultaneously cache their function BDDs. In the event of a circuit modification and a subsequent user switching factor calculation query, our program will begin examining which nets may have been affected. Undoubtedly, any nets that are the immediate fan-in inputs to this net will remain the same. We are assuming that a circuit has no loops, that is, any net cannot be a function of itself. The direct fan-out outputs would first be checked. Each output would have their logic function recomputed, and have these new functions compared to their cached functions. If there is no difference

38

between the two, then the net does not need to be recomputed. In addition, we know that any direct outputs of this net will not change in value, at the least not due to our current net's change. On the other hand, if the function has changed, we know that the switching factor would require recomputing, and that the direct outputs would need to have their function BDDs rebuilt.

The crosschecking method will continue forward through the outputs until all the outputs that have not changed in value are found. These outputs will draw the boundary around all nets that need to have their switching factors recomputed. At this point, the predicament is how to organize the nets so that they can be recomputed efficiently.

The solution is a form of queueing, assisted by a levelization technique, which are concepts derived from the Einstimer application mentioned in section 1.4. Each net is labelled by a level number on its data structure, which is a fuzzy representation of its maximum distance from the primary inputs. The maximum distance of a net can be computed by the number of boxes that lie on the longest path from any of the net's fan-in primary inputs to the net. The level number of a net x with n immediate fan-in nets I =

(io..in) must follow the rule where level(x) > max (level(i)). The rule therefore does not icl maintain that the level number is exactly the maximum distance of the net.

39

A.

Figure 2.4a Example circuit: circled usage boxes represent the boxes that were changed.

Boundary of affected nets is enclosed by shaded areas. The checking of nets proceeds in a levelized manner as depicted in the different shades.

For each level we have in the circuit, we will create a queue. When a net is modified or determined to have had its BDD function or level number changed, it will be placed at the top of the queue in the level designated by its level number. Additionally, we added a queue flag field in the net data structure, which indicates whether its BDD function changed or only its level number changed. This is necessary because one queue is used to update both the BDD function and net level numbers. Implementing one queue instead of two reduces the amount of space used.

The following explains how we incorporated queueing and levelization into our procedure to find affected nets. When a circuit modification is applied, only the immediate net or nets surrounding the modification is queued. Upon a switching calculation query, the program will invoke a recursive procedure starting at the lowest level that has an item queued. This item, being a net n, is popped off the queue, and has its function and/or level number recomputed as specified by the queue flag. Note that the level number is always calculated with a BDD function recalculation. If the BDD

40

function has changed, all its direct outputs are queued with the BDD-change flag, if they have not been queued already. The queueing is similar if the new level number is larger than the cached level number, though in this case the level-change flag will be used. The queue flag prevents nets from being queued twice.

After each net processing, the program always goes back to the lowest level to pop off a queued net, rather than continuing with the current level. Eventually, the minimum level will increase as we process the queues. The recursion will proceed until the minimum level matches the level number of the originally requested net q. It is important to note that this level number may have been updated throughout the queue processing if the net was on a queue. All the queued nets in this level will be computed, which may or may not include the requested net. Upon completion, we are guaranteed that the net logic function is correct given all circuit modifications up to this point in time. The switching factor equation for the one requested net q will be propagated through its computed transition function BDD and the program will report the value to the user.

2.4.1 Queue Data Structure

As described in the above section, our queueing procedure has several queues organized by level number. Our data structure for queueing information stores these queues in an array. Each array offset number corresponds to the queue's level number.

Therefore the queue located at array index 3 is the queue for level 3 nets. Since level numbers may change and increase, we use a dynamically allocated array so that we could allocate more space for a growing number of levels. The number of levels currently allocated is stored in our queue data structure field, maxalloc. Our data structure for all

41

queues also needs to retain other information, such as the minimum level at which any net is queued, as well as the maximum level.

The minimum and maximum number is updated after each net has been queued or dequeued. If the net is the last to be dequeued off of the maximum level, then we know now that all queues are empty because all lower nets have already been dequeued. At this point we will set the minimum level number to the maximum allocated number,

maxalloc, and set the maximum level number to 0. Thus, the queue container is said to be empty if the minimum level number is the same as the number of allocated levels.

If a queued net is the last to be dequeued in a list within the lowest level, then we need to update the minimum level number. The procedure increments the minimum level number and checks the level for any queued nets. It continues doing so until a nonempty level queue is found.

For each individual queue itself, its data structure is a simple linked list, with each node containing a net.

2.4.2 Queue Data Structure Justification

There are several other alternatives to our storage methods, for example using a linked list instead of an array to contain all the queues. However, the array is appropriate because the calculation loop would continually access the individual queues, and an array would be fast. To keep the number of reallocations small, the array will only increase in size as levels increase. During execution, if space is limited and the number of levels decrease, we may want to decrease the queue size by the number of levels decreased.

However, at this point this option is not implemented.

For each queue, the linked list is suitable because the number of nets affected per

42

level is expected to be small, so traversal of the linked list should not be expensive. In fact traversals will be rare, since most of the operations on the list such as insertion, deletion, and lookup would take place only at the head of the list.

2.4.2 Callbacks

In this section, we will explain how modifications prompt the queueing procedure. IDM uses callbacks to alert other programs when events are occurring with the circuit. We define which procedures the callbacks should initiate for which events.

For our purposes, we will be involved with the events of usage box modifications, insertions, and deletions as well as net modifications, insertions, and deletions. To associate a certain event with a certain procedure, one must register a callback.

Registering first involves deciding if the callback is a pre-callback or post-callback, meaning whether the procedure should be executed before the actual modification has taken place or afterwards, respectively. Afterwards, we link the event and procedure.

These callback procedures initiate the queueing mechanism. We will discuss an example for a net reconnection event. To connect one end of a net to a different usage box than the usage box that the net is currently attached to, IDM first requires us to disconnect the net from the usage pin. Thus, the DISCONNECTUSAGEPIN event would be triggered, so we would define a pre-callback procedure for the event. We would first have to determine whether the source end of the net (defined in section 2.2.1) was disconnected or the sink end. If the source end was adjusted, as in figure 2.4.2a, then the net's function may have changed, and therefore we place this net on the queue via a procedure call. However if the sink end was adjusted, as in figure 2.4.2b, then we are confident that the function of the net is still correct, because its inputs have not changed.

43

However, all the new immediate fan-out nets would have to be queued. It is important that this callback is defined as a pre-callback in order for us to be aware of the old connections.

source end net n net immediately affected these nets will be

queued after net n is processed

Figure 2.4.2a Source end disconnected net n sink end all nets immediately affected

Figure 2.4.2b Sink end disconnected

The procedure to determine which net(s) to queue is simple. We find which usage box the disconnection usage pin belongs to, and queue the immediate output nets of the box. (Note: a more efficient implementation of this procedure will recognize that if the pin is the source end, then only the net attached to the pin should be queued instead of all box outputs)

After the disconnection, a connection is performed to complete the net reconnection. The CONNECTUSAGEPIN event should be a post-callback in order to examine the updated state of nets. Otherwise, the stipulations are the same as a

44

disconnect event with regards to source and sink ends of the nets, and thus the procedure is implemented similarly.

Net deletions are treated in the same manner as net disconnections at the sink end of the net. In contrast, the creation of new nets does not initiate queueing, because the nets have no affect until they are physically connected to a usage pin. At this point they will be handled by the connection events. Any usage box modification, deletion, or insertion affects only the output nets of the box, so callback procedures only queue immediate outputs.

Considering that levelization is crucial to the operation of the queue, a complication arises when a net with an uninitialized level number is prompted to be queued. This case can arise when a newly created net as described above is connected, source-end, to an existing usage box. It appears that we would want to queue the new net to have its BDD function recomputed, or in this case computed for the first time.

However, given that it is a brand new net, no operations have been performed on it, so it would have a level default value of -1. We decided to prohibit the queueing of nets with undefined level numbers. The actual only possible case in which our dilemma occurs is that which is described above. Unless the sink end of the new net is connected, the newly created net should have no effect on any other nets in the circuit. If the user decides to query the switching factor of the new net, the algorithm described later in section 2.5

would recognize that no BDD is cached for this net and automatically generate one. If the sink end becomes connected to a usage box, then all of the usage box output nets would be queued. When one of these queued output nets is set to be recomputed, it will traverse to this new net. Sensing that no BDD is cached, it would be forced to compute

45

one.

The levelization property of our implementation helps to ensure correctness. We will discuss an example illustrating this later in section 2.6.1.

2.5

Recursive Algorithm

The following section will describe the general recursive algorithm to create

BDDs and calculate switching factors for a net. We will expand on the procedure in section 2.6 that will include the incremental mechanisms.

Given the circuit file, Booledozer is able to build the circuit structure made of up one proto-box, its usage boxes, nets, and pins. We are able to trace the circuit from primary inputs to primary outputs or vice versa by traversing the net-pin-usage box-pinnet loop.

Figure 2.5a Traversing through a circuit by net-pin-usage box-pin-net loop

The circuit resembles a tree structure where the leaves are the primary inputs.

Each tree node is represented by a combination of a net and its input usage box. Our program traverses the circuit in the same manner as traversing trees. We use a depth-first traversal in order to generate BDDs. Please see the following figures for a run-through of the BDD generator routine.

> Given following circuit, query net a

OR net parameter = net a

P2

P3

AND

NOT

46

> For depth-first traversal, recurse on first input

PI

P2

A net parameter netb

OR--

P3 NOT

> Continue traversal net c

P3

P2OR

NOT

-netparameter =net: p

P

4

CD

> We've reached the base case (primary input net), so create and store 2 BDD variables in the pin tdata structure primary input p, pin data structure: present-state varable:

0 next-state variable: 1

> Next, create BDDs for this net and store in net data structure current net pl data structure: present-state BDD:. o o 0 1 next-state BDD:

0 1

> Backtrack with BDDs net parameter= net c

OR--

P3 > NOT

> Store BDDs into net c's data structure (for now) current net c data structure: present-state BDD:

0

1

-ext-state BDD.

0 1

47

> Recurse into next input net parameter = net p

2

PI E:./

AND -

P3

P3 e

NOT

OR-

ANDb---

> Handle base case as before primary inputp

2 pin data structure present-state variable: 2 next-state variable: 3 current net p2 data structure: present-state BDD:

2

0/A

0 1 next-state BDD:

0 1

> Backtrack with BDDs netparameter= net C

AND-

P3 >-NOT

P4AND

OR

--3

> Get net c's function from input usage box: AND

Next, 'AND' returned BDDs with cached BDDs and

:urrent net c data structure:

>resent-state BDD: 0 store into net data

I/- I

0

2

0 1

0 1 o\

0 1

AND o \i

0 1 lext-state BDD:

0 1

0

G/ \1

0 1

0 1

AMD 0/(

0 1

> Backtrack with these 2 BDDs netlparameter = netb

P2D-AD

P3 NOT

P4

OR

-

AN -M

48

> Store BDDs into net b's data structure (for now) current net b data structure: present-state BDD: o

0 5

02

0 1 lext-state BDD:

0/ 2

03

0 1

> Recurse on next input net parameter

=net d

PI =z'--

P2CD-

P3ED

P4 E

..After processing net d and primary input p3, backtrack with BDDs net parameter = net b

PI E> AND--

P2 1: .

_ _

P3--NO

> 'OR' returned BDDs with cached BDDs and store into net data

:urrent net b data structure:

>resent-state BDD:

1

4

0

0

= E) OR

4 iext-state BDD:

0 2

0

41

5

1

011

0

0 1

S0

00

0

3

1

=

1

0

0 1

R

1

49

> .. After processing all nets net parameter

= net a

P3 [:--4Nyr

P4 E> - - - -- - - - -

> Final step: store BDDs into net data current net a data structure: present-state BDD. 5 1

0

1

4

0

0 1

0 2

01 iext-state BDD: o

7

0

1

5

0

0

1

1

0

So far, we have described our program dealing with only the most common functions; in section 2.11 we will discuss general functions built from equations. As shown above, the composite function, such as AND or OR, can be determined from the usage box. We expect the usage box to be an instance of a TIB def-box, which typically represents one of the following functions: AND, NAND, OR, NOR, XOR, XNOR, and

NOT. Although the AND, OR, and XOR functions are associative, the inverse functions

NAND, NOR, and XNOR are not. For example, while AND(A, B, C) = AND(A, AND

(B, C)), NAND (A, B, C) is not equal to NAND(A, NAND(B, C)). Since we are building our BDDs input by input, our recursive procedure will eventually produce a BDD representing the nested equation. Because this is incorrect for the inverse functions, we will have to use the nested equation with the noninverted function. Once we have all the

50

inputs processed, we negate the final answer to match the original usage box inverse function.

For every net the procedure visits, it is important that the procedure produces two isomorphic BDDs. At each net, we will also cache the generated BDDs in two fields of the net's data structure so that if we visit the net again we can automatically return the previously created present- and next-state BDDs. The procedure will only attempt to build a BDD if it detects that there are no cached values. If space is limited, then we do not need to cache the BDDs. However, the tradeoff is an increased computation time.

Upon completion of the entire recursive procedure, the queried net should contain both states of BDDs within its data structure. Likewise, every net along the path from any primary input to this queried net should have stored their own BDDs. Each net would also have its level number stored in a data structure field during the depth first traversal.

It is assigned to the current depth of the net.

2.5.1 Applying the Formula

Generating BDDs is the first step towards calculating a switching factor for a net.

The next step is to apply the recursive formula described in section 1.3.2. Please see the following set of figures for an illustration of the switching factor calculation routine.

51

Given a transition BDD runwit node

0

0

00

1

Examine 2 level structure rooted at node

0

0

0

0

1

0

3

3

10

Match structure with one from figure 1.3.2f

Recurse on child on

0-0 path

0

For next current node

0.

Examine 2 level structure rooted at node

.0

0

Match structure with one from figure 1.3.2f

Recurse on child on

0-0 path

0

3

00

For next current node

(C)

We've reached the base case, so store the switching probability into BDD data structure (assume 3 modes) urrent node c s BDD data structure

swi chLni

0.0

0

0

Scurnrnt

1 0 node

=c

52

Backtrack with probability array

0

0

Keep 0-0 child probabilities

PC

EaE

0.0J

Recurse on child on 0-1 path

0

1

3

0

For next current node

0

0 0

01

I

I ntnod 3

Handle base case as before gurrent node dts BOO data structure tvchlfg

T xoba$ility:I,

crurrn node 3

Backtrack with probability array

0

0

Keep 0-1 child probabilities

PC

00

0

0 0

Pd

EKI0

1.02

1 0

Next we will recurse on the child on the same probability array.

1 path. It leads to the same child as the 0-0 path, so we return the

Begin calculation for node b

Look up primary input probability data associated with current node using global table

0 1 2 3 4 6 6 7 0 9 1 primary Input data structure primaryinput:p

1

(0

1robabity array 0 sPNthing, state) 0,0

53

Using equations from section 1.3.2 and figure (c) switching probability: from figure 1.3.2f to find BDD (rooted at node b)'s p(xK

0

XK

)= p( xK xKT)

= E(xK) = 0.5/2 = 0.25

-0.5/2 = 0.25

0.2/2= 0.10 xK) = p(xK) E(xK)/

2

=

0.3 - 0.5/2 = 0.05

0.5 0.5/2 = 0.25

0.4 - 0.2/2 = 0.30 p( XK

0 xKT

) = 1

p(xK) E(xK) =

1 0.3 -0.5/2 = 0.45

1 0.5 -0.5/2= 0.25

1 0.4 0.2/2= 0.5

E(node b)

= [p(xK) + p(xKO

XKT

)] p [P(XK

0

XKT)] Pd =

(0.3 + 0.45) 0 + (0.25) 1 = 0.25

(0.5 + 0.25) 0 + (0.25) 1 = 0.25

(0.4 + 0.50) 0 + (0.10) 1 = 0.10

Store switching probabilities into BDD data structure urrent node bs BDD data structure srtching probability.

6 .10

Backtrack with probability array

0

Keep 0-0 child probabilities

Pb

OI7

Recurse on child on

0-1 path

00

00

00

00

54

o

For next current node

0 j cumnnode e

Examine 2 level structure rooted at node

0

1

0

0

Match structure with one from figure 1.3.2f

4

3

03IP

0

After visiting nodes c and d, we retrieve the probability arrays pc and

Pd.

Begin calculation for node e using probability equations from figure (e) of figure 1.3.2f:

E(node e) = [P(7)] Pc+ [P(xK)] Pd (0.7) 0 + (0.3) =0 -

(0.5) 0 + (0.5) 1 = 0.5

(0.6) 0 + (0.4) 1 = 0.4

Store probability array into BDD data structure urrent node es BDD datastructure awtkhing

0TF robabilty

0.5

Backtrack with probability array anmn ndk a

--

0

I o

I

3

3

2

Keep 0-1 child probabilities

Pb

0.25

0.10

Pe a

0Os'

W4I

After visiting the children on the 1-0 and 1-1 path, we retrieve the probability arrays

Pb and pe.

55

Begin calculation for node a

Look up primary input probability data associated with current node using global table

0 1 2 3 4 6 6 7 8 9 10

[primary In put data structure--', primary input: p, probablity array,

(switching, state)

Calculate for node a using probability equations from figure (a) of figure 1.3.2f:

E(node a) = [ p(xj x|) + p( x

0 xiT )] pb+ [ p(x x

1

T

)

+ p( X

1

0

xi)] Pe =

(0.40 + 0.20) 0.25 + (0.20 + 0.20) 0.3 = 0.27

(0.25 + 0.25) 0.25 + (0.25 + 0.25) 0.5 = 0.375

(0.45 + 0.25) 0.10 + (0.15 + 0.15) 0.4 = 0.19

Final step, store switching probability array into BDD data structure urnt nd a's SD data structure jswtc;h"n

0

'proba bil ftyr

When the switching factor calculation is complete for a given net, it will cache the final switching probability array into a field in the net data structure so that subsequent requests can retrieve the values immediately. As shown in the above figures, each calculation is cached into the data structure for the BDD node. This caching is used to take advantage of the reduced property of BDDs. Since there are no redundant BDDs, no more than one instance of a function can exist in the BDD space at one time. Thus, a

BDD b may have multiple parents, if more than one BDD relies on b's function. This aspect is called sharing among the BDD space. Because of this situation, a BDD propagation may visit a set of nodes of a subfunction two or more times. To prevent the

56

extraneous traversal as well as to prevent the calculation of the same function twice, we will use the cached values on the BDD for the second or later visits.

Exclusive-or BDD manipulations are most often larger than the BDDs they were composed of. For space efficiency, we no longer need to keep the transition BDDs for later use. Future requests for the switching factor on this given net can automatically refer to the cached value in the keyword data. An example of a time in which this transition BDD would actually need to be used again is when we are attempting to perform the exclusive-or on the exact same present- and next-state BDDs. This signifies that there are two nets in one circuit whose functions are exactly the same, but such duplication in circuits is not often seen. In actuality, the continued existence of this transition BDD may be useful in cases where the transition BDD would be a subfunction of another exclusive-or manipulation, but we foresee such cases as being rare. Therefore, the next step is to "free" the transition BDD from memory. By "freeing" a BDD, we mean decrementing the reference count for this BDD for the BDD package garbage collector. If there is more than one pointer referencing this BDD then the reference count would be greater than 0, therefore the garbage collector will not delete it from memory.

Another memory issue concerns the next-state BDD. It is not necessary to cache the next-state BDD on the net for the entire time the BDD represents the net function.

The reason is because only the present-state BDD is used for comparison. We need the next-state BDD only until after we have computed the transition BDD. If memory space is strained, then it would be important to implement a modification to clear the cached next-state BDD after the transition BDD has been created. However, our application does not yet have this feature.

57

2.5.1.1 State Probability Calculation

An interesting feature of this algorithm is that it can dually serve as a state probability calculator without any modifications. The probability equations in figures

1.3.2f(d) and 1.3.2f(e) give state probabilities. Therefore, if we pass in a present-state

BDD to our algorithm, each level will always match those two figures. Thus, the algorithm will calculate the state probability of our present BDD. Therefore the user will already have a built-in calculator should they inquire about state probabilities.

2.6 Integration of Queueing and Recursive Algorithm

The pseudocode in figure 2.6a explains how the above BDD generator algorithm is encapsulated within the queueing and levelization system.

One notable modification in the BDD generator procedure is the recursion call.

Instead of calling itself, it actually calls the traverse-queue procedure. Therefore we have a two-procedure recursion technique. The motivation behind this will be discussed in the following section, 2.6.1.

58

(return-presentbdd and return-nextbdd are passed in as nulls) swcalc-traversequeue (NET n, BDDPTR returnpresent-bdd,

BDDPTR returnnext bdd, int *level)

IF n has BDD cached THEN

WHILE minimum queue level

<= n's level DO pop net p off minimum level

IF p is flagged for checking BDD change THEN save p's BDDs and level number to temporary variables reset p's BDDs and level number a_present-bdd

= NULL a_nextbdd

= NULL swcalcbdd(n, apresent-bdd, a_nextbdd, level)

ELSE IF p is flagged for checking level number THEN save p's level number to temporary variable reset p's level number calculate and store p's correct level number

END IF

IF p is flagged for checking BDD change AND p's updated and temporary BDDs are different THEN queue p's outputs for BDD checking

END IF

IF p's updated & temporary level numbers are different THEN queue p's outputs for level checking

(if not already queued for BDD checking)

END IF

LOOP returnpresent-bdd = n's updated present-state BDD returnpresent-bdd

= n's updated next-state BDD

*level = n's updated level

ELSE swcalc-bdd(n, returnpresent-bdd, returnnext bdd, level)

END IF return sw_calc bdd (NET n, BDDPTR return present-bdd, BDDPTR return next-bdd, int *level)

*level

=

0

IF n has a BDD cached THEN returnpresent-bdd = n's cached present-state BDD return-present-bdd = n's cached next-state BDD

*level = n's cached level return

END IF

IF n does not come from a primary input THEN ubox = the usage box attached to the source pin of n f = ubox's function type (represented as an integer)

FOR each usage box input net i DO swcalctraversequeue(n, temppresent-bdd, tempnext bdd, &templevel) returnpresentbdd = compose returnpresentbdd and temppresentbdd using function f nextpresentbdd = compose nextpresentbdd and tempnextbdd using function f

*level

= max(*level, tenplevel

+

1)

LOOP

ELSE returnpresent-bdd

= get BDD from primary input variable returnnextbdd = get BDD from primary input variable

END IF cache BDDs and level into n's keyword return

Figure 2.6a Simplified pseudocode of swcalc_traverse-queue and sw_calcbdd (BDD generator)

59

2.6.1 Two-Procedure Recursion

To illustrate the need for calling traverse-queue within the BDD generator routine, we will first examine how a net reconnection example would behave if the BDD generator recursed only on itself.

In Figure 2.6. 1a, the circuit is subject to two net reconnections, which translates to four pin modifications. Upon disconnecting the sink pin of net 1, net 2 is queued. Upon connection of the sink pin, net 4 becomes queued. For the second reconnection, the first and fourth nets are queued. Let us assume that our goal is to query net 1. From the routine described in section 2.4, the first step would be to pop net 1 and recompute its

BDD. The BDD function is computed incorrectly based on the outdated BDD cache on net 3. The level number, however, is updated to be greater than its maximum input level, which is 4. Since we operate on the current level number, we now need to check all nets that have been queued up to and including level 4. Therefore, the second net is dequeued, and the program will calculate its BDD function and recognize that the function has changed. This will trigger net 3 to be queued. After processing net 3, net 1 is queued again. It is available to be queued because it was popped off at the initial step.

Another computation for net 1 results in the correct BDD function. Net 4 is also recalculated because it has a level number of 4. After all queues in the first four levels are empty, the recursion is complete and the switching factor calculations can be executed based on an accurate BDD.

60

(a)

L nu n3qq

2

1w,7

11111 J r

2 nn

(b) n

Figure 2.6.1a (a) Steps for the net reconnection, (1, 3 are disconnects; 5, 7 are connects) (b) circuit after modification

The situation mentioned above demonstrates the correctness of our levelization procedure. However, it seems inefficient to queue and process a single net multiple times within one query. To prevent such superfluous calculations, when building the BDD for an input net of a given net (in line 13 of sw calc_bdd of figure 2.6a), we call the

traverse-queue procedure to make sure the input net is updated. By doing so, we can be certain that all inputs to our given net have correct BDDs. Therefore, the BDD generation procedure will always return a correct BDD, instead of an erroneous one as described in the earlier example. This reduces the number of times a net is recomputed during a single query.

In general, at times nets that are not directly involved with the queried net may have to be recomputed. For example, although the queried net in Figure 2.6. lb belongs in a separate logic tree from the queued nets, the level clause requires that those nets be processed. Optimizations in the future may be additional clauses that can prune which queued nets need to be recalculated based on the characteristics and location of the queried net.

61

querie dnet

Figure 2.6.1b Example scenario where "q" represents queued nets

2.7

Initialization

Before the application can get started, several initialization duties must occur.

Since we aim to store all mode calculations within the BDD data structure, we must require the user to define all modes before making a query. The rigid BDD memory space cannot expand for later defined modes as previously mentioned in section 2.2.2.

Given that the user has defined n modes, we will explain how the BDD data structure will be initialized to assist in our calculation algorithm. The BDD package initializer procedure takes in one argument being the size of the extra fields on each

BDD. On each BDD node, we will store an array offloat values, with the array length being n. We will allocate this amount of user space for the data structure for each BDD node created.

During the initialization of modes, there is no set order on when probabilities for the modes must be defined. The user may define probabilities after all modes have been created, or the definitions may be interspersed within the process. The only requirement is, logically, that the mode must exist before a probability is set for it. As probabilities

62

are assigned for each primary input, the probability data array for various primary inputs may continually be reallocated because the total number of modes is not yet known. The first time the user asks for a calculation, a procedure is called to ensure the consistency of all the probability data. This involves setting blank probability contents that the user has not defined to default status. The procedure also must confirm that all probability data arrays have lengths equivalent to the total number of modes. This is necessary because the switching factor calculation function expects the exact structure of a fixed-sized array for all probability data.

2.7.1 Global BDD Table

Another initialization task is to create the global table mentioned in section 2.5

that maps variable numbers to primary inputs. In actuality, it is more efficient and convenient to map the variable numbers to primary input data, because the data has a field which links to the primary input itself as well. If the primary input itself was stored, we would need to take an extra step of extracting the data from the pin. The global table exists for efficiency and is not strictly necessary. This is because one can traverse through all the primary input data variable ID fields to search for a match given a variable number. However, efficiency is of the highest concern in the switching factor algorithm and the traversal takes much more time than a constant time lookup in the global table.

The table is initialized to be an array of a pre-determined size, filled with null values.

The index of the array represents the variable ID number, and the content is a pointer to the data structure. Therefore the array element in index 4 is the primary input data whose corresponding BDD variable ID is 4. The array itself is dynamically allocated so should a new variable ID number exceed the array size, an expansion is possible.

63

2.8 Primary Input Probabilities

Throughout the entire calculation process, the maintenance of primary input probability data is among the more complicated tasks, because changes to primary input data may be presented by the user at any time. We will discuss several scenarios in which our implementation handles the triggers that are necessary to keep our data consistent and our calculations accurate.

The first issue deals with the process of updating individual primary input changes. The routine depends on the status of the application: whether or not a calculation has been made yet. If no net switching factor has been queried since the beginning of the program run, then the primary input change is trivial. The program would update the array of probability data values for the primary input. However, if computations have been completed, then the change would cause a ripple effect by affecting all of the cached probability values of all fan-out nets in the logic cone stemming from the primary input because as mentioned in section 2.4, the switching probability is dependent on initial primary input values. An effort must be made to invalidate these stored numbers so that there is no possibility that they can be reused mistakenly.

It is very difficult to delineate exactly which BDDs have depended on the old primary input probability. Recalculating all nets within the logic cone stemming from the primary input may seem to be a comprehensive solution, but the following specific example can reveal BDDs that were missed. The problem concerns the BDD package garbage collector. Suppose a user calculates a net of the circuit. A transition BDD would

64

be created, used, and then cleared. However, the garbage collector does not necessarily delete the BDD from memory immediately. This is only done periodically through a removal policy or when faced with a space crunch. Our current BDD package does not provide a routine to garbage collect on demand. Therefore we have an old BDD floating in memory with stale values cached on it. Next, the user decides to make a change to the net. With the new design, the user decides to change the switching and state probabilities of a primary input that this net is dependent upon. Therefore all descendants of the primary input should have their computations updated. Suppose the user then decides to revert the circuit to its original configuration and recalculate the net switching probability. The BDDs generated would be equivalent to the old present- and next-state

BDDs, and the transition BDD for switching factor calculation would also be the same.

Because of the reduction policy of the ROBDD logic, the package will match the transition BDD with the old BDD lying dormant in memory and revive it. On this BDD we have incorrect values cached on its nodes, but the calculation program will only know that cached values exist and will proceed to use them. We need to develop a solution to avoid this and similar unforeseen problems.

Although a forced garbage collection would be best, there lies another elegant and accurate answer to the above scenario. All BDDs that are dependent on the primary input will have the primary input variables in their support set. The key is to replace both the present- and next-state variables associated with the primary input with two new variables and then queue the primary input net. Therefore, when the BDDs of all nets within this logic cone are recomputed, the program will recognize a difference between the functions because they rely on different variables. Since brand new BDDs will be

65

created with the new variable for the nets, stale cached values will no longer be an issue and calculations will rely on the updated primary input probability values. Although the process may be tedious because it requires the recreation of every BDD in the logic cone if the switching factor of each net is requested, it is very thorough at the same time. The exact location within the program where the variables are replaced are discussed in section 2.8.1.

Alternatively, we can traverse the BDD before dereferencing the BDD and clear all BDD node caches. If this BDD comes to be used again, no cached values on the nodes will exist. However, we cannot be certain that any other calculation has not involved the primary input variable. Efficiency may also be an issue because primary input changes are less likely to occur than the switching factor requests that prompt the generation and deletion of transition BDDs.

2.8.1 Default Mode Probabilities

For default mode probability changes, the goal is to communicate the new information to all primary inputs that depend on the mode for its default values. We would traverse the circuit's linked list of all primary input data to look for those probabilities whose default status is true for the given mode. For each primary input data found, the program will store a flag into the primary input data structure for this primary input to indicate that the probabilities have been modified.

For changes to specific primary inputs, as was done with default mode primary inputs, a flag is set on the primary input indicating that there has been a change with the primary input. The use of the flag will be described below.

The BDD generation procedure has the responsibility to update primary input data

66

BDD variables after a probability change has been made. The updating occurs as follows. Assume the user has replaced primary input A's probability values with new ones. The primary input net connected to pin A is queued. The user then queries a net that is within the logic cone stemming from A. The queueing system becomes active and begins operating on the primary input net because it is on the lowest queued level. When building the output net BDD, the BDD generation routine begins at the primary input net.

Recognizing that a flag is set on this primary input, an update procedure is called. Within this procedure, the variables are replaced and new BDD nodes created from these variables will be cached into the input net and returned. Also, the procedure walks through the probability array of the primary input data, updating default values with the most recent values stored in their corresponding mode data structure. On return from the

BDD creation routine the queueing system notices a function difference and queues the immediate output nets.

2.9 Checkpoints

The incremental switching factor calculator would most benefit the user if it had facilities to report switching factor differences between different logic modifications.

Therefore we adapted the checkpoint concept used by other EDA tools to keep track of changes. The idea is to allow the user to set checkpoints at any given point in time, for example immediately before or after a specific logic change. On setting each checkpoint, the program will record the current state of the circuit, including switching factors of the circuit nets. At any time, if the user decides to inquire about the difference in switching factors between two checkpoints, the program would check the statistics that it has

67

recorded for those times and report back the difference in values. Under this configuration, the user can trace through detailed switching factor information during the course of an optimization process. The advantage of checkpoints is that the user will be able to track nets whose switching factors are responding to certain changes, which will help lead to a more guided optimization strategy.

The checkpoint system is comprised of a complex set of procedures, data structures and triggers. It must constantly keep track of ongoing changes. We will first outline the behavior of checkpoints, and then describe the data structures designed to help accomplish checkpointing. Afterwards we will explain the implementation within the application and some subtle issues that need addressing.

When a user declares a checkpoint via a procedure call, the program updates all net switching factors and generates a new checkpoint data holder. This holder will gather information about nets that change from this point on. As nets change, their old values will be cached into this holder for reference. When the user requests a report of all changes that have occurred since the declaration of the checkpoint, the program will examine the data holder and regurgitate the old cached values. The user has access to the current values and can make a comparison.

2.9.1 Data Holder Data Structure

Checkpoint data structures represent non-overlapping time spans. The first checkpoint may hold information from time A to time B, the second may keep track of changes from time B to time C, and the third from time C until the current time. By combining all three checkpoint data structures, the user can summarize all the changes from the first checkpoint until now. Similarly, for changes from the second checkpoint

68

on, the last two checkpoints are utilized. Therefore the checkpoints are used together to span combinations of times, rather than using each checkpoint to represent one unique time frame, i.e. having the first checkpoint spanning from time A to now and the second checkpoint including time B to now. Thus, the data holder has an efficient design by cascading consecutive checkpoints to minimize duplication of data.

The structure resembles a linked list of linked lists. Figuratively (see figure

2.9.1 a), there is a list that lies vertically in a downward direction. These represent the checkpoints. The earliest checkpoint created is located at the top, and the most current checkpoint is the bottommost item. Branching off of each checkpoint horizontally is a list of nets that have been changed since the creation of the checkpoint that the list is attached to. In actuality, the list is composed of net data, which includes the net itself.

Given all this, to find all nets that have changed from, say, the third earliest checkpoint, we point to the item in the third position of the vertically linked lists and collect information horizontally until we reach the end of the list. Then we continue to the next position vertically and do the same. We gather information in this zigzag manner until we reach the last item in the bottommost linked list.

checkpoint 1 net3 checkpoint2 net7 checkpoint 3 checkpoint4 nell

Figure 2.9.1a Example checkpoint structure instance

For our circuit, the protodata data structure contains a field linking to the

69

checkpoint structure. It will always be a pointer to the most recent checkpoint.

2.9.2 Duplication

Within the horizontal linked list of changed data we avoid having nets listed more than once. Double or more listings are not necessary because the only change that is important is the earliest change that was reported, because any changes recorded afterwards do not reflect the state of the circuit at the time the checkpoint was created.

They represent the state after a modification. If the user actually does want to know the effect of values due to those other modifications, the user always has the opportunity to set new checkpoints in the code or script before those changes take place in the program.

The following paragraph will explain how duplications within one list are avoided. First, all checkpoints are identified by a number. If a net is added to this checkpoint, a field in the net data structure using a keyword key-checkpointjid will store the ID of the checkpoint that the net is being added to. However, if the field already has a value stored that matches the checkpoint number, the net would not be added

For example, assume a net n is being added to the current checkpoint with an ID of 1. Then say a new checkpoint is created with an ID of 2. Next, the net n is modified, so the checkpoint system would be triggered to add n to the checkpoints. To prevent duplication though, the program will look up the keycheckpointjid keyword of the net and see that the number stored is 1. Therefore the net has not yet been stored on the most current checkpoint. The change is recorded and the net checkpoint number field is updated to 2. If after a while, the net is changed again, the program will do another lookup and see that the number stored is 2. Since that is the number of the current checkpoint, the program will understand that this net has already been added to this

70

specific checkpoint and should not be added now.

2.9.3 Generating Reports

When a user requests a checkpoint report, information is gathered into another data structure to facilitate the reporting of differences. The end result of the report is going to be a list of nets that have changed along with information about their old values.

This list will be made accessible to the user through a cursor. The cursor, a pointer to a temporary linked list, will be used to traverse through each item of the list. Each item contains information specific to one net that is derived from current values and values stored in the data holder. Basically, as shown in figure 2.9.3a, the data holder structure will contain, for each recorded change, the following three pieces of information: the net that will be changed, the switching probability of the net before the change, and the state probability of the net before the change.

When the time comes for a report to be generated, the program first confirms that the circuit has up-to-date information (discussed later in section 2.9.6). Next it begins a loop through the data holder items gathered from the zigzag motion as described in section 2.9.1. At each item, the nets are queried for their probability values and compared with the checkpoint-held values of the net. If a difference is recognized, a new item is added to the report list, which will contain the held switching probability, the difference in switching probabilities, the held state probability, the difference in state probabilities, and the net name. When the linked list for the report is completed, a cursor, being a pointer to the head of the list, is returned to the user. The user may manipulate the cursor through routines that can increment the cursor forward through the list or report values from the item that the cursor is pointing to.

71

cursor pointer -net name: n7 old static prob: 0.45

static prob difference. 0.02

old switching prob: 0.34 switching prob difference: -0.11

3w-change-cursor oat pl float ps float deltaps

fl oat deltaps struct swchange-cursor *next net name: n1i old static prob: 0.-305 static prob dfference:

-0.03

old switching prob: 0.42

switching prob difference: -0.3 netname: n6

(old stati pr ob: 0.2 static prob difference: 0.00

old switching prob: 0.34

Iswitching prob difference: -0.6

(b)

Figure 2.9.3a (a) report data structure, swchange-cursor (b) example report instance

When reporting across multiple checkpoints, it is possible to face one net multiple times. The key net to report is the earliest net. Therefore, when traversing the lists, a net is flagged once it is visited. If the generator comes across a net that is flagged later on the traversal, the data holder item for that net is ignored. After the report is complete, the list is traversed again to clear all flags.

2.9.4 Checkpoint Deletion

Checkpoints may also be deleted if the user no longer needs the checkpoint information. The deletion process depends on the location in the list of the checkpoint to be removed. If it is the earliest checkpoint then the process is simple. All of the items on the linked list of the checkpoint will be deleted, as well as the checkpoint item itself within the vertical linked list. The earliest checkpoint now would be the item that was next on the deleted checkpoint's link. On the other hand, if the checkpoint is located anywhere else on the vertical list, then its linked list of net changes must be collapsed onto the list of its parent checkpoint. The parent checkpoint here refers to the latest

72

checkpoint created before the given checkpoint was created, or in other words, the checkpoint that is located on top vertically. The collapse is basically a merging of the two lists. However, there is a precaution of avoiding net duplication using net flags as described in the previous section. It is important that each of the collapsed nets have

their key-checkpoint-id number updated to the parent checkpoint ID number. The protodata that the checkpoints belong to will update its checkpoint pointer to the most recent checkpoint after the deletion, if necessary.

As long as at least one checkpoint exists, information would continue to be recorded.

checkpoint 1 net3 checkpoint 2 net6 net2 -: net7 net 1 checkpoint

4 net5

Figure 2.9.4a Deleting a checkpoint (solid lines: before deletion, dotted lines: after deletion)

2.9.5 Checkpoint Triggers

The next implementation issue concerns events that should trigger the addition of nets to checkpoints. We could create a clause in every callback available to signal the checkpoint system that a change to a net has been made. However, a simpler indication of a change exists. We will take advantage of the queueing system, because the callbacks report to it already. We are certain that a net has been changed at the crucial point in time when the queueing system recognizes a difference between the old cached BDDs and the newly created BDDs of a net. To be more precise, the checkpoint system should be triggered exactly when the present-state BDD of the net is replaced by a new BDD. This

73

step is noteworthy because we know the state of both the old present-state BDD and the new. This is important because if the present-state BDD was null, then this signifies that this net is being computed for the first time. If there is at least one checkpoint in memory, we will treat nets that fall under these conditions as newly created nets and will need to handle them carefully as we add them to the checkpoint system. This will be discussed in section 2.9.7.

Secondly, the actual present-state BDD itself will be important for the checkpoints also. We had mentioned that the reported information would include the differences in state probability values. For the data holder, we could obtain the switching probability from the currently cached value on the net keyword. State probability values, on the other hand, are not stored directly on any keyword, since these values are already stored on the root node of the present-state BDD. Therefore we must preserve the old present-state BDD for just enough time before the actual net modification so that we can extract out the state probabilities that have been computed for it to store it into the checkpoint data holder. This is another reason for this step to be a trigger for our checkpoint system.

2.9.6 Updates

In this paragraph we will explain how the system proceeds to update all switching factor values when a new checkpoint is added. For the very first checkpoint, the update is simple and tedious: query for the switching and state probabilities of all of the nets within the circuit. The reason behind examining each and every net is because all information must be updated to represent the current state of the checkpoint correctly.

However the time spent is not too expensive if the user has already queried values,

74

because we can immediately retrieve cached values from nets that have already been calculated.

For every other checkpoint added afterwards, updates can be more efficient.

Again, we can take advantage of the queueing system. The queue contains all nets that could have possibly changed since the first checkpoint. Therefore, to update the current status we just need to calculate all nets that are queued. After clearing the queue, all nets would be updated, with the exception of newly created nets as we will explain shortly in section 2.9.7.

When a user requests a report on the checkpoints, another update must first take place in order for the report to be aware of differences between current and data holder values. It is a mistake to believe that we only need to update nets that exist in the checkpoint lists because we assume that all nets that have changed values are automatically added to the checkpoint system. This is incorrect because nets can only be added when the queueing system detects an actual function change as opposed to a circuit modification, and this only occurs when the user is querying a switching factor. Without any query, no net BDDs will be replaced, and checkpoints are added only when BDDs are replaced, as explained in section 2.9.6. Thus we need to simulate a query by clearing the queue in order to add all updated nets to the checkpoint list.

The two particular modifications of creation and deletion of nets raise subtle issues that need to be handled properly within our application. The problems mostly arise from a lack of information due to either an uninitialized new net or removal of information with a deleted net.

75

2.9.7 Net Creation

We will approach the net creation concern first. The difficulty for this modification occurs when there is no existence of checkpoints at all. The issue in this case is that newly created nets may not be detected by the checkpoint system and may not be included in the reported data collection. The oversight will not affect the switching power at all, and the user would not lose any valuable difference information in the checkpoint reports if we do not address this problem. However, in order to provide as much information as possible we will implement some mechanisms to allow created nets to be reported to the user.

Initially before any checkpoints are ever added in the program, nets can be created without qualms. This is true because the very first checkpoint is treated as a special case in which all nets existing within the system are visited. After a checkpoint has been added, however, a problem may occur as shown in the following scenario. Assume that a checkpoint Source: Schneider, Schlichtmann, Wurth

[51 © IEEE has been created, and after a time is deleted. Then let us assume that a new net is created and connected to a circuit pin on its source-end but not its sink end, and thus there are no outputs of this net that can be placed on the queue. The user then adds a third checkpoint, and by protocol the queue is cleared. Assume now that the inputs to the new net are changed, thus changing the new net's probabilities. However, since the new net is still uninitialized and has an invalid level number of -1, it cannot be queued. If the user requests a report now for the third checkpoint, no changes will be displayed because clearing the queue will not affect the new net.

To force the inclusion of new net information, we would like to add any newly

76

created nets to the checkpoint list immediately, given that at least one checkpoint has already been set at some point in time. Therefore when the reporting procedure queries each net on the data holder lists for its probabilities, it would come across the new net and calculate it because there are no BDDs cached. Here we may add a trigger within the

createnet callback that adds an item to the checkpoint system immediately. This will work fine if a checkpoint currently exists in memory, but for the scenario in the previous paragraph there is no checkpoint. Consequently a report conducted later still would not include the new net.

The solution then is to keep track of all nets that are created after all checkpoints have been deleted. A linked list is kept in memory with nets being added to the list as they are created. As soon as a checkpoint is declared, all the nets on this list are transferred onto the checkpoint lists with the create status, and the new nets list is cleared. Using this method the user will never miss any piece of information.

Incidentally, for all new nets, the report will consider its initial probability values to be 0.

If the net never becomes connected on either side, then it will have null BDDs upon calculation, prompting the switching factor calculator to return 0. Although the new net will be displayed, its change will be 0.

2.9.8 Net Deletions

Ideally, if a net is deleted, then it should also be deleted from the checkpoint system should it exist on one or more of their lists. If the item is deleted though, the reporter will never realize that a switching power change has occurred due to a deleted net. This is due to the fact that this net will never be encountered during traversal of the checkpoint lists. Fortunately, IDM has a concept of "hidden deletes" which were

77

originally created for undo procedures. Upon deletion, the net is not actually cleared from memory, but is tagged as being deleted by the user and is rendered inactive.

However the user can still access the net. To accommodate for deletions within our checkpoint system, two code modifications must be made. First, we need to use the

deletenet callback to add the net immediately to the checkpoints. The net will be added with its current information. Second, the report generator will need to examine each net on the data holder lists for their delete status. If the delete status is true, then the current probability values of the net are reported as 0.

2.10 Cuts

We will now focus on some general performance issues with our application.

Despite their efficiency advantage, binary decision diagrams have a very unfortunate drawback. As the number of inputs to a function increase, the BDD representation has a tendency to grow as much as exponentially in size. In addition, certain small circuit functions may translate to very large BDDs. This blow-up of BDD size can cause significant delays for propagating equations. Manipulation of large BDDs may not finish in an acceptable amount of time. This is a crucial problem to address given that our application hinges on performance and our circuits can contain hundreds of inputs.

Therefore we will introduce an approximation technique to maintain small BDDs within our circuit. The concept is to apply cuts across nets to divide the circuit into separate smaller semi-independent circuits. They are independent in that they are represented by their own BDDs, but they are dependent because they rely on probability data that are transferred amongst themselves. Though the BDDs are smaller because they

78

represent smaller functions, the cost of the cuts is that the switching activity calculation is now an approximation because spatial correlations are not preserved.

Figures 2. 10a and 2. 10b illustrates the idea of using cuts. First a cut is applied to a net. From the point of view of the source end of the net, the net is now a primary output. Meanwhile, the sink end views this cut net as a primary input. Therefore, any fan-out nets stemming from this cut net would also assume the net is a primary input.

The BDD generation routine for a fan-out net of this cut net would thus treat this cut net as a base case, whereas before the cut the procedure would continue recursing to the inputs of the net. For switching probability calculations, a fan-out net would need to know the initial state and switching probabilities of this pseudo-primary input. These values will actually be derived from the probabilities computed for the cut net being a primary output. Thus the approximation can be seen here because the calculations do not recurse to the actual primary inputs.

z

OR0

X -.

R mX

Fg v

AND

/ , \7/ z :)o

2 v

Figure 2.10a Cuts: creating sem-i-independent circuits

OND

79

0 x

0

0

0 1 x

0w c

0 1

0 x

0

W

V

Figure 2.10b Cuts: respective BDD representations of cuts

The following sections will discuss how cuts are created and identified within our application, and how we propagate switching probability values across cut nets.

2.10.1 Criteria

We need to define a criteria or policy to decide which nets to place cuts on.

Ideally, the nets chosen should operate in the circuit more independently than others. For example, a change applied to a chosen net would affect relatively few of its fan-out nets.

There exist some clever methods to identify these nets; for example the reconvergence region analysis from [5] pinpoints mutually independent internal signals. This idea is not easily applied to our program, however, because our circuits are constantly changing and the region recomputation may become expensive. For our purposes, because BDD size should be the most important factor in performance time, we will emphasize this as a criterion first.

Without BDD cuts, we take spatial correlation into account for the entire circuit.

By constraining BDDs by size, we are effectively reducing the number of levels that we account for spatial correlation to the number of net levels the BDD function spans.

Though this may result in a loss of accuracy, experiments have shown that the error for

80

ignoring spatial correlation for signals that reconverge after many levels of logic is insignificant

1

. Our test results in section 5 will show that accuracy is very reasonable under these conditions.

In the next few paragraphs we will explain the data structures involved in maintaining cuts, the implementation of creating a cut, and how the application incorporates the cuts in the normal queueing and computation routines.

2.10.2 Cut Data Structure

Since in theory a cut acts similar to a primary input, it is logical to reuse the primary input data structure to represent a cut net. The only difference in the construction is that primary inputs defined by the user are related to usage and proto pins, whereas cut primary inputs will be associated with nets. Therefore for nets, we will have two associated data structures: one being the net data with the typical BDD and probability cache information, and the second being primary input data, which would be empty if the net is not a cut net. The primary input data itself would have an extra field in its data structure to reference the net that it belongs to, if appropriate. Primary input data are strictly associated with either only a net, or only a pin.

2.10.3 Cut Implementation

The BDD generator routine must be altered slightly. When a cut net c is queried, the BDD generator must return the primary input BDDs associated with the net. All outputs will view this as the function BDD for the net c. However, the generator must also continue recursing to the fan-in primary inputs of this net c and cache the resulting

BDD into the net data keyword. This BDD will be used to calculate the switching and state probability for this net, and also provide the initial probabilities for the primary

81

input that it is simulating. Note that any fan-in input ancestor of this net can itself be a cut net, but this current net will treat them as actual primary inputs.

To implement the solution above, the procedure is unchanged except for the return statement. Previously, the program would return the BDDs that it had generated and cached. This time we would need to check first whether or not the net is a cut net.

Our program essentially defines a net as a cut net if its primary input data keyword is not empty. If we determine the net to be a cut net, we return the primary input BDDs. If not, the generated BDD is returned. The only BDDs that will be cached will be the generated

BDDs.

E 3

AN D b AD ab

0 1

OR 13t 1 10

1 0 0 1 0

Figure 2.10.3a Example circuit and BDDs before cut

82

E d a a 0

1

01

0

0 1

Ekl

0

Figure 2.10.3b Example circuit and BDDs after cut (OR BDD still cached, but outputs see dotted BDD)

2.10.4 Creating Cuts

The next issue is how and when to create cuts. We are going to use BDD size as a criterion, so the plan is the following. First, when a net BDD is being generated, the procedure will recurse completely to the first primary input encountered. During this one-way path no BDDs are being generated. However, for each step as the procedure backtracks a new BDD has been created for one net. We know that this BDD will be an input to another net. Consequently, if this BDD size is relatively large, then the BDD size of the immediate output net would be at least as large. At this point then, we will check the size of the newly generated BDD for the net. If the number is larger than a given BDD size threshold, then we will declare this net a cut net by initializing primary input data for it. Therefore, its immediate output would see a primary input, and will have a BDD input being a size of one rather than a size that is greater than the threshold.

As discussed in the previous paragraph, we will cache the large BDD into the net data but return primary input BDDs.

83

2.10.5 Probability Maintenance

Fortunately, maintenance of the primary input probability data for a cut net is also a light extension of our current application. Each time the queueing mechanism determines that the function for a net has changed, we must update the primary input probability data immediately if the net is a cut net. This basically requires us to perform the switching factor and state probability calculation on the net's updated BDD. In addition, these values will be stored as the initial probabilities in the primary input data probability array.

For cuts, it is important that the values be calculated as soon as a net function change is detected. The reason is because the only other place that the primary input probability data is updated is within the BDD generator procedure, at the primary inputs.

Remember that the detection of a function change takes place only after the BDD regeneration. If we only flag the probability data for change rather than updating it immediately, we must wait until the BDD generation routine rebuilds this net again. This will not happen until another query is made. Our current query though will not have updated cut probability values. Thus, when executing the switching factor calculation routine for our cut net, we will be feeding old, incorrect data.

Another notable issue with cuts concerns levelization between cuts. We must be careful in our code to propagate level numbers through cut nets and to not reset level numbers to 0 at each cut net primary input. The error would profoundly affect our entire queueing system, because level numbers represents net dependencies. We accomplish the task by relating the level numbers to the level numbers of its fan-in inputs always, regardless of the cut status of the inputs.

84

In the case where many modifications are occurring with the circuit, there might seem to be a chance that too many cuts will be created. We do not envision this to be a grave problem because the cuts already existing should still keep the BDD sizes under control. Consequently, few cuts are expected to be added following a modification.

Should cases occur where there seems to exist an over-approximation due to a large number of cuts, we should provide an option for the user to clear and set cut nets. This option has not been implemented yet.

2.11 Expansion Views

A different issue with our application concerns circuit representations. As explained in section 1.4, def-boxes can be defined by a complex equation that do not fit the normal AND, OR, XOR, and NOT gate configurations. Since the BDD package can manipulate BDDs using only these 4 basic functions and their derivatives, the ability to correctly identify and process the complicated definition boxes is necessary. The handling will affect the BDD generation procedure, which currently is able to work with only TIB-based usage boxes.

Fortunately, IDM can translate any definition box to a TIB-based equivalent through a procedure called bideqn. The package uses a concept known as views, which allows different representations of the same circuit to exist. For example, a user may have two views on one circuit, one of which describes the circuit in a black-box configuration, and the second describing a more detailed implementation. The def-boxes that hide complex equations maps to the black-box example. The translator examines these equations, which must be composed of the AND (&), OR (1), and NOT(!) functions.

85

The utility creates a second view, labeled 'EQNVIEW', in which all the def-boxes are converted into interconnections of TIB def-boxes (see figure 2.11 a) which embody the same logic function. This transformation is essential in our circuit traversal during BDD generation. Given a def-box in the main view, one can locate its TIB-ified representation in 'EQNVIEW' through a lookup.

The following paragraph explains our solution, which allows the generator to map between the decomposed TIB boxes and its associated def-box to produce the correct

BDD.

Within our BDD generation procedure (on line 10 of sw_caic_bdd within figure

2.6a), a clause exists to identify the function of the usage box. We had assumed that it would match one of the pre-defined TIB functions, but we must make an exception for the boxes that do not fall under this category. At this point, we aim to call a procedure that will generate the correct BDD for this box.

This procedure will first find the def-box that this usage box is mapped to. For every def-box, there lies a correlated proto-box within the EQNVIEW view, as shown in figure 2.1 la. This proto-box, known as an expanded logic block, is the actual container of the interconnected decomposed TIB boxes. The output nets of this proto-box map to the output nets of the usage box, and similarly with the input nets. The beauty of this configuration is that due to the exclusive TIB composition of the proto-box, we can pass any of its output nets into the BDD generator routine and generate the correct BDD that represents it, thus representing the usage box output nets that we were originally aiming to generate a BDD for.

86

givenusagebox a,

DEFi1 d nj ni

__W definitionboxDEF_I a

1 d=(a&b) Ic protoboxDEPI tn2 d

WiueRnetgymr subnet keywmrl

I n2 1 n03

Figure 2.11a Expansion boxes: mapping between usage box, def box, and proto box

However, there are critical problems that we must not overlook. Most importantly, if we use this proto-box directly, the BDD generator will compose a result based on the assumption that the proto-box primary inputs are the actual primary inputs, rather than the fact that the inputs are simply inputs nets to a usage box. Therefore the

BDD generator undesirably neglects any fan-in input nets to the usage box. At the protobox primary inputs, we need the generator to map back to the usage box inputs and to continue recursing. The generator should then return the correct BDD for our expanded logic block.

2.11.1 Expansion Box Mapping

To solve the problem, the generator code needs modification. First, we must create a mapping between the input proto-nets of the proto-box with our usage box input nets. Remember that one EQNVIEW proto-box is associated with one def-box, and one def-box is associated with several usage boxes. Therefore we must be careful that any modification we make to this proto-box is temporary, in case another usage box later

87

needs to reuse it. The mapping will be represented by adding a field to the net data structure. This addition will use the keyword, subnet, and will store the usage box input net that corresponds to the proto-box input net (see figure 2.11 a). This will be done for all the input nets.

In our BDD generator routine, we will add a clause at the beginning to examine the given net's subnet value. If the keyword value is not empty, it will replace the current net argument with the subnet value, being the usage box net. From then on, the routine will behave as expected.

Let us explore an example to clarify the solution we described above. Assume we are in the BDD generation routine for a net when we face a usage box that involves a complex equation. The program executes the expandeqn procedure, which finds the associated proto-box. For each proto-box input net we will create a subnet keyword, in which we will store the correlated usage box input net. The expandeqn procedure next calls the BDD generator to obtain a BDD for the usage box output net. The BDD generator now proceeds into the mapped proto-box through the output proto-net. It will recurse towards the proto-box's input net. At each recursive step, it will examine whether the subnet value has data on the current net. If not, the recursion function has not yet reached the proto-box input net. When it reaches the proto-box input net, it will replace its current net argument with the keyword value being the usage box input net.

The generator will then recurse to the net's fan-in inputs and continue normally. It will visit all of the proto-box input nets and do all the appropriate substitutions. The generator will then return to the expand-eqn procedure a correct BDD representing the given usage box. The procedure will return the result back to the first BDD generation call.

88

2.11.2 Chained Expansion Boxes

Another concern with the subnet keyword appears in the case in which two usage boxes, A and B, of the same def-box lie in the same logic path. This means that upon building a BDD for a proto-box input net for usage box A, the BDD generator will encounter another usage box B that will need to use the same proto-box. In our current implementation, when the expandeqn procedure is called for the second time, it will replace all of the subnet values that had been stored from the first expandeqn procedure.

When the generator backtracks to the next proto-box input net for the usage box A, it will not have the original nets stored in subnet. Instead, it will contain nets for usage box B.

To overcome this hurdle, we will modify the keyword to be a LIFO queue of nets, rather than one single net. The expandeqn procedure will push nets onto the queue, and the

BDD generator routine will pop the nets off upon substitution. This solution will allow many usage boxes to be chained in the same logic path. The solution also fulfills our temporary requirement, because after the BDD generation routine is completed for an entire proto-box output net, all of the mapped nets will have been popped off the queues of the subnet fields.

2.11.3 Caching

The temporary issue spans farther than the input nets. A subtle problem will occur because the BDD generator caches BDDs on the nets that it is involved with. In addition, the BDD generator may also place cuts on the nets in the expanded logic block.

Consequently, our EQNVIEW proto-box will have BDDs cached for each net that lies within its holdings and possible cut net primary input data installed on its nets. We want to be able to distinguish between nets that are in an expanded logic block and nets that

89

are in the original given circuit. We will do this by passing an extra parameter into our

BDD generator routine. This parameter, savep, is a Boolean value which is true when we want to store information on the nets. For original nets, save-p should be set to true, and for expanded logic blocks save-p should be set to false.

Therefore, when the user queries a net, the queueing system should set save-p to true. This Boolean value will be passed between each recursive step.

On the other hand, if expandeqn is the calling procedure, it will set save-p to false. Once the BDD generator substitutes a net, it will realize that it has finished with the expanded logic block and will begin recursing the original circuit. Therefore it will

set save-p to true.

A tricky circumstance that can potentially trouble our efforts is the case in which an expanded logic block lies inside another expanded logic block. However, because expanded logic blocks must consist of only TIB boxes, the above case is not possible.

2.12 Latches

TIB boxes do not encompass only the basic Boolean functions. Latches, registers, and similar constructs lie within a sequential category of TIB boxes. Sequential elements delay information transfer. Because our application is developed for only combinational circuits, we need a workaround to these boxes, which commonly appear in circuit designs. Our solution will be to treat them as primary inputs. This treatment will differentiate the sequential TIBs from normal TIB boxes yet at the same time pass probability information through the boxes. Unfortunately with the approximation we do lose the temporal correlation with sequential TIBs.

90

To achieve sequential TIB compatibility, we need to once again extend our BDD generation routine in the following manner. When the generator attempts to determine the function of a usage box, it may detect that the box is a sequential TIB. When this occurs, the generator will branch to another procedure, swcalc_bddlatch, which will attempt to return the correct BDDs for the usage box output net. One of the more commonly used IBM sequential TIBs is a D-latch which contains a pin labelled "D". We would like to pass the information from the net connected to this pin through to our

output. Sw-calcbddlatch will examine the given usage box and determine if its defbox matches the pattern of our common latch. If so, the program will pass the "D" net into a second BDD generator process in order to retrieve the BDDs to represent our usage box output net. Following this we will declare the output net a cut, return the BDDs, and refocus the program back to the first BDD generation process. At this time, the final steps of the routine processes the cut net by calculating new probability data for the cut and returning the cut primary input BDD variables.

Should swcalc_bddlatch find there to be no match between its given usage box and our D-latch TIB or if it fails to find the appropriate connected net for a "D" pin, the program will assert a primary input on the usage box pin on the source end of the output net. The new primary input will take on the default mode probabilities and we will lose any data that may have possibly been passed through. The primary input assertion should be a more valuable solution than guessing at an appropriate input pin, because if the assumption was incorrect, we may provide grossly inaccurate data to the user without the user being aware of it. Though the assertion may also be significantly incorrect, it will result in more predictable behavior for the circuit. However, a revision should be applied

91

to the code to make an exception for non-matching sequential TIBs that have only one input, in which case a cut net will be made with data derived from this one input.

3

Improvements

There are many extensions to our algorithm that will improve its accuracy and performance. Primarily, the ability to model general delay gates would increase accuracy greatly. One suggestion includes the incorporation of timed BDDs 1 91 , which adds a temporal dimension to the BDD data structure. In addition, BDDs to represent glitching were also used in the Ghosh et. al paper, and may possibly be useful in our quest. We would like to further develop our latch and sequential TIB support as well. A potential solution builds upon our current framework of two-state BDDs. For one latch, we can expand and build equations that represent a three-state configuration. Accordingly, more latches within the same chain would need more states.

A more intelligent cut technique should also improve our accuracy. The simple criterion of BDD size threshold does not examine the structure or logic of the circuit, and thus may miss key relationships that affect switching factor values. A potential solution may be using a weighting algorithm that determines a good BDD size limit based on the number of fan-in and fan-out nets to a BDD node

[13]

Another simple improvement would be a procedure that would have the ability to detect loops within the circuit design. Physical circuit loops may result in infinite loops within our application code. In addition to loop detection, it would be necessary to determine what course of action to take in calculating a switching factor if a loop is present.

92

4 Testing

Our testing phase aimed at proving the accuracy and performance of our application. Accuracy was measured by comparisons with simulated circuit results in addition to well-established static-approach calculators. We examined our results with two tools, one being the IBM PowerCalc application simulator based on a zero-delay model. The simulation was performed with an average of one million randomly generated input patterns.

Our test suite involved common benchmarks as used in other research papers. We also tested an IBM-specific circuit that included sequential TIBs. For our application, we computed the switching factor of all nets for each test circuit. The PowerCalc simulation results for each net were then compared to the results of our program, and the average difference, RMS error, and standard deviation of the two sets of data were recorded. We also made multiple modifications to the circuit and compared the resulting calculations with PowerCalc's results.

In addition to the simulator, we used the SIS application developed by U.C.

Berkeley, which provides useful computer-aided design measurements. In particular, we used the switching factor calculator which had a zero-delay model implementation derived from the work of Ghosh et. al. The algorithm is accurate and would serve as a good comparison base. The drawback is that large circuits cannot be handled by this algorithm due to memory constraints, so several of our benchmark circuits do not have a static-based comparison.

We tested performance in concurrence with our accuracy tests. We adjusted BDD

93

size thresholds also to determine tradeoffs between accuracy and performance with regard to cuts. A database of logically optimized circuits was not widely available.

Therefore we used a worst-case scenario to test performance by making a random modification (usage box function change) at a low level net and a mid-level net. Since the queueing system is guaranteed to propagate to the primary outputs rather than stopping at a border, an actual logic optimization would be expected to take much less time than our tests do.

Small circuits were used to test the boundary calculation. In these cases we can make a simple logic modification using De Morgan's law or other transformations to determine whether the incremental analysis calculated the correct boundary around the affected nets.

5

Results and Conclusion

The table below lists run times from our tests.

BDD threshold 20 circuit Incr.

C17

C1355

C1908

C880

C499

C3540

C432

C5315

C7552

C2670

0.38

11.93

16.87

33.41

34.26

48.03

67.36

87.88

166.59

296.64

PowerCalc

0.5

19.24

SIS

0.7

4.641

19.69 4.31

BDD threshold 50 circuit Incr. PowerCalc

C17

C1355

C1908

0.49

30.9

30.19

29.73 5.08

12.76 3.97

113.32 0.19

7.74 2.37

156.86 19.49

278.8 0.19

C880

C499

C3540

C432

C5315

C7552

35.13

65.16

122.08

68.88

231.61

226.6

79.47 0.33

C2670 212.95

Table 5a Comparison of run time in real seconds

SIS

0.61 0.89

18.74 5.32

19.25

30.91

12.67

116.59

7.93

163.32

285.68

78.96

4.54

5.3

4.26

0.25

2.63

22.56

0.24

0.2

Times included the file processing time for each application, because we were not able to extract from SIS the time to calculate only the switching factors. SIS is very fast in comparison with our method and PowerCalc's simulation. However, the application

94

was not able to complete several larger circuits in a reasonable amount of time. In the majority of cases with a BDD size threshold of 20, our application completed in a less amount of time than the simulator. As expected with an increased size threshold of 50, the time was increased

The next tables describe the accuracy comparison between the three applications.

SIS circuit Avg. Diff. Std. Dev RMS

C17

C1355

C1908

C880

C499

C3540

0.001985 0.001981 0.044557

0.010201

0.008909

0.011739 0.011601 0.108345

0.006241

-

0.010097

0.00883

0.006202

-

BDD threshold 20

0.100999

0.094389

0.079001

circuit

C17

C1355

C1908

C880

C499

C3540

Avg. Diff.

PowerCalc

0.013655 0.013515 0.117054

0.016493

0.016027

0.016615

0.014677

0.019572

Std. Dev

0.016221

0.01577

0.01634

0.014463

0.019189

RMS

0.128424

0.126597

0.128902

0.121154

0.139901

C432 0.0231 0.022566 0.151987

C432 0.022389 0.021892 0.149643

C5315

C7552

0.013677

-

0.01349

-

0.11695

-

C5315

C7552

0.019172

0.018445

0.018805

0.018105

0.138464

0.135812

C2670 C2670 0.013728 0.01354 0.117168

Table 5b The average difference, standard deviation, and RMS error between our incremental calculator,

SIS and PowerCalc for a BDD threshold of 20

BDD threshold 50

SIS circuit Avg. Diff. Std. Dev

C17

RMS

0.001985 0.001981 0.044557

C1355

C1908

0.008758 0.008681 0.093584

0.002929 0.002921 0.054121

C880

C499

C3540

0.008891 0.008812 0.094292

0.009256

-

0.00917 0.096208

circuit

C17

C1355

C1908

C880

C499

C3540

Avg. Diff.

PowerCalc

Std. Dev RMS

0.013655 0.013515 0.117054

0.015813 0.015566 0.125761

0.011204 0.011079 0.105851

0.014536

0.017691

0.014325

0.017382

0.120567

0.133023

0.019331 0.018957 0.139036

C432 0.022746 0.022228 0.150817

C432 0.021824 0.021352 0.147743

C5315

C7552

0.005899 0.005864 0.076802

-

C5315

C7552

0.012391 0.012238 0.111315

0.013419 0.013239 0.115841

C2670 -

C2670 0.011798 0.011659 0.10862

Table 5c The average difference, standard deviation, and RMS error between our incremental calculator,

SIS and PowerCalc for a BDD threshold of 50

95

As demonstrated in Tables 5b and 5c, although the calculations are not as accurate as other methods such as the Boolean Approximation Method, our average differences are reasonable. We have a better accuracy rate with the SIS method than the simulator.

As expected, higher BDD thresholds increase the accuracy.

The following tables test incremental calculation times and the accuracy with the results from a PowerCalc simulation. Note that for these tests, our incremental time was reported without file processing times. We did not want to include the file processing time because we needed to show the relative performance of a one-pass calculation and the second incremental calculation.

Low-Level Change circuit One-pass Incr-pass Avg Diff Std Dev RMS

C17

C1355

0.09

5.73

0.08 0.013177 0.01305 0.114992

2.03 0.038228 0.036789 0.195578

C1908

C880

7.98

26.21

1.94 0.012077 0.011931 0.109895

2.11 0.015007 0.014782 0.122503

C499

C3540

C432

C5315

28.42

35.19

62.97

54.43

1.45 0.02058 0.020158 0.143461

4.89 0.023944 0.023371 0.154738

0.87

7.83

0.023048

0.017549

0.022521

0.017241

0.151828

0.132474

C7552 120.92 12.22 0.02089 0.020453 0.144533

C2670 266.63 3.61 0.016942 0.016655 0.13016

Table 5d Times and error rates for a change at a randomly-picked net of level 1

96

Multiple change circuit One-pass Incr-pass Avg Diff Std Dev RMS

C17

C1355

0.56

5.84

0.19

69.56

0.008056

0.015007

0.007999

0.014782

0.089802

0.122503

C1908

C880

C499

C3540

8.37

42.75

29.81

32.99

89.4 0.015246 0.015014 0.123474

34.45 0.016277 0.016012 0.127581

58.04 0.023949 0.02338 0.15477

72.86 0.02324 0.0227 0.152446

C432

C5315

64.47

62.7

149.35

73.4

0.024583

0.020969

0.023992

0.020529

0.156831

0.144806

C7552 148.53 120.1 0.019311 0.018938 0.138962

C2670 264.34 41.79 0.014177 0.013976 0.119069

Table 5e Times and error rates for changes to 10 randomly picked nets of level 1

For Table 5d, we first calculated all nets and recorded the time under the Onepass heading. After, we picked a level 1 net at random and modified its usage box function. Then we recalculated all the nets and recorded the run time of the recalculation.

The results are very encouraging. For Table 5e, we followed the same procedure except we modified 10 nets in order to examine the effect of multiple changes on the accuracy rate. Comparing the error columns of the two tables together and with Tables 4b and 4c, we see that the accuracy rate remains relatively stable through a small or large number of changes.

The incremental-pass times for multiple changes prove the worth of our application, because for nearly all of the circuits, making 10 changes takes approximately the same time as calculating the original circuit one or two times. In three cases, the recalculation time is less than the one-pass time.

In conclusion, we have developed a novel process for incremental switching factor computation. We have determined that the number of nets which are affected by logic modifications to a circuit can be bounded. By recalculating the switching factors of the nets within the boundary, we can obtain the new correct power output without having

97

to recalculate any other nets. We also incorporated circuit cuts into our application to handle BDD size limitations. Our test results show that the more modifications made to a circuit, the amount of time saved by using an incremental calculator increases significantly. Thus, our application is very efficient and suitable for power computation for low power optimizations.

98

References

[1] Marculescu, R., D. Marculescu, and M. Pedram. "Probabilistic modeling of dependencies during switching activity analysis." Computer-Aided Design of Integrated

Circuits and Systems, Vol. 17, Issue: 2, Feb. 1998, pp. 73-83

[2] Uchino, T., F. Minami, T. Mitsuhashi, and N. Goto. "Switching activity analysis using Boolean approximation method." Proceedings of the 1995 IEEE/ACM

International Conference on Computer-Aided Design, 1995, pp. 20-25.

[3] Ghosh, A., S. Devadas, K. Keutzer, and J.White. "Estimation of average switching activity in combinational and sequential circuits." Design Automation Conference, 1992, pp. 253-259.

[4] Theodoridis, G., S. Theoharis, D. Soudris, T. Stouraitis, and C. Goutis. "An efficient probabilistic method for logic circuits using real delay gate model." Proceedings of the

1999 IEEE International Symposium on Circuits and Systems, Vol. 1, 1999, pp. 286-289.

[5] Schneider, P. H., U. Schlichtmann, and B. Wurth. "Fast power estimation of large circuits." IEEE Design & Test of Computers, Vol. 13, Issue: 1, Spring 1996, pp. 70-78.

[6] Iman, S., and M. Pedram. "An approach for multilevel logic optimization targeting low power." IEEE Transactions on Computer-Aided Design of Integrated Circuits and

Systems, Vol. 15, No. 8, August 1996, pp. 889-901.

[7] Brace, K.S., R.L. Rudell, and R.E. Bryant. "Efficient implementation of a BDD package." Conference Proceedings on 27th ACM/IEEE Design Automation Conference,

1990, pp. 40-45.

[8] Costa, J., J.C. Monteiro, S. Devadas. "Switching activity estimation using limited depth reconvergent path analysis." Proceedings of the International Symposium on Low

Power Electronics and Design, 1997, pp. 184-189.

[9] Li, Z., Y. Zhao, Y. Min, and R.K. Brayton. "Timed Binary Decision Diagrams".

Proceedings of the IEEE International Conference on Computer Design: VLSI in

Computers and Processors, 1997, pp. 352-357.

[10] Malik, S., A. Wang, R. Brayton, and A. Sangiovanni-Vincentelli. "Logic

Verification using Binary Decision Diagrams in a Logic Synthesis Environment". IEEE

Digest of Technical Papers: International Conference on Computer-Aided Design, Nov.

1988, pp. 6-9.

[11] Marculescu, R., D. Marculescu, and M. Pedram. "Efficient Power Estimation for

Highly Correlated Input Streams". Proceedings of the 32nd A CM/IEEE Design

Automation Conference, 1995. pp. 628-634.

99

[12] Devedas, S., K. Keutzer, and J. White. "Estimation of Power Dissipation in CMOS

Combinational Circuits Using Boolean Function Manipulation." IEEE Transactions on

Computer Aided Design of Integrated Circuits and Systems, March 1992. pp. 373-383.

[13] Choi, H. and S.H. Hwang. "Reducing the Size of a BDD in the Combinational

Circuit Power Estimation By Using the Dynamic Size Limit." Proceedings of the 1997

IEEE International Symposium on Circuits and Systems, 1997. pp. 1520-1523.

[14] Bryant, R. "Graph-based Algorithms for Boolean Function Manipulation." IEEE

Transactions on Computers, Aug. 1986. pp. 677-691.

[15] Abato, R.P., Drumm, A.D., Hathaway, D.J. and van Ginneken, L.P. International

Business Machines. Incremental Timing Analysis. 1996. U.S. Pat. 5,508,937.

100

Appendix

Appendix A: Data Structures

queuedata int min I evel

0 int rmx-1evel ueue int mmx aloc NET pet strUxct queue *next

2" rw

_alloc" swmode dhar *mmo int index

0 flotpl flat bnlfps struct protodata

*prd

3 nmmodes

Alis E

NETDATA nd

-- NET n sAnuct niist *rnnd netdata

BDDPTR present -bdd sBDDPTRe float *Ps flagss

NE Tn nmt bbddsfloat

...

.

pratobox list

PROTO~_BOX pbax- struct Protobox-list *=ex protodata

PROTOBOX phax struct queuedata *qd okit

-WMODE

--num -modes int ftags

NLIST ndist

PLIST plist

SW CHECKPOINT

QUEUE new nets

CP1 list b prirwy_input_data int presetfarid int nox-vari d int int nun-modes tags

-

PROB_-DATA *prob -

NETWORK PiNnpi--

NE T nnmmds prob_data float p

I float halfps bool p ljdefauit_p

0 bool ps _default_p plist

PIDATA pd s U

0 float

-

Avcheckpoint

SW

CP

ITEM item

-- +

IPR6 TO-BOX intid pbox flo p fot *Ps

-dem

_ stt sw checkpoirt *prev E

0. s=rc sw_checkpoirt *neZ

Axt sip _checkpoirt item *ngft num

_rmde "

0 ft d nvn-mode

-.-

101

Appendix B: Usage

Required Steps

Assume that all circuit files and DLL files have been loaded. In order to calculate a valid switching probability for a net, the user must first define a mode, then set default probability values for this mode. These two steps are all that is needed before the user can continue calculating switching or state probabilities for a net. Optionally, the user may want to define more than one mode, or set different probabilities on primary inputs. To track changes of switching probabilities during a session, the user can use checkpoints.

Defining Modes

Before any calculation can be made, at least one mode must be defined. A protobox may have several different modes, i.e. idle mode, run mode, etc. The main difference between two modes is the default primary input switching and state probabilities that the user will set for each mode.

In defining a new mode, the user needs to supply the program with the proto-box that will contain the mode and the name of the mode. The user will call the following procedure: bool sw_definemode (PROTOBOX pbox, char *name, SWMODE *return mode)

This will add the mode to the proto -box, and will set the default mode switching probability to an invalid -1 and the default mode state probability to an invalid -1. The user must set the default mode probabilities to reasonable values. The procedure will return a pointer to the newly created mode, which the user should provide for any function that requires a mode as an input. Note that once a calculation is made, no modes can be defined without clearing all data , which will reset all values and modes that the user has defined.

Accessing Modes

Traversing through all of the modes in a proto-box can be accomplished using the following set of routines. A pointer to the first mode in a protobox can be created using the procedure: bool sw_firstmode (PROTOBOX pbox, SWMODE *returnmode)

The procedure returns the pointer to the first mode in return_mode. To get the next mode following this mode in the proto-box, provide return_mode as the input to mode to the following procedure: bool sw_nextmode (SWMODE mode, SWMODE *returnmode) swnextmode can be repeatedly called to obtain the next modes until it returns a NULL.

Setting Default Mode Probabilities

Default probabilities for a specific mode will be used for all primary inputs in the circuit that do not have probabilities individually assigned to them by the user (see Setting

Proto/Usage Pin Probabilities ). By supplying the mode and the default switching and state probabilities, the default mode probabilities can be set using the following

102

procedures: bool swsetdefaultswitchprob (SWMODE m, float prob) bool sw_setdefault-oneprob (SW_MODE m, float prob)

Setting Proto/Usage Pin Probabilities

The user may want to assign specific initial probabilities for primary inputs on a proto pin or usage pin for a specific mode. These values will be used instead of the default mode values. To do so, the user supplies the specific mode, the network pin (either the proto pin or usage pin), and the initial switching or state probability. The following procedures should be used: bool swsetswitchprob (SWMODE npin, float prob) bool swsetoneprob (SWMODE NETWORKPIN npin, float prob)

Calculating Probabilities For A Net

Given that the user has defined at least one mode and the user has set valid default probabilities on this mode, the user can calculate a valid switching or state probability for a net using the following procedures: bool swnetswitchprob (SW_MODE m, NET n, float *return_prob)

The variable returnprob will contain the requested probability. The probability reflects the latest changes to the design or to probability values on any net, if any, that occurred before the function call was made.

Using Checkpoints

Checkpoints contain information about changes in the probabilities of nets of a protobox within a period of time. The user first sets a checkpoint at the point when the user wants to begin checking for changes in data. In a program, the user can set a checkpoint at any time by calling bool swset-checkpoint (PROTOBOX pbox, SW_CHECKPOINT *return-cp)

This will return a pointer to the checkpoint return_cp, which the user should provide for any functions that require a checkpoint as input.

At any time the user wants to list of the changes in net probability values from the time the checkpoint was set until the current time, the user can obtain the list by calling the following, supplying the checkpoint and the mode that the user is inquiring about: bool swget-change_cursor (SWCHECKPOINT cp, SWMODE m,

SWCHANGECURSOR *returnchangecursor) pointer to the list of changed nets. The user cannot access the information from this change cursor directly, the user should provide this cursor to the following procedure to obtain information about the item on the list that the cursor is pointing to: bool swgetchange_info change-cursor, NET

*returnnet, float *returnpl, float *return-pl change, float

*return_ps, float *return_pschange)

return_net is the net that changed, returnpl and returnps are the state and switching probability, respectively, of the net at the time the checkpoint was created,

103

return-p1_change and return-ps-change are the changes in state and switching probability values, respectively, from the time the checkpoint was created until now

(current value previous value).

To get the cursor to point to the next item on the list, supply the cursor to the following procedure: bool swincchange (SWCHANGECURSOR *changecursor, bool

*return-eol)

If the user no longer needs the cursor and wishes to delete it, the user may call: bool swdelete_change-cursor (SW_CHANGECURSOR *change_cursor)

Warning: The user should not create a copy of the list manually using

*returnchangescursor. This cursor is permanently altered in the preceding procedures, meaning that list items will be deleted and floating copies of the original change cursor may not point to valid addresses. The user should only use the procedure sw-getschange-cursor to create cursors.

If the user no longer needs the checkpoint and wishes to delete the checkpoint, the user may call: bool swdeletecheckpoint (SWCHECKPOINT *cp)

Note that associated cursors are not deleted. Also, no other existing checkpoints are affected by this checkpoint deletion.

104

Appendix C: C Command Reference

sw define mode

Description: creates a new mode for the given protobox.

Syntax: bool swdefine-mode (PROTOBOX pbox, SWMODE *return_mode, char

*name)

Prerequisites: swnet-switch-prob or swnetoneprob have not yet been called, or swcleardata was called just before swdefinemode is called.

Inputs:

* protobox proto-box for which this new mode will be created

" name the name of the new mode

Outputs:

9 SWMODE returnmode on success, a pointer to the newly created mode; on failure,

NULL

Return value:

" TRUE if the mode was successfully defined

" FALSE otherwise

Notes: none.

sw net switch prob

Description: Calculates and returns the switching probability or factor on a net.

Syntax: bool swnetswitch-prob (SWMODE mode, NET n, float *returnprob)

Prerequisites: at least one mode has been defined and its default probabilities set.

Inputs:

* mode which mode to use to calculate probability

" n net to calculate probability for

Outputs:

e return-prob switching probability

Return value:

" TRUE if the probability was successfully calculated

" FALSE otherwise

Notes: none.

sw net one prob

Description: Calculates and returns the state probability on a net.

Syntax: bool swnetone-prob (SWMODE mode, NET n, float *returnprob)

Prerequisites: at least one mode has been defined and its default probabilities set

Inputs:

* mode which mode to use to calculate probability

" n net to calculate probability for

Outputs:

* return-prob state probability

Return value:

105

"

TRUE if the probability was successfully calculated

" FALSE otherwise

Notes: none.

sw set checkpoint

Description: Creates a checkpoint to start tracking probability changes from current point in time.

Syntax: bool swset-checkpoint (PROTOBOX pbox, SWCHECKPOINT *cp)

Prerequisites: none

Inputs:

* pbox proto-box for which the checkpoint will track changes

Outputs: o cp on success, pointer to the checkpoint structure; on failure, NULL

Return value:

" TRUE if checkpoint was successfully created

" FALSE otherwise

Notes: none.

sw delete checkpoint

Description: Deletes a checkpoint from memory.

Syntax: bool swdeletecheckpoint (SWCHECKPOINT *cp)

Prerequisites: none.

Inputs: o cp checkpoint to be deleted

Outputs: none.

Return value:

" TRUE if checkpoint was successfully deleted

" FALSE otherwise

Notes: none.

sw get change cursor

Description: Creates a list of nets with information whose probabilities have changed since the time when the checkpoint was created until the current time, and returns a pointer to the head of the list.

Syntax: bool sw get change cursor (SWCHECKPOINT cp, SWMODE m,

SWCHANGECURSOR *retumchange.cursor)

Prerequisites: none.

Inputs:

" cp checkpoint to get changes from

" m which mode to get changes about

Outputs: o returnchangecursor pointer to the head of the list of nets whose probabilities have changed

106

Return value:

" TRUE if a change-cursor was successfully created

" FALSE otherwise

Notes: The user should not create a copy of the list manually using

*retumchange-cursor. This cursor is permanently altered in other cursor procedures, meaning that list items will be deleted and floating copies of the original change cursor may not point to valid addresses. The user should only use the procedure swget changecursor to create cursors.

sw get change info

Description: Extracts net and probability values from a change cursor.

Syntax: bool sw-get-changejinfo (SWCHANGECURSOR change-cursor, NET

*returnnet, float *retumpl, float *retumplchange, float *retumps, float

*returnps change)

Prerequisites: none

Inputs:

e change-cursor change cursor that points to the head of the list of changes

Outputs:

* returnnet the net that changed

" return-pl the state probability of net at the time the checkpoint was created

" return-pLchange the difference in state probabilities (current-old)

" return-ps - the switching probability of net at the time the checkpoint was created

" return-ps-change the difference in switching probabilities (current-old)

Return value:

" TRUE if information was successfully extracted

" FALSE otherwise

Notes: none.

sw inc change cursor

Description: Moves the change-cursor pointer to the next item in the list of changes.

Syntax: bool swincchangecursor (SWCHANGECURSOR *changecursor, bool

*returneol)

Prerequisites: none.

Inputs:

* change-cursor the change cursor to increment

Outputs:

e returneol TRUE if this is the last item on the list, FALSE otherwise

Return value:

" TRUE if the cursor was successfully incremented

" FALSE otherwise

Notes: none.

sw delete change cursor

Description: Deletes a change cursor from memory.

Syntax: bool swdeleteschange-cursor (SWCHANGECURSOR *change-cursor)

107

Prerequisites: none.

Inputs:

* changecursor change cursor to delete

Outputs: none.

Return value:

" TRUE if change cursor was successfully deleted

" FALSE otherwise

Notes: none.

sw clear data

Description: Clears all probability calculations, defined modes, and probability values that have been set.

Syntax: bool swclearidata(void)

Prerequisites:

Inputs: none.

Outputs: none.

Return value:

" TRUE if all data was successfully cleared

" FALSE otherwise

Notes: This procedure should be called if a user wants to define new modes after asking for a calculation (i.e. from swnetswitch-prob).

sw set default one prob

Description: Sets the default state probability on a mode.

Syntax: bool swsetdefault-one-prob(SWMODE mode, float prob)

Prerequisites: none.

Inputs:

" mode mode to set default state probability

" prob default state probabilty

Outputs: none.

Return value:

" TRUE if default probability was successfully set

" FALSE otherwise

Notes: none.

sw set default switch prob

Description: Sets the default switching probability on a mode.

Syntax: bool swsetdefaultswitchprob(SWMODE mode, float prob)

Prerequisites: none.

Inputs:

" mode mode to set default switching probability

" prob default switching probabilty

Outputs: none.

Return value:

108

"

TRUE if default probability was successfully set

" FALSE otherwise

Notes: none.

sw set one prob

Description: Asserts an initial state probability on a network pin.

Syntax: bool swsetone-prob(SWMODE mode, NETWORKPIN npin, float prob)

Prerequisites: none.

Inputs:

" mode mode for which the state probability applies

" npin network pin to set the probability on

" prob initial state probability

Outputs: none

Return value:

* TRUE if the state probability was successfully set

* FALSE otherwise

Notes: If the network pin is a usage pin, this function turns it into a primary input.

sw set switch Prob

Description: Asserts an initial switching probability on a network pin.

Syntax: bool swsetswitch-prob(SWMODE mode, NETWORKPIN npin, float prob)

Prerequisites: none.

Inputs:

" mode mode for which the switching probability applies

" npin network pin to set the probability on

" prob initial switching probability

Outputs: none.

Return value:

" TRUE if the switching probability was successfully set

" FALSE otherwise

Notes: If the network pin is a usage pin, this function turns it into a primary input. sw first mode

Description: Returns the first mode in the proto-box.

Syntax: bool swfirst-mode(PROTOBOX pbox, SWMODE *return mode)

Prerequisites: none.

Inputs:

* pbox the protobox from which to obtain to mode

Outputs:

& return_mode on success, the first mode; on failure, NULL

Return value:

" TRUE if the first mode was successfully returned

" FALSE otherwise

Notes: none.

109

sw next mode

Description: Returns the mode following the input mode in its protobox

Syntax: bool swnextmode(SWMODE mode, SWMODE *retummode)

Prerequisites: none.

Inputs:

* mode the mode that precedes the desired mode

Outputs:

* return_mode on success, the mode following the input mode; on failure, NULL

Return value:

" TRUE if input mode is not the last mode in the proto-box

" FALSE otherwise

Notes: none.

sw set bdd size

Description: Sets an upper bound on the size that any BDD can grow to.

Syntax: bool swsetbddsize(int size)

Prerequisites: none.

Inputs:

* size upper bound on BDD size

Outputs: none.

Return value:

" TRUE if the size is > 1

* FALSE otherwise

Notes: none.

110

Appendix D: TCL Test Scripts

auxfunctions.tcl

########

# functions to help in testing

########

# ------------ file utilities -----------

# -- sorting a file

#

-- given input filename and output filename proc sortfile

{infilename outfile-name} { set readfile [open $infile-name] set writefile [open $outfilename "w"] set contentlist [list] while {[eof $readfile] gets $readfile dirline lappend contentlist $dirline

} close $readfile set contentlist [lsort -increasing $contentlist]

} foreach listitem $contentlist { puts $writefile $listitem

} close $writefile

# -- reports difference of two files, line by line proc diffile (filenamel filename2 outfilename) {

# takes two files and compares each line side by side

# if node names are alike, takes

# the difference and reports to output file

# i.e. if filel has line "NNO .452"

# and file2 has line 'N_NO .450"

# then the output file will have "N_NO .452 .450 .002" set filel [open $filenamel] set file2 [open $filename2] set writefile [open $outfile-name "w"]

# throw away contents of first line

# its blank gets $filel fileline gets $file2 fileline set match 1 while ([eof $filel] 1= 1 && [eof $file2] 1= 1) { if {$match ==

1) ( gets $filel filelline

} gets $file2 file2line set filelfound [regexp ((.*) set file2found [regexp {(.*)

(.*)}

(.*)}

$filelline all filelname filelvalue]

$file2line all file2name file2value]

# if names match if {$filelfound ==

1 && $file2found == 1 && [string trim $filelname] == [string trim

$file2name]} (

# print out net name and switching probabilities

111

puts $writefile [string trim $filelname]\ [string trim $fileivalue]\ (string trim

$file2valueJ\ [expr $filelvalue $file2value]

I set match 1

} else ( set match 0

} close $filel

I

close $file2 close $writefius

# -- takes average of difference file proc averagedifference {infile-name}{

# given a file with each line following

# the format "name valuel value2 diffvalue",

# averages the diffvalue set readfile [open $infilename] set count 0 set total 0 while {[eof $readfile] I= 1) { gets $readfile readline

# if line matches pattern if {[regexp {.* ([0-9].* )([0-9].* )(.*)) $readline all vimvalue ovalue diffval]

{

# add absolute value of diffval to total set total [expr $total + abs($diffval)]

# increment count incr count

)

} close $readfile

>

0)

} return [expr $total / $count.0]

#

-- takes average difference, max difference, stddev, rms,

# -- and the difference of the sums of each circuit switching probs of difference file

#

-- returns value as a list in this order proc statistics (infile-name) {

# given a file with each line following

# the format "name valuel value2 diffvalue",

# averages the diffvalue set readfile [open $infile-name] set count 0 set squaresum 0 set sum 0 set maxdiff 0 set vimsum 0 set osum 0

{ while ([eof $readfile] I= 1} { gets $readfile readline

# if line matches pattern if {[regexp (.* ([0-9].* )([0-9].* )(.*)} $readline all ovalue vimvalue diffval]

# add absolute value of diffval to total set sum [expr $sum + abs($diffval)] set squaresum [expr $sum + (expr $diffval * $diffval]]

>

0}

112

if ([expr abs($diffval)] > $maxdiff) { set maxdiff [expr abs($diffval)]

I set vimsum [expr $vimsum

+

$vimvalue] set osum [expr $osum

+

$ovalue]

# increment count incr count

I

} close $readfile set avg [expr $sum / $count.01

# stdev = (n*squaresum sum^2)/n^2 set stddev [expr [expr [expr $count.0

*

$squaresum]

-

[expr $sum

*

$sum]] / [expr

$count.0 * $count]]

# rms = sqrt(squaresum/ n) set rms [expr sqrt([expr $squaresum / $count.0])] set sumdiff [expr abs([expr $vimsum $osum])] return [list $avg $maxdiff $stddev $rms [list $osum $vimsum $sumdiff]]

}

# ------ performing calculations -------

# -- calculating SIS switching factor proc calc-sis {circuit outfile-name} {

# given a circuit name and

# an output file name

# calculates SIS's switching factors

# store script in temporary file set writefile [open temp "w"] puts $writefile readblif\ $circuit puts $writefile power-estimate puts $writefile powerprint puts $writefile quit close $writefile

# runs SIS with the script and pipes

# output to a file exec -/sis/sis-1.2/bin/sis < temp

>

$outfilename

} exec rm temp

#

--- calculating PCALC switching factor

# any srules should already be loaded proc calc-pcalc (circuit defname viewname outfile-name} { readvim -def $defname -view $viewname -lib $circuit set theDef set theProto

[ idm::locatedefbox -name $defname

[ idm::locateprotobox -def-box $theDef -viewname $viewname ] set-activeproto -proto $theProto

# calculate switching factor lp_calc_switchfactor -methods (STATISTICAL) -check-type (STATIC} -piprob (0.500000)

regprob (0.500000} -pi-dens (0.500000} -regdens (0.500000)

# print out switching report to output file lp_print-swfile -sw_file $outfilename

# have to have undelete mode off or system

# won't really delete it

# delete current proto and def box so any proceeding

# functions won't try to use it sw::swtoggleundelete idm: :deleteproto box -proto-box $theProto idm::deletedefbox -def box $theDef

113

sw: :swtoggle-undelete

}

#

--- calculating VIM switching factor

# any srules should already be loaded

# expects switching.dll to already be loaded proc calc-vim (circuit defname viewname outfilename sisfile name {bdd_size 20)} {

# calculates switching factors for all nets in

# the given circuit

# takes in 5 required parameters, 1 optional

# circuit, defname, and viewname define a single circuit

# outfile-name is the filename to write the results in using net names

# sisfile name is the filename to write results in using usage box names readvim -def $defname -view $viewname -lib $circuit set theDef set theProto

[ idm::locatedefbox -name $defname

[ idm::locateproto box -def box $theDef -viewname $viewname setactiveproto -proto $theProto sw::sw-registercallbacks set theMode [ sw::sw define mode -proto-box $theProto -name "MODEl"] sw::swset default switchprob -mode $theMode -prob 0.5 sw::sw setdefault one-prob -mode $theMode -prob 0.5 sw::swsetsizethreshold -size $bddsize set writefile [open $outfilename "w"] set sisfile [open $sisfile-name "w"]

# calculate and write all switching probabilities

# to a file idm::foreachnet -varname anet -protobox $theProto { set prob [sw::swnetswitchprob -net $anet -mode $theMode]

# write net information set nodename [idm::netname -net $anet] puts $writefile $nodename\ $prob

# write usage box information set upin [idm::fnet-pin -net $anet -pintype source] if {[idm::isprotopin -networkpin $upin] set nodename [idm::protopin name -protopin $upin]

} else { set ubox [idm::get usage box from usage-pin -usagepin $upin] set nodename [idm: :usage box name -usage-box $ubox]

} puts $sisfile $nodename\ $prob

} close $writefile close $sisfile

# undo vim-specific settings

# unregister callbacks, clear data, and delete usage box

# so any proceeding functions won't try

# to use it sw::swunregistercallbacks sw::swclear_data

# have to have undelete mode off or system

# won't really delete it sw: :swtoggleundelete

114

idm::deletedefbox -def box $theDef

) sw::sw_toggle_undelete

#

----------- file conversion -----------

#

-- converts sis output file to generic format

#

-- "GGO

0.52" proc convertsis (infilename outfile name)

{

#-------------------------------------

# extracts node name and switching

# probability from a blif switching

# output file

#-------------------------------------

# takes in 2 parameters:

# 1) name of file to sort

#

2) name of file to put result in

# assumes file has the format in which each line

# is like "Node P_233GAT_40_

# returns "P_233GAT_40 0.50"

Cap. = 16 Switch Prob. = 0.50 Power = 20.0" set readfile [open $infile-name] set writefile [open $outfile-name "w"] while {[eof $readfile]

!= { gets $readfile readline

# sis has a tendancy to insert prompts

# in random places, take it out regsub -all sis\> $readline

"" readline

# if line matches pattern if ([regexp (Node(.*)Cap.*Switch(.*)Prob. =(.*)Power) $readline all nodename nothing switchprob] > 0) {

# print out net name and switching probability puts $writefile [string trim $node_name]\ [string trim $switchprob]

}

} close $readfile close $writefile proc convert-pcalc (infilename outfilename numruns} {

#-------------------------------------

# takes the number of switches reported

# by pcalc and divide it by a given

# number of runs to obtain switching

# probability

II-------------------------------------

# takes in 3 parameters:

# 1) name of file to sort

#

2) name of file to put result in

#

3) number of runs

# assumes file has the format in which each line

# is like " NNO

# returns "NNO

0.11" set readfile [open $infile name] set writefile [open $outfile-name "w"] while ([eof $readfile] I= 1) { gets $readfile readline

116747 116747"

115

# if it finds a number if (Eregexp ( .*(EO-9].* )([O-9].* )} $readline all firstnum secondnum > 0} { set switchprob [expr $secondnum / $numruns.0]

# get net name regexp ( (.* )([0-9.* )} $readline all netname

# print out net name and switching probability puts $writefile [string trim $net-name]\ $switchprob

}

}

} close $readfile close $writefile

#

------------- usage boxes ------------- proc random box {avoidboxname} {

# i.e. random-box AND2 or randombox OR

# given a box name, randomly finds another function that

# does not have the same function name

# extract the TIB name out of boxname if its similar to

#

AND2 or OR3

# otherwise nothing happens regexp ((.*) [0-9] .*} $avoidboxname all avoidboxname set boxlist [list "AND" "OR"] set boxname $avoidboxname

# make sure we don't choose the same

# function from the boxlist while {$avoidboxname == $boxname} { set rand [expr (int(rando*2))] set boxname [lindex $boxlist $rand]

} return $boxname

} proc replace-box (ubox pbox newtype (name noname}} {

# i.e. replace-box $ubox $pbox AND

# replaces a usage box with another usage box of

# a possibly different function, and transfers net

# connections

# disconnect nets from old usage box

# and store each net in a variable set count 0 idm::foreachusagepin -varname upin -usagebox $ubox -pintype output { incr count

# assign connected nets to variables set nout$count [idm::getnet_from usagepin -usagepin $upin]

# disconnect nets from usage pin idm::disconnect-usage-pin -usagepin $upin

} set count 0 idm::foreachusagepin -varname upin -usagebox $ubox -pintype input

{ incr count

# assign connected nets to variables set nin$count [idm::getnet_fromusagepin -usagepin $upin]

# disconnect nets from usage pin idm: :disconnect-usage-pin -usagepin $upin

}

# name of desired new def box is $newtype$count, i.e. AND2 set dboxname $newtype$count

# except when there is only one input

116

if {$count <= 1) { set dboxname $newtype

}

# get def box set dbox [idm::locatedefbox -name $dboxname]

# create, bind, and connect new usage box

# create usage box set ubox [idm::create-usage-box -proto box $pbox -def box $dbox -name $name]

# following set of statements create bound pins

# and connects nets to them set count 0 idm::foreach-defpin -varname dpin -defbox $dbox -pintype input { incr count

# create bound usage pin set upin [idm::createboundusagepin -usage-box $ubox -def-pin $dpin]

# connect net to usage pin idm::connect-usagepin -usagepin $upin -net [set nin$count]

} set count 0 idm::foreach-def-pin -varname dpin -defbox $dbox -pintype output ( incr count

# create bound usage pin set upin [idm::createboundusagepin -usage-box $ubox -defpin $dpin]

# connect net to usage pin idm::connect-usagepin -usagepin $upin -net [set nout$count]

}

} primary-test.tcl

set circuitdir /afs/btv.ibm.com/u4/chtran/benchmarks set viewname SYNVIEW set defname TOP set SOURCEPATH /afs/btv.ibm.com/u4/chtran/bdd/switching set RULEPATH /afs/btv.ibm.com/u4/chtran/rules/all/moretibs/srule source $SOURCEPATH/path.tcl

load $SOURCEPATH/switching.dll

load-srule -srule $RULEPATH/moretibs.srule -tech CMOS7S load powercalc.dll

source auxfunctions.tcl

* given a list where each item is

# (number net}

# sorts list by decreasing number

# and returns list of all the nets whose

# numbers are in the middle proc getfirst-nets {levellist} {

# first sort list by decreasing number set sortlist [lsort -decreasing $levellist] set midnumber 1

# find first item that has the midnumber as its level set index [lsearch -regexp $sortlist ^$midnumber\

]

# make sure a net with level $midnumber exists while ($index

== -1)

{ incr midnumber set index [lsearch -regexp $sortlist A$midnumber\ ]

}

117

set midlist [list] while ($index < [llength $sortlist] &&

[lindex [lindex $sortlist $index] 0] == $midnumber) { lappend midlist [lindex [lindex $sortlist $index] 1] incr index

}

} return $midlist

# --- calculating VIM switching factor

# any srules should already be loaded

# expects switching.dll to already be loaded proc calc-mid-vim {circuit defname viewname {bdd-size 20}} {

# calculates switching factors for all nets in

# the given circuit

# takes in 3 required parameters, 1 optional

# circuit, defname, and viewname define a single circuit readvim -def $defname -view $viewname -lib $circuit set theDef set theProto

[ idm::locatedefbox -name $defname

[ idm::locateproto box -defbox $theDef -viewname $viewname setactiveproto -proto $theProto sw::swregister-callbacks set theMode [ sw::swdefinemode -protobox $theProto -name "MODEl"] sw::swsetdefault switch-prob -mode $theMode -prob 0.5 sw::swsetdefaultoneprob -mode $theMode -prob 0.5 sw::swsetsizethreshold -size $bddsize set levellist [list]

# calculates one time

# start timing set cpu [cputime -quiet]

I

# calculate all switching probabilities

# and store net levels in a list idm::foreachnet -varname anet -protobox $theProto ( set prob [sw::swnetswitchprob -net $anet -mode $theMode] lappend levellist [list [sw::sw-test_level -net $anet] $anet]

# stop timing set cpu [cputime -quiet] set origtime [lindex $cpu 0]

# trying to make a new list of all the

# mid level nets set midlist [getfirstnets $levellist]

# get usage box attached to first list item set index [expr [llength $midlist] 1] set upin [idm::f-netpin -net [lindex $midlist $index] -pintype source] set ubox [idm::get-usagebox_from_usagepin -usage-pin $upin]

# replace usage box set newfunc [random-box [idm::defbox-name -def-box [idm::getdefboxfrom_usage box

usage-box $ubox]]] replace-box $ubox $theProto $newfunc new_[idm::usagebox_name -usagebox $ubox] set cp [sw::swset-checkpoint -proto box $theProto]

118

# start timing set cpu [cputime -quiet]

# recalculate set writefile [open primvimout "w"] idm::foreachnet -varname anet -protobox $theProto

{

# calculate prob set prob [sw::swnetswitchprob -net $anet -mode $theMode]

# write net information set nodename [idm: :netname -net $anet] puts $writefile $nodename\ $prob

} close $writefile

# stop timing set cpu

[cputime -quiet] set recalctime [lindex $cpu 0] set theCC [ sw::swgetchangecursor -checkpoint $cp -mode $theMode] set count 0 while { $theCC 1= 0) { incr count set theCC [ sw::swincchangecursor -change-cursor $theCC]

}

# saves circuit to temporary directory writevim -lib -chtran/switchingtcls/testtrash/tempdir

# undo vim-specific settings

# unregister callbacks, clear data, and delete usage box

# so any proceeding functions won't try

# to use it sw::sw clear data sw: :sw_unregister-callbacks

# have to have undelete mode off or system

# won't really delete it sw: :sw toggleundelete idm: :deleteproto box -proto-box $theProto idm::deletedefbox -def-box $theDef sw: :swtoggleundelete

# use pcalc to calculate netlist set cpu [cputime -quiet] calcpcalc -/switching-tcls/test-trash/tempdir $defname $viewname primpcalcout set cpu

[cputime -quiet] set pcalctime [lindex $cpu 0]

# parse and sort files convertpcalc primspcalcout prim-pcalcoutl 1000048 sortfile primpcalcoutl primpcalcsortout sortfile primvimout prim-vimsortout diffile primpcalcsortout prim-vimsortout prim diffout

# stores accuracy set av [statistics primdiffout]

# remove temporary files

* exec rm -r tempdir exec rm prim pcalcout exec rm prim_vimout exec rm primpcalcoutl

119

exec rm prim-pcalcsortout exec rm prim vimsortout exec rm primdiffout

} return [list $circuit $origtime $recalctime $pcalctime $av $count] set circuitlist [list MY_ADDER C1355 C1908 C432 CM150A C2670 C499 C7552 I10 PCLER8 C17

C3540 C5315 C880 19 TERM1] foreach circuit $circuitlist { puts CIRcUIT:::\ $circuit set item [calc midvim $circuitdir/$circuit $defname $viewname] set writefile [open thesis-primary-change "a"] puts $writefile circuit:\ $circuit\ origtime:\ [lindex $item 1]\ recalctime:\ [lindex

$item 2]\ pcalctime:\ [lindex $item 3]\ accuracy:\ [lindex $item 4J\ changed-nets:\

[lindex $item 5] puts circuit:\ $circuit\ origtime:\ [lindex $item 1]\ recalctime:\ [lindex $item 2]\ pcalctime:\ [lindex $item 3]\ accuracy:\ [lindex $item 4]\ changed-nets:\ [lindex $item

5] close $writefile

} multipleschange.tcl

# Testing accuracy of multiple recalculations on a circuit

# Here, we're changing 10 level 1 boxes

# and comparing the new circuit with pcalc set circuitdir /afs/btv.ibm.com/u4/chtran/benchmarks set viewname SYNVIEW set defname TOP set SOURCEPATH /afs/btv.ibm.com/u4/chtran/bdd/switching set RULEPATH /afs/btv.ibm.com/u4/chtran/rules/all/moretibs/srule source $SOURCEPATH/path.tcl

load $SOURCEPATH/switching.dll

loadsrule -srule $RULEPATH/moretibs.srule -tech CMOS7S load powercalc.dll

source .. /aux functions.tcl

# given a list where each item is

# (number net}

# sorts list by decreasing number

# and returns list of all the nets whose

# numbers are in the middle proc get-firstnets (levellist} {

# first sort list by decreasing number set sortlist [lsort -decreasing $levellist] set midnumber 1

# find first item that has the midnunber as its level set index [lsearch -regexp $sortlist ^$midnumber\ I

# make sure a net with level $midnumber exists while {$index == -1)

{ incr midnumber set index [1search -regexp $sortlist A$midnumber\

} set midlist [list] while ($index < [llength $sortlist] &&

[lindex [lindex $sortlist $index] 0] == $midnumber} { lappend midlist [lindex [lindex $sortlist $index] 1]

120

} incr index

} return $midlist

#

--- calculating VIM switching factor

# any srules should already be loaded

# expects switching.dll to already be loaded proc calc-mid-vim {circuit defname viewname (bdd-size 20)) {

# calculates switching factors for all nets in

# the given circuit

# takes in 3 required parameters, 1 optional

# circuit, defname, and viewname define a single circuit readvim -def $defname -view $viewname -lib $circuit set theDef set theProto

[ idm::locatedef box -name $defname

[ idm::locateprotobox -def box $theDef -viewname $viewname set activeproto -proto $theProto sw::sw register_callbacks set theMode [ sw::swdefinemode -proto box $theProto -name "MODE1"] sw::swsetdefaultswitch-prob -mode $theMode -prob 0.5 sw::swsetdefault one-prob -mode $theMode -prob 0.5 sw::swsetsizethreshold -size $bdd size set levellist [list]

* calculates one time

# start timing set cpu [cputime -quiet]

# calculate all switching probabilities

# and store net levels in a list idm::foreachnet -varname anet -protobox $theProto { set prob [sw::sw net switchprob -net $anet -mode $theMode] lappend levellist [list [sw::swtestlevel -net $anet] $anet]

}

# stop timing set cpu [cputime -quiet] set origtime [lindex $cpu 0]

# trying to make a new list of all the

# mid level nets set midlist [getfirst-nets $levellist]

# just pick the first 10 boxes set midlist [1range $midlist 0 9]

# start timing set cpu [cputime -quiet] set cp [sw::swset_checkpoint -proto box $theProto] foreach chnet $midlist {

# get usage box set upin [idm::fnetpin -net $chnet -pintype source] set ubox [idm::get-usage-box-from-usagepin -usagepin $upin]

# replace usage box set newfunc [random-box [idm::defboxname -defbox [idm::getdefboxfrom-usagebox

usage-box $ubox] ]

121

replace-box $ubox $theProto $newfunc new_[idm::usage box name -usage-box $ubox]

# recalculate set writefile

[open primvimout "w"] idm::foreach net -varname anet -protobox $theProto {

# calculate prob set prob [sw::swnetswitchprob -net $anet -mode $theMode]

# write net information set nodename [idm::netname -net $anet] puts $writefile $nodename\ $prob

} close $writefile

}

# stop timing set cpu [cputime -quiet] set recalctime [lindex $cpu 0] set theCC [ sw::swgetchangecursor -checkpoint $cp -mode $theMode] set count 0 while { $theCC != { incr count set theCC [ sw::swinc_changecursor

-change-cursor $theCC]

}

# saves circuit to temporary directory writevim -lib tempdir

# undo vim-specific settings

# unregister callbacks, clear data, and delete usage box

# so any proceeding functions won't try

# to use it sw::sw clear data sw::swunregistercallbacks

# have to have undelete mode off or system

# won't really delete it sw: :swtoggle undelete idm::deleteproto box -proto box $theProto idm::deletedefbox -defbox $theDef sw: :swtoggle undelete

# use pcalc to calculate netlist set cpu

[cputime -quiet] calcpcalc tempdir $defname $viewname primpcalcout set cpu

[cputime -quiet] set pcalctime [lindex $cpu 0]

# parse and sort files convertpcalc primrpcalcout prim-pcalcoutl 1000048 sortfile primpcalcoutl primpcalcsortout sortfile prim vimout prim-vimsortout diffile prim-pcalcsortout primvimsortout prim-diffout

# stores accuracy set av [statistics prim diffout]

# remove temporary files

* exec rm -r tempdir exec rm prim-pcalcout exec rm prim vimout exec rm prim-pcalcoutl exec rm primpcalcsortout

122

exec rm primvimsortout exec rm primdiffout

} return [list $circuit $origtime $recalctime $pcalctime $av $count] set circuitlist [list MYADDER C1355 C1908 C432 CM150A C2670 C499 C7552 I10 PCLER8 C17

C3540 C5315 C880 19 TERM1] set circuitlist [list C17

C432 C5315 C7552 C2670]

PCLER8 CM150A MYADDER TERM1 C1355 C1908 19 C880 C499 C3540 I10 foreach circuit $circuitlist

{ puts CIRcUIT:::\ $circuit set item [calcmidvim $circuitdir/$circuit $defname $viewname] set writefile [open thesis-multiple-primary-change "a"] puts $writefile circuit:\ $circuit\ origtime:\ [lindex $item 1]\ recalctime:\ [lindex

$item 2]\ pcalctime:\ [lindex $item 3]\ accuracy:\ [lindex $item 4]\ changed-nets:\

[lindex $item 5] puts circuit:\ $circuit\ origtime:\ [lindex $item 1]\ recalctime:\ [lindex $item 2]\ pcalctime:\ [lindex $item 3]\ accuracy:\ [lindex $item 4]\ changed-nets:\ [lindex $item

5]

} close $writefile

123

Appendix E: Source Code swaux.C

#include

"swswitching.h"

/*--------------------------------------------------------*

Function: swflag-set-p

Desc: given a flag and a mask, returns whether or not a flag has been set

*--------------------------------------------------------* bool sw_flagsetp (int flag, int mask) (

} return (flag & mask)

/*--------------------------------------------------------*

Function: swset-flag

Desc: given a flag and a mask, set it to the given value

*--------------------------------------------------------* bool swset_flag (int *flag, int mask, bool value) { if (value) {

*flag mask;

} else {

*flag &=

}

-mask;

} return TRUE;

/*--------------------------------------------------------*

Function: sw_malloc

Desc: calls malloc for given size, exits program if there is not enough memory

Post: space created

*--------------------------------------------------------* void *swmalloc (nt size, char data_string[]) { void *space = malloc (size); if (space == NULL) { printf ("Error: no more space to create %s.\n", data-string); exit(0);

} return space;

}

/*--------------------------------------------------------*

Function: swrealloc

Desc: calls realloc for given size, exits program if there is not enough memory

Post: space created

*--------------------------------------------------------* void *swrealloc (void *olddata, int size, char datastring[]) { void *space

= realloc (old-data, size); if (space == NULL) { printf ("Error: no more space to create exit(0);

%s.\n", datastring);

} return space;

}

/*--------------------------------------------------------*

Function: sw_getproto boxfromnetwork-pin

Desc: gets the proto box from the network pin

*--------------------------------------------------------*

PROTOBOX swgetprotoboxfrom_networkpin (NETWORKPIN npin) (

// returns the proto box depending if its

124

// a proto pin or a usage pin if (isprotopin (npin, C)) ( return getproto-box-fromprotopin((PROTO_PIN) npin, C);

}

// network pin is a usage pin return get-parentprotobox_from-usage-box

}

/*--------------------------------------------------------*

Function: swfloatequals

Desc: compares values of two floats and returns

TRUE if they are equal with small error,

FALSE if not

*--------------------------------------------------------* bool swfloat equals (float fl, float f2) {

} bool iszero; float diff

= fl f2; return (abs(diff) < 1.0e-6);

/*--------------------------------------------------------*

Function: swbddfree

Desc: frees a bdd, checking if its refcount > 0 first

*--------------------------------------------------------* void swbddfree (BDDPTR *b) {

} if (*b 1= NULL && BDDREFCOUNT (*b) > 0) ( bddfree (*b);

} swcalc.C

#include "sw switching.h"

/*--------------------------------------------------------*

Global variables

*--------------------------------------------------------*

BDDPTR (*bddfunc[6])(BDDPTR, BDDPTR) =

(bdd-and, bdd-or, bdd-xor};

// function pointer array

/*--------------------------------------------------------*

Function prototype

*--------------------------------------------------------* void swcalctraversequeue (PROTODATA prd, NET n,

BDDPTR *pbdd, BDDPTR *nbdd, int

*level, bool savep);

/*--------------------------------------------------------*

Function: sw-calc-prob

Desc: uses DFS to calculate probabilities

Pre: for each bdd variable in f, its pidata needs to have probs correct

Post: f and all of its children nodes have probabilities in their user data

Case: 1 2a 2b 3 4

0 0 0 0

I

/ \ / \ /\ / \ |

I o o o

\ / o

/ \

*--------------------------------------------------------* float *swcalc-prob(BDDPTR f, int total) {

125

float *v;

BDDPTR bdd_0, bdd_1;

//

// temporary float array

f's else and then children

PIDATA pd ; // pi data to get prob values float *resOO, *res0l, *res10, *resll, *reso, *resl; int i; if (if) { printf ("Warning: no bdd.\n");

// return an array zero-filled values v = (float *) calloc (total, sizeof (float));

// warn printf ("Warning: setting default of 0.0 for probability

} for (i = 0; i < total; i++)

{ v[i] = OFFSET;

} return v;

// get user data of bdd v = (float *) BDDUSERDATA PTR(f);

// if the value has already been calculated

// return that value

// we assume that any bdd user data value of less than

// the OFFSET means the bdd is uncalculated if (*v >= OFFSET) { return v;

}

// if this is BDD_1 or BDD_0,

// return 1.0 and 0.0 respectively value.\n"); if (BDD_1_P (f)) { for (i = 0; i < total; i++)

{ v[i] = 1.0 + OFFSET;

} return v;

} else if (BDDOP { for (i = 0; i < total; i++)

{ v[i]

= 0.0 + OFFSET;

} return v;

I

// get associated pidata pd = swglobal-bddtableget(BDDVARID(f));

// determine whether in case 1, 2, 3, or 4

// if in present state if (BDDVARID(f) == pd->presentvarid) {

// get children of this node bdd_0 = bddelse(f); bdd_1 = bdd-then(f);

// case 1 if (BDDVARID(bdd_0) == pd->next-varid &&

BDDVARID(bddl) == pd->next-varid) ( res00 = sw_calcprob(bdd_else(bdd_0), total); resOl = sw_calcprob(bddthen(bdd_0), total); reslO = sw_calcprob(bdd_else(bdd&), total); resll = sw_calcprob(bdd_then(bddl1), total); for (i = 0; i < total; i++) { v[i] = OFFSET +

(1.0

pd->prob[i]->pl pd->prob[i]->halfps) * (res0O[i]

-

OFFSET)

+

126

}

(pd->prob[i]->halfps) *

(res0l[i]

-

OFFSET)

+

(pd->prob[i]->halfps) * (res10[i] OFFSET) +

(pd->prob[i]->pl pd->prob[i]->halfps) *

(res11[i]

-

OFFSET);

//

} case 2a else if (BDDVARID(bdd_0) == pd->nextvarid &&

BDDVARID(bdd_1) 1= pd->next-varid) { resO0 = sw-calcprob(bdd-else(bdd_0), total); resOl = sw-calcprob(bddthen(bdd_0), total); resl = sw-calcprob(bdd_1, total); for (i = 0; i < total; i++) f v[i] = OFFSET +

(1.0 pd->prob[i]->pl pd->prob[i]->halfps) * (resO0[i] OFFSET) +

(pd->prob[i]->halfps)

*

(res0l[i]

-

OFFSET)

+

(pd->prob[i]->pl) * (resl[i] OFFSET);

}

// case 2b

} else if (BDD VARID(bdd_0) 1= pd->nextvarid &&

BDDVARID(bddl) == pd->next-varid) { res0 = sw-calc-prob(bdd_0, total); reslO = sw-calcprob(bddelse(bdd_1), total); resli = sw-calcprob(bdd_then(bdd_1), total); for (i = 0; i < total; i++) { v[i]

=

OFFSET +

(pd->prob[i]->pl) * (resO[i] OFFSET) +

(pd->prob[i]->halfps) * (resl0[i] OFFSET) +

(pd->prob[i]->pl pd->prob[i]->halfps) * (res1l[i] OFFSET);

}

//

} case 3 else if (BDDVARID(bddO) 1= pd->nextvarid &&

BDDVARID(bdd_1) 1= pd->next-varid) { resO = sw calcprob(bdd_0, total); real = sw calcprob(bdd_1, total);

} for (i = 0; i < total; i++)

( v[i] =

OFFSET

+

(1.0 pd->prob[i]->pl) * (res0[i] OFFSET) +

(pd->prob[i]->pl) * (resl[i] OFFSET);

}

// next state

} else (

// case 4 resO = sw-calcprob(bddelse(f), total); resl = sw-calcprob(bdd_then(f), total); for (i = 0; i < total; i++) { v[i] = OFFSET +

(1.0 pd->prob[i]->pl) * (res0[i] OFFSET) +

(pd->prob[i]->pl) * (resl[i]

-

OFFSET);

}

} /* endif which state are we in */

} return v;

/*--------------------------------------------------------*

Function: swget-funcindex

Desc: gets the array index of the function corresponding to the given tib number

*--------------------------------------------------------* int sw_get func index (int tib) { switch (tib) (

127

case ANDTIB: return 0; break; case ORTIB: return 1; break; case XORTIB: return 2; break; case XNORTIB: return 2; break; case NANDTIB: return 0; break; case NOTTIB: return 4; break; case NORTIB: return 1;

// same as XOR

// same as AND

// same as OR break; default:

// check if if ((tib >=

(tib >= return 5; its an 10 TIB or a SEQUENTIAL TIB

MINPADINDEX && tib <= HAX_PADINDEX)

MINSEQUENTIALINDEX

&& tib <= MAXSEQUENTIAL INDEX)) {

}

}

// otherwise probably an expanded logic block return -1; break;

} return -1;

/*--------------------------------------------------------*

Function: swnetfpop-subnet

Desc: returns the net to be substituted in place of the current net if one is specified, otherwise, returns null

Pre: n is valid

*--------------------------------------------------------*

NET swnetpop_subnet (NET n) {

NET n2;

QUEUE q, delq;

// pop the latest subnet out of the stack locatekeyword value (n, keysubnet, &q, C); if (q 1= NULL) n2 = q->qnet; delq = q; q = q->next;

{ free (delq); setkeyword value(n, keysubnet, q, C);

} return n2; else ( return NULL;

}

/*--------------------------------------------------------*

Function:

Desc:

Pre:

Post: sw_netpush-subnet returns the net to be substituted in place of the current net if one is specified, otherwise, returns null n is valid n is associated with subnet

128

void sw-net-pushsubnet (NET n, NET subnet) (

QUEUE q, newq;

// get queue of subnets locate keywordvalue (n, keysubnet, &q, C);

// add new net to the queue newq = (QUEUE) sw malloc (sizeof (queue), "subnet"); newq->qnet = subnet; newq->next = q; q

= newq; set-keywordvalue (n, keysubnet, q, C);

}

/*--------------------------------------------------------*

Function: swcalc_mapusage-box

Desc: maps the nets from the input proto pins of a proto box to the usage pins of a usage box

Pre:

Post: pbox was made from newgen and bldegn each input pin of the pbox is mapped to a usage box input pin

*--------------------------------------------------------* bool swcalcmapusage-box (USAGEBOX ubox, PROTOBOX pbox) {

PROTO PIN ppin;

NET nu, np;

USAGEPIN upin;

DEFPIN dpin; bool returnval = TRUE;

// for all the input proto pins for (ppin = fprotopin (pbox, SOURCE_PIN, C); ppin; ppin = nprotopin (ppin, C)) (

// get the net np = get-net-fromprotopin (ppin, C);

// get the corresponding usage box net

//

// find the usage pin with the same def pin as the proto pin dpin = get defpinfromprotopin (ppin, C); upin = fusagepin (ubox, SOURCEPIN, C);

// traverse all usage pins while (upin && get-def-pin-from-usagepin (upin, C) upin = n-usagepin (upin, C);

}

!= dpin) {

// if couldn't find a corresponding usage pin if (!upin) { printf ("Warning: no usage pin mapped to def pin.\n"); returnval = FALSE;

// set a null substitute net swnetpush-subnet (np, NULL);

// found one

} else

(

// set substitute net nu = getnetfrom-usagepin (upin, C);

} swnetpush-subnet (np, nu);

129

} return return val;

}

/*--------------------------------------------------------*

Function: swcalc-bdd-expand-eqn

Desc: creates a present and next-state bdd for a

Pre:

Post: non-tib usage box newgen and bldeqn have already been called ubox output netdata's bdd and level updated all input cone nets' bdds updated

*--------------------------------------------------------* void swcalcbddexpand egn (PROTODATA prd, USAGEBOX ubox,

BDDPTR *f, BDDPTR *g, int

*level) {

DEFBOX dbox;

PROTOBOX pbox;

PROTOPIN ppin;

NET output-net;

NETDATA nd;

*f = NULL;

*g = NULL;

// get the def box for the usage box dbox = get def box from usage box (ubox, C); if (dbox == NULL) { printf ("Warning: no def box exists for this usage box.\n"); return;

}

// get the proto box from this def box under the

// EQNVIEW view pbox = locateproto-box (dbox, "EQNVIEW", C); if (pbox == NULL) { printf ("Warning: no expansion proto box exists to map usage box %s.\n", def-box-name

(dbox, C)); return;

}

// get the output proto pin, assuming there's only one ppin = f-proto-pin (pbox, OUTPUTPIN, C);

// get the output net from the proto pin output-net = get net-from-protopin (ppin, C);

// substitute nets from tib-ified usage box using

//

// nets from non-tib usage box except for the output net swcalc-mapusagebox (ubox, pbox);

) sw-calctraverse_queue (prd, output net, f, g, level, FALSE);

/*--------------------------------------------------------*

Function: swcalciscut

Desc: returns whether or not (n} is a cut net, or is a net to a pin that is a cut pin, and if

Pre:

Post: so, returns the associated pidata

(n} is valid returns TRUE if net is/leads to a cut and *pd is the associated pidata otherwise returns FALSE and *pd is NULL

*--------------------------------------------------------* bool swcalciscut (NET n, PIDATA *pd) {

130

NETWORKPIN npin;

// check whether its a cut net if (sw-pidata-does-exist (NULL, n)) {

*pd = swpidataget (NULL, n); return TRUE;

}

// get its source net pin npin = fnetpin (n, SOURCE_PIN, C);

// check if its a proto pin if (isprotopin (npin, C)) (

*pd = swpidataget ((PROTOPIN) npin, NULL); return TRUE;

}

// check if its a usage pin that is cut if (swpidata does_exist ((USAGEPIN) npin, NULL)) {

*pd = swpidataget ((USAGE_PIN) npin, NULL); return TRUE;

}

}

// otherwise

*pd = NULL; return FALSE;

/*--------------------------------------------------------*

Function: swcalcbddoperate

Desc: operates on (a) and

(tib)

(b) given the tib function

Pre:

Post:

{a} and (b} are either valid or NULL if both are non-NULL, returns (a} op (b) if only one of {a} and (b) are NULL, returns the non-NULL bdd, except if the function is a NAND, it will return the inverse of the non-NULL bdd if both are NULL, returns a NULL

*--------------------------------------------------------*

BDDPTR swcalc-bdd_operate (int tib, BDDPTR a, BDDPTR b) { if (a 1= NULL && b == NULL) { return a;

}

!=

NULL) { if (a == NULL return b;

} if (a == NULL && b == NULL)

{ printf ("Warning: null bdd.\n"); return NULL;

} if (swget_func_index(tib) < 0 11 swget_func_index(tib) > 2) {

}

// tib number is not recognized, return a null BDD return NULL;

} return (*bddfunc(swgetfuncindex(tib)])(a, b);

/*--------------------------------------------------------*

Function: sw-calc-level

Desc:

Pre: calculates level of (n} queue of net proto box's protodata is

Post: correct level of this net > levels of all nets in its

131

input cone

* --------------------------------------------------------* void swcalc_level (PROTODATA prd, NETDATA nd, int *level, bool savep) {

NET netin;

BDDPTR pbdd = NULL;

BDDPTR nbdd = NULL; int max-level;

*level = 0;

//

// only used for call to calcqueue only used for call to calcqueue

}

// if level is already stored if (nd->level != {

*level = nd->level; return;

// get a cursor of all direct fan in inputs

QUEUE in; in = sw-inputnetcursor (nd->n);

// if this is a primary input, i.e. if (in == NULL)

{

}

// level is 0

*level = 0; return; no input nets

// iterate through the input nets and

// select the greatest level while (in) ( netin

= swjinput-net (in);

// update queue swcalctraversequeue (prd, netin, &pbdd, &nbdd,

&max-level, savep);

*level = max (*level, max level + 1); swinput netcursorinc (&in);

} /* end while input cursor is not null

*/

}

// maybe save level to netdata if (savep) ( swnetdatasetlevel (nd, *level);

}

/*--------------------------------------------------------*

Function: swcalcbddlatch

Desc: for a latch with a "D" pin, calculates present and next state bdds on net, otherwise puts in a pin cut

*--------------------------------------------------------* void swcalcbddlatch (NET n, USAGEBOX ubox, USAGE_PIN npin,

PROTODATA prd, BDDPTR *pbdd, BDDPTR *nbdd, int *level, bool savep) {

NET latch-net;

USAGEPIN latchpin;

// search for the input net pin labelled "D" latch-pin = f-usagepin (ubox, SOURCEPIN, C); while (latch-pin && strcmp (usagepin-name (latch_pin, C), "D") 1= 0) latchpin = n-usagepin (latchpin,

}

{ latch_net

= NULL;

132

// if a "D" latch if (latchpin)

( pin exists, get its connecting net latchnet = get-netfrom_usagepin (latchpin, C);

}

// if a net exists, get BDDs from that net and make

// a cut if (latch-net) { swcalc_traverse-queue (prd, latchnet, pbdd, nbdd, level, save p);

*level = *level + 1;

}

// create the cut swpidataget (NULL, n);

// if no pin exists, create a generic primary input if (Ilatchpin 11!latch-net) {

}

} swpidataget (npin, NULL);

/*--------------------------------------------------------*

Function: swcalcbdd

Desc: calculates present and next state bdd on net, and level of net

Pre: queue of net proto box's protodata is correct

Post: net present and next bdd and level value is correct

*--------------------------------------------------------* void swcalc_bdd (PROTODATA prd, NET n,

BDDPTR *pbdd, BDDPTR *nbdd, int *level, bool save-p) {

NETDATA nd, nd&in;

NET net-in, n2;

PIDATA pd;

BDDPTR temp-pbdd;

BDDPTR temp nbdd;

NETWORKPIN npin;

USAGEBOX ubox; int tib = -1; int maxlevel;

// set a default level

*level = 0;

// if this net is to be substituted, do so if (n2 = sw-netpopsubnet(n)) ( n = n2;

//

//

// reset savep because if the net is to be substituted, then the net is an input net to an expanded logic box.. .therefore all further input nets are not part of the expanded logic and need

// to be saved

}

// its not possible for a expanded logic block to be inside

//

// another expanded logic block, so we don't worry about whether we should save data to this net savep

=

TRUE; nd = swnetdataget (n);

// already have value if (sw-netdatahasdata (nd)) {

// if its a cut net

133

if (swpidata does exist(NULL, n)) { pd = sw pidataget (NULL, n);

*pbdd bddcreatevar

(pd->present-varid);

*nbdd = bdd createvar

(pd->nextvarid);

} else {

*pbdd = nd->presentbdd;

*nbdd = nd->next-bdd;

}

}

*level = nd->level; return;

// try to get the usage box that's connected to this net,

// if any

// if this net leads to a cut and is not a

// cut net, we want to bypass the usage box if (sw-calciscut (n, &pd) && !sw-pidatadoesexist (NULL, n)) {

// do nothing

//

} otherwise try to get the usage box else (

//

// first get the network pin (should only have one source network pin) npin = f-net-pin (n, SOURCEPIN, C); ubox = get-usagebox_from-usagepin ((USAGEPIN) npin, C);

// get its tib number tib = syntib (ubox);

// check whether an npin exists (otherwise no usage box), if so,

// check if this is a sequential tib i.e. a latch if (npin && tib == REGTIB) ( level, savep);

// check whether an npin exists (otherwise no usage box), if so,

// check if this is

// a usage box that should be checked for expansion

} else if (npin && swget_func_index(tib) == -1) {

// get the expanded logic bdds for f and g swcalcbddexpand_eqn (prd, ubox, pbdd, nbdd, level);

// if pbdd or nbdd is null, then the expansion equation

// wasn't created correctly if (*pbdd == NULL)

{ printf ("Warning: expansion box at net creating primary input.\n", net name(n, C));

%s produced invalid bdd. By default,

// create a net pin cut (primary input) here, if net

// is not part of expansion block if (savep) (

} pd = swpidataget(npin, NULL); else { printf ("Warning: creating primary input failed, null bdd produced.\n");

}

} else {

QUEUE in = sw input net cursor (n);

134

// calculate this netdata's bdds by

// functioning all its inputs while (in) { netin = sw-input-net (in); temppbdd = NULL; tempnbdd = NULL; sw_calc_traversequeue (prd, netin, &temp-pbdd, &temp-nbdd,

&max-level, savep);

*pbdd = swcalc-bdd-operate

(tib, *pbdd, temp-pbdd);

*nbdd = swcalc-bddoperate

(tib, *nbdd, tempnbdd);

*level = max (*level, maxlevel + 1); swinput-net-cursorjinc (&in);

} /* end while traversing through inputs

*/

}

// invert answers if this is a NOT, XNOR, NAND, or NOR tib if (tib == NOTTIB tib == XNORTIB

| tib == NORTIB | tib == NANDTIB) {

*pbdd = bddnot (*pbdd);

*nbdd = bddnot (*nbdd);

} /* end if this is not an expanded logic block */

// save bdds and level number to netdata if (save-p) { swnetdata setpresentbdd (nd, *pbdd); sw_netdatasetnext-bdd (nd, *nbdd); swnetdataset_level (nd, *level);

}

) /* end if this is a cut net or not a cut */

II

// if net is, or leads to some sort of cut

// (primary, usage, asserted/automatic)

// or net should be cut

// or the net leads to a register or sequential tib

// savep requires that net is not part of expansion

// box if (save-p && (sw-calciscut (n, &pd)

|j

(nd->presentbdd && bdd_size (nd->present-bdd) > global-sizethreshold) sw-getfuncindex(tib) == 5)) {

// get pidata if net is not yet a cut if (pd == NULL) { pd = swpidataget (NULL, n);

I

I

// update the pidata if necessary if (sw-flag-set-p (pd->flags, ANY-NEEDS UPDATE)) { sw_protodatapidataupdate (prd, pd);

*pbdd = bddcreate var (pd->present-varid);

*nbdd = bddcreate var (pd->next-varid);

// save to netdata if its not a cut net if (iswpidatadoes exist (NULL, n)) ( swnetdatasetpresentbdd (nd, *pbdd); sw-netdatasetnext bdd (nd, *nbdd); swnetdata_set_level (nd, *level);

135

}

}

}

/* -------------------------------------------------------- *

Function: sw-calc_traverse entire-queue

Desc:

Pre: calculates all items on the queue all changed items are queued, and queued at their level at the time of the change

{prd} is valid

Post: queue is empty

*--------------------------------------------------------* void swcalctraverseentire_queue (PROTODATA prd) {

NET gnet; int flag; float prob;

// calculate each net on the queue until queue is empty while (!sw_queuedatais-empty(prd->qd)) { gnet = prd->qd->list[prd->qd->min-level]->qnet; swnetswitch-prob (prd->mode[O], qnet, &prob); swnet one-prob (prd->mode[], qnet, &prob);

}

/*--------------------------------------------------------*

Function: sw calctraverse-queue

Desc: calculates all items on the queue that

Pre: have a lower or equivalent level to (n}'s level all changed items are queued, and queued at

Post: their level at the time of the change

{prd) is valid and is associated with (n}'s proto box all nets of a level <= (n}'s level have

BDDs calculated and correct levels (if their

BDDs are valid). all pidata whose associated nets are of a level <= (n}'s level are updated

*--------------------------------------------------------* void swcalctraversequeue (PROTODATA prd, NET n,

BDDPTR *pbdd, BDDPTR *nbdd, int *level, bool savep) {

NETDATA nd, qnd;

NET gnet;

PIDATA pd;

BDDPTR temppbdd, temp-nbdd; int templevel;

BDDPTR check-pbdd; int check-level; int flag; nd = sw-netdata-get (n);

// go through queue if netdata has data if (swnetdata has data (nd)) { while ((swqueuedata_isempty (prd->qd)) && prd->qd->minlevel <= nd->level) {

// get the first net on the queue qnet = swprotodata_dequeue (prd, &flag); qnd = sw-netdata-get (qnet);

// if net is queued for bdd change if (swflag-set-p (flag, BDDCHG)) { temp-pbdd = NULL; tempnbdd = NULL; templevel = -1;

136

checkpbdd = qnd->present bdd; checklevel

= qnd->level; swnetdata-set-present-bdd (qnd, NULL); swnetdatasetnext bdd (qnd, NULL); swnetdataset_level (qnd, -1);

// update net sw_calc-bdd (prd, anet, &tenqpbdd, &temp_nbdd,

&temp_level, savep);

// otherwise if net is queued for level

} else if (sw-flagsetp (flag, LEVELCHG)) { checklevel = qnd->level;

// reset level so that calclevel procedure will

// recalculate level (it won't recalculate it if

// it sees a valid level) swnetdatasetlevel (qnd, -1);

}

// update level swcalc level (prd, qnd, &tenp_level, savep);

//

// if bdd changes occurred, queue successors for

bdd change if (sw flagsetp (flag, BDD-CHG) && gnd->presentbdd 1= check pbdd) {

// update pidata immediately if (sw-pidata doesexist (NULL, qnet)) { pd = swpidataget (NULL, qnet); sw_protodatapidata-update(prd, pd);

}

// queue output nets swprotodataqueue outputs (prd, qnet, BDDCHG);

// clear ps data swnetdata-setps (qnd, NULL, 0);

// clear unneeded bdds swbdd-free (&(check-pbdd));

//

//

} otherwise, if level changes occurred, queue successors for level change else if (qnd->level != {

// queue output nets sw_protodata-queue-outputs (prd, gnet, LEVEL-CHG);

}

} /* end while items still on queue */

// if its a cut net if (swpidatadoesexist (NULL, n)) { pd = swpidataget (NULL, n);

// return the pidata bdds

*pbdd = bdd createvar

(pd->present-varid);

*nbdd = bddcreatevar

(pd->nextvarid);

// otherwise return the normal netdata bdds

) else (

*pbdd = nd->present-bdd;

*nbdd = nd->next-bdd;

*

*level = nd->level;

137

}

// otherwise, calculate this uninitialized net

} else { sw_calc-bdd (prd, n, pbdd, nbdd, level, savep);

}

/*--------------------------------------------------------*

Function: sw-net-switch-prob

Desc: calculates the switching probability on a net

Post: all netdata of nets of net's level and less are updated given net switch probability is updated

*--------------------------------------------------------* bool swnetswitchprob (SWMODE m, NET n, float *prob) {

PROTODATA prd;

NETDATA nd;

BDDPTR bxor;

BDDPTR pbdd = NULL;

BDDPTR nbdd = NULL; int level; float *ps;

} if (m == printf return

NULL) {

("Error:

FALSE; mode is null.\n");

} if (n == printf return

NULL) {

("Error:

FALSE; net is null.\n");

// check for initialization if (Iglobal_initp) { swinitonetime();

// get protodata prd = sw-protodataget

(getparentprotoboxfrom (n, C));

// check that all is updated sw-calctraverse_queue(prd, n, &pbdd, &nbdd, &level, TRUE);

// get netdata nd = swjnetdataget (n);

// if value that we want is not calculated yet if (nd->ps == NULL)

{

// update it bxor = bdd-xor(pbdd, nbdd); ps = sw-calc-prob (bxor, prd->nummodes);

} else { ps

= nd->ps;

} swnetdata-setps (nd, ps, prd->num modes); swbdd free(&(bxor));

// get appropriate switching prob

*prob = ps[m->index] OFFSET; return TRUE;

/*--------------------------------------------------------*

Function: swnet-one-prob

138

Desc:

Post: calculates the state probability on a net all netdata of nets of net's level and less are updated given net state probability is updated

*--------------------------------------------------------* bool swnet_oneprob (SWMODE m, NET n, float *prob) {

PROTODATA prd; float *v;

BDDPTR pbdd = NULL;

BDDPTR nbdd = NULL; int level; if (m == NULL)

{ printf ("Error: mode is null.\n"); return FALSE;

} if (n == NULL) { printf ("Error: net is null.\n"); return FALSE;

}

I

// check for initialization if (Iglobalinitp) { swinitone-timeo;

// get protodata prd = swprotodataget

(getparent-proto-boxfromnet (n, C));

// check that all is updated swcalc_traversequeue(prd, n, &pbdd, &nbdd, &level, TRUE); if (pbdd == NULL)

{

*prob = 0.0; return FALSE;

}

// get appropriate state prob v = (float *) BDDUSERDATAPTR(pbdd);

// if value that we want is not calculated yet if (*v < OFFSET) {

I

// update it sw-calc-prob

(pbdd, prd->nummodes);

*prob = v[m->index] OFFSET;

} return TRUE; swcallback.C

#include "sw switching.h"

/*--------------------------------------------------------*

Function:

Desc: sw-queueusage-box-outputs queues all the output nets of a given usage-box for recalculation for a given change

*-----------------------------------------------------*1 bool sw queue usage boxoutputs (PROTODATA prd, USAGEBOX ubox, int change-flag,

CONTEXT ct) {

139

NET n;

USAGEPIN upin;

// traverse through all the output usage pins for (upin = fusagepin (ubox, OUTPUT-PIN, C); upin; upin = nusagepin (upin, C)) {

// get net from usage pin n = getnet_from-usagepin (upin, C);

// queue the net swprotodataqueue(prd, n, changeflag);

} /* end for each output usage pin */

} return TRUE;

/*--------------------------------------------------------*

Function: swconnectprotopin callback

Desc: queue outputs of net for bdd recalculation

*--------------------------------------------------------* void swconnectprotopin callback (long rc, NET n, PROTO PIN ppin,

CONTEXT ct, void *data) {

PROTOBOX pbox;

PROTODATA prd;

USAGEBOX ubox;

//

// nothing is affected when a net becomes attached to an output proto pin

// for input proto pins, the bdd value may change

// based on the proto pin probability data

// get protobox pbox = get_proto-box-fromprotopin(ppin, C);

// get protobox data prd = swprotodataget(pbox); if (protopin == SOURCEPIN) {

// queue all net outputs swprotodataqueueoutputs(prd, n, BDDCHG LEVELCHG);

}

} /* end if this pin is an input proto pin */

/*--------------------------------------------------------*

Function: swconnect usagepin-callback

Desc: queue outputs of pin's usage box for bdd rebuilding

*--------------------------------------------------------* void sw connectusagepin callback (long rc, NET n, USAGE_PIN upin,

CONTEXT ct, void *data) {

PROTOBOX pbox;

PROTODATA prd;

USAGEBOX ubox;

// get usage box ubox = get usage boxfromusagepin (upin, C);

// get protobox pbox = getparentproto boxfrom-net(n, C);

// get protobox data prd = swprotodataget(pbox);

140

BDDCHG I LEVELCHG, C);

}

/*--------------------------------------------------------*

Function: swconnect-pin callback

DeSc: queue appropriate outputs of pin for bdd rebuilding

*--------------------------------------------------------* void sw connectpin-callback (long rc, NET n, NETWORK PIN npin,

CONTEXT ct, void *data) {

// call the corresponding callback routines depending

// on pin type if (isprotopin (npin, C)) { swconnectprotopin callback (rc, n, (PROTOPIN) npin,

C, data);

// else its a usage pin

} else { swconnect usagepincallback (rc, n, (USAGEPIN) npin,

C, data);

}

}

/*--------------------------------------------------------*

Function: swdeleteusage-box callback

Desc: queue outputs of usage box for bdd rebuilding

*--------------------------------------------------------* void *data) {

PROTOBOX pbox;

PROTODATA prd;

// get protobox pbox = get_parent_proto-box-from-usage-box(ubox, C);

// get protobox data prd = swprotodataget(pbox);

} swqueue-usage-box-outputs(prd, ubox, BDDCHG I LEVELCHG,

C);

/*--------------------------------------------------------*

Function: swdeleteprotopin callback

Desc: queue proto pin outputs for bdd recalculation

*--------------------------------------------------------* void sw-deleteprotopin_callback (PROTOPIN ppin, CONTEXT ct, void *data) (

PROTOBOX pbox;

PROTODATA prd;

NET n;

//

// nothing is affected if the proto pin is a sink pin

// otherwise if (protopin-type (ppin, C) == SOURCEPIN) {

// get protobox pbox = getproto box fromprotopin(ppin, C);

// get protobox data prd = swprotodataget(pbox); n = get-netfromprotopin (ppin, C);

// queue all net outputs sw_protodataqueueoutputs (prd, n, BDDCHG I LEVELCHG);

141

}

} /* end if this pin is an input proto pin */

/*--------------------------------------------------------*

Function: swdelete usage-pin callback

Desc: queue outputs of the usage box of the usage pin for bdd recalc.

*--------------------------------------------------------* void sw-deleteusagepincallback (USAGEPIN upin, CONTEXT ct, void *data) {

PROTOBOX pbox;

USAGEBOX ubox;

PROTODATA prd;

// get usage box ubox = get usage-boxfromusagepin (upin, C); if (!ubox) { printf ("Warning: no usage box attached to this usage pin.\n"); return;

}

// get protobox pbox = getparentprotobox from usage box(ubox, C);

// get protobox data prd = swprotodataget (pbox);

} swqueue usage box outputs(prd, ubox, BDDCHG I LEVELCHG,

C);

/*--------------------------------------------------------*

Function: swdeletenetcallback

Desc: if a net is deleted, queue the outputs for bdd rebuilding

*--------------------------------------------------------* void sw-deletenetcallback (NET n, CONTEXT ct, void *data) {

NETDATA nd;

NET n2;

USAGEPIN upin;

NETWORK-PIN sinkpin;

PROTOBOX pbox;

PROTODATA prd;

QUEUE outcursor;

// get protobox pbox = getparentproto box from net(n, C);

// get protobox data prd = swprotodataget(pbox);

// get netdata nd = sw-netdataget(n);

// if net is queued for any change if (sw-flag-set-p (nd->flags, ANYCHG)) {

}

// dequeue if net is queued swprotodatadequeue-net(prd, n); sw-protodataqueue-outputs(prd, n, BDDCHG | LEVELCHG);

// disconnect all pins disconnect net-pins (n, C);

} swcheckpointadd-changed-net (n, nd->present-bdd);

142

/*--------------------------------------------------------*

Function: swdisconnectproto-pin-callback

Desc: queue outputs of net connected to proto pin for bdd recalculation

*--------------------------------------------------------* void sw-disconnect_proto-pin-callback (PROTOPIN ppin,

CONTEXT ct, void *data) {

PROTOBOX pbox;

PROTODATA prd;

USAGEBOX ubox;

NET n;

// nothing is affected when a net becomes disconnected

// from an output proto pin

I/ for input proto pins, the bdd value may change

// based on the proto pin probability data

// get protobox pbox = getprotoboxfromrprotopin(ppin, C);

// get protobox data prd = swprotodata-get(pbox); if (protopin-type (ppin, C) == SOURCEPIN) {

// get net from proto pin n = get net-fromprotopin (ppin, C);

// queue all net outputs swprotodataqueue outputs(prd, n, BDDCHG LEVELCHG);

}

) /* end if this pin is an input proto pin */

/*--------------------------------------------------------*

Function: sw_disconnect-usagepin-callback

Desc: queue outputs of net for bdd recalculation

*--------------------------------------------------------* void sw-disconnect-usagepin-callback (USAGEPIN upin,

CONTEXT ct, void *data) {

PROTOBOX pbox;

PROTODATA prd;

USAGEBOX ubox;

// get usage box ubox = get-usage-box-from-usagepin (upin, C); if (ubox) { printf ("Warning: no usage box attached to this return;

} usage pin.\n");

// get protobox pbox = getparent-protoboxfrom-usage-box(ubox, C);

// get protobox data prd = swprotodata-get(pbox);

} swqueue-usage-box-outputs (prd, ubox,

BDDCHG I LEVELCHG, C);

/*--------------------------------------------------------*

Function: swdisconnect-pin callback

Desc: queue appropriate outputs of pin for bdd

143

rebuilding void swdisconnectpin callback (NETWORKPIN npin,

CONTEXT ct, void *data) {

// call the corresponding callback routines depending

// on pin type if (isprotopin (npin, C)) { swdisconnect-protopin callback ((PROTOPIN) npin,

C, data);

// else its a usage pin

} else { swdisconnectusagepin callback ((USAGEPIN) npin,

C, data);

}

}

/*--------------------------------------------------------*

Function: sw createnetcallback

Desc: adds net to the checkpoint, this is a post callback

*--------------------------------------------------------* void swcreatenetcallback (NET n, PROTO BOX pbox, char *name,

CONTEXT ct, void *data) {

}

// adds net to checkpoint swcheckpoint-addcreatednet

(n);

/*--------------------------------------------------------*

Function: sw register callbacks

Desc: create IDM callbacks

*--------------------------------------------------------* void swregistercallbacks () {

// IDM callbacks

IDMCONTEXT :: addpostcb

(IDMCBCONNECTPROTOPIN, "SW", sw_connect-proto_pin callback, NULL);

IDMCONTEXT :: addpost_cb sw_connectusagepin callback, NULL);

IDMCONTEXT :: add-post_cb sw_connectpin callback, NULL);

IDMCONTEXT :: add_post_cb sw create net callback, NULL);

IDMCONTEXT :: addpre_cb swdelete-protopin callback, NULL);

IDMCONTEXT :: addpre_cb

(IDMCBDELETEUSAGE PIN, "SW", swdeleteusagepincallback, NULL);

IDMCONTEXT :: addpre_cb swdeletenetcallback, NULL);

IDMCONTEXT :: addpre-cb swdelete_iusageboxcallback, NULL);

IDMCONTEXT :: addpre_cb

(IDMCBDISCONNECTPROTO_PIN, "SW",

144

swdisconnect_protopin-callback, NULL);

)

IDMCONTEXT :: add_pre_cb

(IDMCBDISCONNECTUSAGEPIN, "SW", swdisconnect usagepin-callback,

NULL);

/*--------------------------------------------------------*

Function: sw-unregistercallbacks

Desc: remove IDM callbacks

*--------------------------------------------------------* void swunregistercallbacks () {

// IDM callbacks

IDMCONTEXT :: removepost-cb

(IDM CBCONNECTPROTOPIN, sw-connect-protopin callback);

IDMCONTEXT :: removepost-cb

(IDM CBCONNECTUSAGEPIN, sw_connect usagepin-callback);

IDMCONTEXT :: remove_post-cb

(IDM CB CONNECTPIN, sw-connectpin-callback);

IDMCONTEXT :: remove_post-cb

(IDM CBCREATENET, sw createnetcallback);

IDMCONTEXT :: removepre-cb

(IDM CBDELETEPROTOPIN, sw delete_proto_pin callback);

IDMCONTEXT :: removepre-cb

(IDM CBDELETEUSAGEPIN, sw-deleteusagepin callback);

IDMCONTEXT :: remove_pre-cb

(IDM CBDELETENET, sw-deletenetcallback);

IDMCONTEXT :: removepre-cb

(IDM CBDELETEUSAGEBOX, sw-deleteusage box.callback);

IDMCONTEXT :: remove_pre-cb

(IDM CBDISCONNECTPROTOPIN, sw disconnect-protopincallback);

}

IDMCONTEXT :: remove_pre-cb

(IDM CBDISCONNECTUSAGEPIN, swdisconnect usagepin callback); swscheckpoint.C

#include "sw switching.h"

/*--------------------------------------------------------*

Function: swsetcheckpointflag

Desc: given a net and a mask, set the checkpoint flag to the given value

*--------------------------------------------------------* bool sw-set-checkpointflag (NET n, int mask, bool value) {

NETDATA nd; nd = sw_netdataget (n); return swsetflag (&(nd->flags), mask, value);

}

/*--------------------------------------------------------*

Function: swcheckpointflag-set-p

Desc: given a net and a mask, determines whether the flag is set or not

*--------------------------------------------------------* bool swcheckpointflagsetp (NET n, int mask) {

145

NETDATA nd; nd = sw-netdata get (n); return sw-flagset-p (nd->flags, mask);

}

/*--------------------------------------------------------*

Function: swcheckpoint list deflag

Desc: removes INCHECKPOINTLIST flag on nets in the checkpoint and in all following checkpoints

*--------------------------------------------------------* bool sw-checkpoint-listdef lag (SWCHECKPOINT cp, int mask) {

SW_CP_ITEM cpi;

// remove examined flags if (cp != {

// go through each item on this checkpoint's list cpi

= cp->item; while (cpi) {

// set the examined flag to false sw set checkpointflag (cpi->n, mask, FALSE);

}

) cpi = cpi->next;

} return TRUE;

/*--------------------------------------------------------*

Function: swcheckpointupdateprob

Desc: calculates probabilities for relevant nets for setting a checkpoint

Pre: protobox has at least one mode.

all nets have their structures updated

*--------------------------------------------------------* bool sw-checkpointupdateprob (PROTODATA prd, SWCHECKPOINT cp) {

NET n; float prob;

// if all nets have not yet been calculated, do so if (iswflagsetp (prd->flags, ALLNETSCALC_P)) { for (n = fnet (prd->pbox, C); n; n = n-net (n, C)) {

// avoid constant nets (ONE and ZERO) if (strncmp (net-name (n, C), "ONE", 3) I= 0 && strncmp (net-name (n, C), "ZERO", 4) 1= 0) {

}

// calculate both probabilities for an

//

// arbitrary mode, so it will calculate for all modes swnetswitchprob (prd->mode[0], n, &prob); sw netoneprob (prd->mode[0], n, &prob);

// set global flag that calculation was done sw_set_flag (&(prd->flags), ALLNETSCALCP, TRUE);

//

//

} all nets have been calculated, i.e. a checkpoint has already been set else {

// clear queue

146

swcalctraverseentirequeue (prd);

// calculate all added nets

QUEUE nl; nl = prd->newnetslist; while (nl) { sw-net-switchprob (prd->mode[O], nl->qnet, &prob); sw-netoneprob (prd->mode[0], nl->qnet, &prob);

// add it to the checkpoint list sw-checkpointaddcreated_net (nl->qnet);

} nl = nl->next;

} swprotodatanewnetslistclear (prd);

} return TRUE;

/*--------------------------------------------------------*

Function: swsetcheckpoint

Desc: creates the checkpoint

*--------------------------------------------------------* bool sw-set checkpoint (PROTOBOX pbox, SWCHECKPOINT *cp) {

PROTODATA prd; int index;

// get protobox data prd = sw protodataget(pbox);

// create the checkpoint

*cp = (SWCHECKPOINT) malloc (sizeof (sw-checkpoint));

(*cp)->pbox = pbox;

// if allocation error if (*cp == NULL) { return FALSE;

}

(*cp)->item = NULL;

(*cp)->next = NULL;

// set the id number if (prd->cp) (

}

(*cp)->id =

} else { prd->cp->id

(*cp)->id = 0;

+ 1;

// store the checkpoint in the protodata

(*cp)->prev = prd->cp; if (prd->cp) { prd->cp->next = (*cp);

} prd->cp = *cp;

// calc probs for all checkpointed nets if necessary swcheckpointupdateprob (prd, (*cp)->prev);

I return TRUE;

/*--------------------------------------------------------*

Function: swget-checkpoint-id

Desc: get the checkpoint id keyword from the net

*--------------------------------------------------------*

147

int swgetcheckpointid (NET n) ( int *id; locatekeyword-value (n, keycheckpointid, &id, C); return *id;

}

/*--------------------------------------------------------*

Function: sw-set-checkpointid

Desc: sets the checkpoint id keyword on a net

*--------------------------------------------------------* bool swsetcheckpointid (NET n, int id) { set keyword value (n, keycheckpointid, id, C); return TRUE;

}

/*--------------------------------------------------------*

Function: swcheckpoint-new cp-item

Desc: returns an initialized checkpoint item

*--------------------------------------------------------* bool swcheckpoint new cpitem (NET n, PROTODATA prd, SWCPITEM *cl) { int id;

}

// if there is no checkpoint if (prd->cp == NULL)

{ return FALSE;

// get the most recent checkpoint id, if any,

// of the checkpoint that contains this net id = swget-checkpointid(n);

}

// if this id matches the current id,

// don't add it, try to keep this checkpoint list

// nonrepetitve if (id == prd->cp->id) { return FALSE;

// set the net's checkpoint id to the

// current one swset_checkpointid (n, prd->cp->id);

// allocate space for a checkpoint list item

(*cl) = (SWCPITEM) malloc (sizeof (swcheckpointitem));

// store net on item

(*cl)->n = n;

// add item to the beginning of the list

(*cl)->next

= prd->cp->item; prd->cp->item = (*cl);

} return TRUE;

/*--------------------------------------------------------*

Function:

Desc: sw checkpoint add changednet save the old data of this newly changed net

Pre: assumes updated values on the netdata

*--------------------------------------------------------* bool swcheckpoint add changed net (NET n, BDDPTR oldbdd) {

PROTOBOX pbox;

PROTODATA prd;

148

SWCPITEM ci;

NETDATA nd; float *pl; int index; pbox = getparentprotoboxfrom-net(n, C);

// pbox should be available if (!pbox) { return FALSE;

}

// get protodata prd = sw protodataget(pbox);

// if there's no checkpoint, return if (!prd->cp) { return FALSE;

}

// get the pl data from the netdata nd = sw-netdataget(n); pl

= (float *) BDDUSERDATAPTR(oldbdd);

// initialize new item, and check if its added or not if (swcheckpointnew-cpitem (n, prd, &cl)) {

// copy p1 and ps arrays cl->ps = (float *) malloc (sizeof (float) * prd->nummodes); cl->pl = (float *) malloc (sizeof (float) * prd->numnmodes);

} for (index = 0; index < prd->num modes; index++) { cl->ps[index] = nd->ps[index] OFFSET; cl->pl[index] = pl[index] OFFSET;

}

} return TRUE;

/*--------------------------------------------------------*

Function: sw-checkpointaddcreatednet

Desc: add a created net to the checkpoint with initial values of 0

*--------------------------------------------------------* bool sw checkpointadd created net (NET n) {

SWCPITEM cl;

PROTOBOX pbox;

PROTODATA prd; int index; pbox = getparentprotobox-from net(n, C);

// pbox should be available if (!pbox) { return FALSE;

}

// get protodata prd = swprotodata-get(pbox);

// if there is no checkpoint, add this to the list

// of new nets if (prd->cp == NULL && sw-flagsetp (prd->flags, ALLNETSCALC P)) { sw-protodata new netslist_add (prd, n); return FALSE;

}

149

if (sw checkpoint-new-cp-item(n, prd, &cl)) {

// initialize p1 and ps arrays cl->ps = (float *) malloc (sizeof (float) * prd->numjmodes); cl->pl = (float *) malloc (sizeof (float) * prd->nummodes);

} for (index = 0; index < prd->num modes; index++) { cl->ps[index] = 0.0; cl->pl[index] = 0.0;

}

} return TRUE;

/*--------------------------------------------------------*

Function: sw checkpoint listfindnet

Desc: searches through a list and returns whether the given net is part of the lsit

*--------------------------------------------------------* bool swcheckpoint listfindnet (NET n, SWCPITEM cl) { while (cl) ( if (cl->n == n) { return TRUE;

} else { cl = cl->next;

}

}

} return FALSE;

/*--------------------------------------------------------*

Function: swclear checkpoint

Desc: frees checkpoint data

*--------------------------------------------------------* bool swclear-checkpoint (SWCHECKPOINT *cp) {

SWCPITEM cpi;

PROTODATA prd; bool delete item-p = FALSE;

// check if checkpoint is NULL if (cp == NULL) { return FALSE;

}

// get proto data prd = swprotodataget ((*cp)->pbox);

// if this is the most recent checkpoint,

// update it if (prd->cp == *cp) { prd->cp = (*cp)->prev;

}

// if there is a following checkpoint, update its

// prev pointer if ((*cp)->next) {

(*cp)->next->prev = (*cp)->prev;

}

// if there is no checkpoint created before

// this checkpoint if ((*cp)->prev == NULL) {

// free each item while ((*cp)->item) {

150

} cpi = (*cp)->item;

(*cp)->item = (*cp)->item->next; sw-setcheckpoint-id (cpi->n, -1); free(cpi->pl); free(cpi->ps); free(cpi);

// this is not the earliest checkpoint

} else {

// update the previous checkpoint's next pointer

(*cp)->prev->next = (*cp)->next;

// concatanate lists

// mark all items on the previous list cpi = (*cp)->prev->item; while (cpi) { swsetcheckpointflag (cpi->n, INCHECKPOINT_LIST, TRUE); cpi = cpi->next;

}

// add all items that are not marked while ((*cp)->item) (

// otherwise if its marked as occurring in previous

// list, delete item if (sw-checkpointflag-setp ((*cp)->item->n, INCHECKPOINTLIST)) { cpi = (*cp)->item;

(*cp)->item = (*cp)->item->next; sw_setcheckpoint_flag (cpi->n, INCHECKPOINTLIST, FALSE); swset-checkpointid (cpi->n, -1); free(cpi->pl); free(cpi->ps); free(cpi);

}

// else add it to head of the previous list

} else { cpi = (*cp)->item;

(*cp)->item = (*cp)->item->next; cpi->next =

(*cp)->prev->item; swset-checkpointid (cpi->n, (*cp)->prev->id);

(*cp)->prev->item = cpi;

}

}

// clear all incheckpoint-list flags sw-checkpointlistdeflag ((*cp)->prev, IN_CHECKPOINTLIST); free(*cp);

} return TRUE;

/*--------------------------------------------------------*

Function: sw-change-cursoradddeletednet

Desc: sets up and adds a change cursor element to the *next list that is based on a deleted net

*--------------------------------------------------------* bool sw change-cursor add deleted net (SWCPITEM cpi, int mode,

SWCHANGECURSOR *next) {

SWCHANGECURSOR cc;

// store change data

151

}

// only add it if the previous values are not 0, because now the

// values are 0, therefore there wouldn't have been changes if (cpi->ps[mode] == 0.0 && cpi->p1[mode] ==

0.0) { return FALSE; cc = (SWCHANGECURSOR) cc->n = cpi->n; cc->deltaps

=

-cpi->ps[mnode]; cc->deltapl = -cpi->pl[mode]; cc->ps = cpi->ps[mode]; cc->pl = cpi->pl[mode]; cc->next = *next;

*next = cc; return TRUE;

}

/*--------------------------------------------------------*

Function: swchangecursoradd

Desc: sets up and adds a change cursor element to the *next list

*--------------------------------------------------------* bool swchangecursor add (SW_CP_ITEM cpi, int mode,

SWCHANGECURSOR *next) {

SWCHANGECURSOR cc;

NETDATA nd; float templ, temp2; float *pl; nd = swnetdata-get(cpi->n);

//

// if this net has no values for it (has a null present bdd) if (!nd->present-bdd) {

}

// act like its a deleted net, no future info return sw-change_cursoradd deletednet (cpi, mode, next);

// get state probability values p1 = (float *) BDDUSERDATAPTR(nd->presentbdd);

}

// if there's no change, return false if (sw float equals (nd->ps[mode] OFFSET, cpi->ps[mode]) swfloat equals (pi[model

-

OFFSET, cpi->pl[mode])) { return FALSE;

&&

// store change data cc = (SWCHANGECURSOR) malloc (sizeof (swchangecursor)); cc->n = cpi->n; cc->deltaps

= (nd->ps[model OFFSET) cpi->ps[mode]; cc->deltapl = (pl[mode] OFFSET) cpi->pl[mode]; cc->ps = cpi->ps[mode]; cc->pl = cpi->pl[mode]; cc->next

= *next;

*next = cc; return TRUE;

152

/*--------------------------------------------------------*

Function: sw-checkpointcursor-deflag

Desc: resets all the netdata flags indicating that net is in a cursor

*--------------------------------------------------------* bool swcheckpoint-cursor-def lag (SWCHANGECURSOR cc) {

// traverse through each item in the cursor while (cc) {

// reset the flag swsetcheckpoint_f lag (cc->n, IN-CURSOR, FALSE);

I cc

= cc->next;

} return TRUE;

/*--------------------------------------------------------*

Function: sw checkpointcursorlistfindnet

Desc: searches through a cursor list and returns whether the given net is part of the lsit

*--------------------------------------------------------* bool sw checkpointcursorlistfind-net (NET n, SW CHANGECURSOR cc) { while (cc) { if (cc->n == n)

} return TRUE; else { cc

= cc->next;

{

}

}

} return FALSE;

/*--------------------------------------------------------*

Function: swget-change-cursor

Desc: returns a cursor (pointer to a list) of all changed nets and their difference in values

*--------------------------------------------------------* bool swget-changecursor (SWCHECKPOINT cp, SWMODE m,

SWCHANGECURSOR *return_changecursor) {

SW_CP_ITEM cpi;

SWCHECKPOINT cpt;

SWCHANGECURSOR cc; float prob;

*returnchangecursor = NULL;

// clear queue swcalctraverse-entirequeue (m->prd);

//

// traverse through each checkpoint since this checkpoint (inclusive) cpt

= cp; while (cpt) {

// traverse through each changed item cpi = cpt->item; while (cpi) {

// only add net if its not in cursor yet if (Isw checkpointflagsetp (cpi->n, INCURSOR)) {

// if the net is deleted if (cpi->n->isdeleted)) {

// add deleted net to change cursor

153

swchange-cursoradd deleted net (cpi, m->index, return_changecursor);

// otherwise

I else (

// update switching and state values swnetswitch-prob (m, cpi->n, &prob); swnetoneprob (m, cpi->n, &prob);

} sw-change-cursor_add (cpi, m->index, returnchangecursor); i swsetcheckpointflag (cpi->n, INCURSOR, TRUE);

} cpi = cpi->next;

} cpt

= cpt->next;

// remove all the traversal flags swcheckpointlist deflag(cp,

INCURSOR);

} return TRUE;

/*--------------------------------------------------------*

Function: swgetchange info

Desc: returns a set of changed nets and their difference in values

*--------------------------------------------------------* bool sw-getchange_info (SW CHANGECURSOR changecursor,

NET *return-net, float *return_pl, float *return_plchange, float *returnps, float *returnpschange) {

*returnnet = changecursor->n;

*returnpl = changecursor->pl;

*return_plchange = changecursor->deltapl;

*return-ps = changecursor->ps;

*returnpschange = changecursor->deltaps;

} return TRUE;

/*--------------------------------------------------------*

Function: swincchangecursor

Desc: points the cursor to the next item in the change list, deletes current item

*--------------------------------------------------------* bool swinc-changecursor (SWCHANGE CURSOR *change-cursor, bool *returneol) {

SWCHANGECURSOR cc; cc = *change-cursor;

*changecursor = (*change-cursor)->next;

// free cursor free(cc);

// returns whether or not the cursor is at the end of

// the list

*returneol = (*changecursor == NULL); return TRUE;

}

/*---------------------------------------------------------*

154

Function: sw-delete-change-cursor

Desc: clears changed list

*--------------------------------------------------------* bool swdelete-change-cursor (SW-CHANGECURSOR *changecursor) {

SWCHANGECURSOR cc;

// frees each node on the list while (*changecursor) { cc = *change-cursor;

*change-cursor = (*change-cursor)->next; free(cc);

)

} return TRUE;

/*---------------------------------------------------------*

Function: sw clear all checkpoints

Desc: frees all checkpoint data starting from the earliest checkpoint

*--------------------------------------------------------* bool swclearallcheckpoints (SW_CHECKPOINT cp) {

SWCHECKPOINT cp2;

// go to the earliest checkpoint if (cp) { while (cp->prev) { cp = cp->prev;

}

} while (cp) { cp2 = cp; cp = cp->next; swclear-checkpoint(&cp2);

}

} return TRUE; swcursor.C

#include <stdio.h>

#include "vim.h"

#include "sw switching.h"

/*--------------------------------------------------------*

Function: findnet

Desc: search through a queue for a given net and returns the queue or NULL

*--------------------------------------------------------*

QUEUE find_net(NET n, QUEUE nl) {

QUEUE tnl; tnl = nl; while (tnl) { if (tnl->qnet == n) return tnl;

I else { tnl = tnl->next;

}

{

}

I return NULL;

/*--------------------------------------------------------*

Function: sw-output-net-cursor

Desc: gets the cursor to traverse all the outputs nets stemming from the input net

155

QUEUE sw output net cursor (NET in) {

NETWORKPIN sinkpin;

USAGEPIN upin;

QUEUE output netlist, tnl;

NET n;

} if (!in) { printf ("Warning: no net specified for output net cursor.\n"); return NULL; output netlist = NULL; for (sink-pin = f-netpin(in, SINK-PIN, C); sink_pin; sinkpin = n-netpin(sinkpin, C)) {

// if this is not an output proto pin if (!(is_protopin(sinkpin, C))) {

// obtain output usage pins from the usage box from the

// sink network pin connected to the net for (upin

= f-usagepin

(get usage box from usagepin

((USAGEPIN) sinkpin, C),

OUTPUTPIN, C); upin; upin = n-usagepin(upin, C)) { n = get net fromusagepin(upin, C);

}

// add net to the list if (n && i C), output net list))) ( tnl = (QUEUE) malloc (sizeof (queue)); tnl->qnet = n; tnl->next = output net-list; output net list = tnl;

} /* end for each usage pin */

) /* end if this is not a proto net */

}

/* end for each sink net pin */

} return output netlist;

/*--------------------------------------------------------*

Function: swoutput net

Desc: returns the current net of the cursor

*--------------------------------------------------------*

NET sw_outputnet(QUEUE cursor) {

} return cursor->qnet;

/*--------------------------------------------------------*

Function: sw_output netcursorinc

Desc: increments cursor to point to the next element

*--------------------------------------------------------* bool swoutputnetcursor_inc(QUEUE *cursor, bool *cursor-nullp) {

*cursor = (*cursor)->next;

*cursor-null-p = (*cursor

==

NULL); return TRUE;

}

/*--------------------------------------------------------*

I Function: swoutput net cursorinc

156

Desc: increments cursor to point to the next element

*-----------------------------------------------------*1 bool swoutputnetcursorjinc (QUEUE *cursor) { bool cursor-null;

} return sw-output-net-cursorinc (cursor, &cursornull);

/*--------------------------------------------------------*

Function: sw-input netcursor

Desc: gets the cursor to traverse all the inputs nets stemming from the output net

*--------------------------------------------------------*

QUEUE sw inputnetcursor (NET out) {

NETWORKPIN source-pin;

USAGEPIN upin;

QUEUE input-netlist, tnl;

NET n; if (!out) { printf ("Warning: no net specified for input net cursor.\n"); return NULL; input net list = NULL; for (sourcepin = f-netpin(out, SOURCEPIN, C); sourcepin; sourcepin = n-netpin(source-pin, C)) {

// if this is not an input proto pin if ((is_protopin(sourcepin, C))) {

// obtain input usage pins from the usage box from the

// source network pin connected to the net for (upin = fusagepin

(get usageboxfrom_usagepin

((USAGEPIN) source-pin, C),

INPUTPIN, C); upin; upin = nusagepin(upin, C)) { n

= getnetfrom usagepin(upin, C);

}

// add net to the list if (n && l(find-net(get netfrom_usagepin(upin, C), input net-list))) ( tnl = (QUEUE) malloc (sizeof (queue)); tnl->qnet = n; tnl->next = input-netlist; inputnetlist = tnl;

}

) /* end for each usage pin */

} /* end if this is not a proto net */

/* end for each source net pin */ return inputnet_list;

}

/*--------------------------------------------------------*

Function: sw-input-net

Desc: returns the current net of the cursor

*--------------------------------------------------------*

NET sw-inputnet(QUEUE cursor) {

} return cursor->qnet;

157

/*--------------------------------------------------------*

Function: sw inputnetcursorinc

Desc: increments cursor to point to the next element

*--------------------------------------------------------* bool sw input net cursor inc(QUEUE

*cursor, bool *cursor-nullp) {

*cursor = (*cursor)->next;

*cursor-nullp = (*cursor == NULL); return TRUE;

}

/*--------------------------------------------------------*

Function: sw inputnetcursorinc

Desc: increments cursor to point to the next element

*--------------------------------------------------------* bool swinput netcursor inc(QUEUE *cursor) { bool cursor-null;

} return sw input netcursorinc (cursor, &cursor-null); sw-global.C

#include "sw-switching.h"

/*--------------------------------------------------------*

Function: swglobal-bddtable set

Desc: sets an index of the bddtable to the given value

Pre:

Post: none globalbddtablesize = max (index, globalbddtable-size) globalbddtable_size[index] = pd all table entries are either valid pidatas or are NULL

*--------------------------------------------------------* bool sw-globalbddtable set (int int i; index, PIDATA pd) { if (index < 0) { printf ("Warning: cannot set table value for a negative index.\n"); return FALSE;

}

// expand table if index is larger than the

// table size if (index >= globalbddtablesize)

{

// if the table is NULL, do a malloc if (global bddtable == NULL) { global bddtable = (PIDATA *) sw jmalloc

(sizeof (primaryinput data) * (index + 10),

"global bddtable");

} else ( global-bddtable = (PIDATA *) sw-realloc

(globalbddtable, sizeof (primaryinput data) * (index + 10),

"global bddtable");

}

// fill in the table with NULLs for (i = globalbddtablesize; i < index + 10; i++)

{ global bddtable[i] = NULL;

}

// update table size global-bddtable-size = index + 10;

158

globalbddtable[index] = pd;

} return TRUE;

/*--------------------------------------------------------*

Function: sw-global bddtable-get

Desc: returns value at the given index of the

Pre: bddtable none

Post: on success, returns the value global bddtable[index] on error, returns a NULL

*--------------------------------------------------------*

PIDATA swglobalbddtableget (int index) ( if (index < 0 11 index >= globalbddtable size) { printf ("Warning: cannot get table value for a index %d.\n", index); return NULL;

} return globalbddtable[index];

/*--------------------------------------------------------*

Function: sw-global-pblist-add

Desc: adds a proto box to the global proto box list

Pre: globalpblist is valid or NULL, {pbox} does not yet occur in global-pblist

Post: {pbox} is added to the head of the list

*--------------------------------------------------------* void swglobalpblistadd (PROTOBOX pbox) {

PBOXLIST pb;

// allocate space for pbox list entry pb = (PBOXLIST) sw-malloc (sizeof (protobox list),

"proto box list item");

// initialize pbox list entry pb->pbox = pbox; pb->next = globalpblist;

}

// add it to the global list globalpblist = pb;

/*--------------------------------------------------------*

Function: sw__globalpblist-remove

Desc:

Pre: removes a proto box from the global proto box list globalpblist is valid or NULL, (pbox) occurs only once in globalpblist

Post: {pbox} is removed from the list

*--------------------------------------------------------* void swglobalpblist-remove (PROTOBOX pbox) {

PBOXLIST tnl, tnlparent;

// try to find it tnl = globalpblist; tnlparent

= globalpblist; while (tnl I= NULL && tnl->pbox I= pbox) { tnlparent = tnl; tnl = tnl->next;

// if its not found if (tnl == NULL)

{ return;

}

159

// if its at the head if (tnl == tnlparent) { globalpblist

= globalpblist->next; free(tnl); return;

}

// its in the middle or at the end tnlparent->next = tnl->next; free(tnl);

}

/*--------------------------------------------------------*

Function: sw-global_maxnummodes-update

Desc: if (value} is greater than

Pre:

Post: globalmaxnummodes, set it to (value} globalmaxnummodes has been set global_maxnummodes

= max ({value}, global_maxnum_modes) globalmaxnummodes is the maximum number of modes that any protodata has

*--------------------------------------------------------* void sw-global-max]nummodesupdate (int value) { global-max _nummodes = max (value, globalmax_nummodes);

} swinit.C

#include "swswitching.h"

/*--------------------------------------------------------*

Function: swinitonetime

Desc: initializes bdd package and expanded

Pre:

Post: logic equation boxes none

bdd package is initialized, global_initp = TRUE, all usage boxes of all pboxes on the globalpboxlist have associated logic equation boxes

*--------------------------------------------------------* void sw-initonetime () {

PBOXLIST cpbox;

// check whether its already initialized if (global init-p) return;

}

// initialize bdd package with each bdd node having

// user data space bddinit (sizeof (float) * globalmax._nummodes);

// initialize bdd table space

// view needed for expanded equations

VIEW v = createview ("EQNVIEW", C);

// for each proto box, build expanded equation

// boxes cpbox = globalpblist; while (cpbox) (

//

// bldeqn and newgen operates on the current

BDsyn box, set this pbox

BDsyn_set_current-proto-box (cpbox->pbox);

160

//

// make expanded equation boxes for each def box in the current proto box bldeqn();

// newgen); cpbox = cpbox->next;

} global_initp = TRUE;

}

/*--------------------------------------------------------*

Function: sw-define-mode

Desc: creates a new mode and adds it to (pbox)'s

Pre:

Post: protodata none on success, protodata associated with pbox has mode added to its mode array and its num_modes field is updated, returns TRUE on error, no action, returns FALSE

*--------------------------------------------------------* bool swdefine-mode (PROTOBOX pbox, char *name, SWMODE *return-mode) {

PROTODATA prd;

// if calculation has already been done,

// add a mode printf ("Warning: cannot define a mode return FALSE; after a calculation has been done.\n");

// check if (pbox printf return

} pbox

== NULL) {

("Warning:

FALSE; cannot define a mode for a NULL pbox.\n");

// check name if (name == NULL) { printf ("Warning:

} replacing NULL name with 'unnamed'.\n"); prd = swprotodataget(pbox);

// set up mode

*returnmode = sw_mode new (name, prd);

// add mode to protodata swprotodata_add_mode (prd, *return-mode);

} return TRUE;

/*--------------------------------------------------------*

Function: swsetdefault one-prob

Desc: set initial state probabilities for a mode

Pre:

Post: none m->pl = prob, all pidata flags are set to need updating

*--------------------------------------------------------* bool swsetdefaultone-prob(SWMODE if (m == NULL)

{

M, float prob) { printf ("Warning: cannot set probability for a null mode.\n"); return FALSE;

} sw_modeset-pl(m, prob); sw_protodata-pidata-flag defaults

(m->prd, m);

161

return TRUE;

/*--------------------------------------------------------*

Function: sw setdefaultswitchprob

Desc: set initial switching probabilities for a mode

Pre:

Post: none m->halfps = prob/2, all pidata flags are set to need updating

*--------------------------------------------------------* bool swsetdefault switch-prob(SWMODE m, float prob) { if (m == NULL) { printf ("Warning: cannot set probability for a null mode.\n"); return FALSE;

} swmode set halfps(m, prob/2.0); swprotodatapidata-flag-defaults

(m->prd, in);

} return TRUE;

/*--------------------------------------------------------*

Function:

Desc: sw setoneprob set initial state probability of a pin for a mode

Post: probability set for mode for npin

*--------------------------------------------------------* bool sw_setoneprob(SWMODE

PIDATA pd; if (in == NULL)

{ printf ("Warning: cannot set probability for a null mode.\n"); return FALSE;

} if (npin == NULL) { printf ("Warning: cannot set probability for a null net pin.\n"); return FALSE;

} pd = swpidataget (npin, NULL);

// set probability swpidatasetprob (pd, prob, FALSE, m->index, PROB_P1);

// mark for updating swpidatasetflag (pd, ONENEEDSUPDATE, TRUE);

} return TRUE;

/*--------------------------------------------------------*

Function: swset switch-prob

Desc: set initial switching probability of a pin for a mode

Post: probability set for mode for npin

*--------------------------------------------------------* bool sw_set switchprob(SWMODE in, NETWORK-PIN npin, float prob) {

PIDATA pd; if (in == NULL) { printf ("Warning: cannot set probability for a null mode.\n"); return FALSE;

}

162

if (npin == NULL)

{ printf ("Warning: cannot set probability for a null net pin.\n"); return FALSE;

) pd = swpidata-get (npin, NULL);

// set probability sw_pidatasetprob (pd, prob/2.0, FALSE, m->index, PROBPS);

// mark for updating swpidatasetflag (pd, SWITCHNEEDSUPDATE, TRUE);

} return TRUE;

/*--------------------------------------------------------*

Function: swclear data

Desc: for each protobox in use, clears its protodata, then resets the environment

*--------------------------------------------------------* bool sw clear data (void) {

PROTODATA prd;

// for each proto box, clear its data while (globalpblist) {

} prd = swprotodata-get (globalpblist->pbox); swprotodataclear (prd); free (prd); sw-globalpblist-remove (globalpblist->pbox);

// reset global variables global_initp = FALSE; globalmaxnum_modes = 0; global-bddtablesize = 0; free(global-bddtable); globalbddtable = NULL;

// keep the global size global-pblist = NULL;

// quit the bdd package bdd-quito;

} return TRUE;

/*--------------------------------------------------------*

Function: swfirstmode

Desc: returns mode at index 0 in protodata

Pre: {prd) valid

*--------------------------------------------------------* bool sw-first-mode (PROTOBOX pbox, SWMODE *return_mode) {

PROTODATA prd;

*return_mode = NULL;

// can't take a null pbox if (pbox == NULL) ( printf ("Warning: cannot get mode for a null proto box.\n"); return FALSE;

} prd = swprotodataget (pbox); if (prd->nummodes <= 0) (

163

} printf ("Warning: no modes in proto box.\n"); return FALSE;

*return-mode = prd->mode[O]; return TRUE;

}

/*--------------------------------------------------------*

Function: swnext mode

Desc: returns mode that follows (mode}, NULL if none, in proto box

Pre: {mode} valid

*--------------------------------------------------------* bool swnext mode (SW_MODE mode, SWMODE *returnmode) {

*returnmode = NULL;

// can't take a null mode if (mode == NULL) ( printf ("Warning: cannot get next mode for a null input mode.\n"); return FALSE;

} if (mode->prd->num_modes <= mode->index + 1) { return FALSE;

}

}

*returnmode

= mode->prd->mode[mode->index

+ 1]; return TRUE; swmode.C

#include "swswitching.h"

/*--------------------------------------------------------*

Function: swmode new

Desc: returns a new instance of a mode

Pre:

Post:

*name is NULL or valid, {prd) is valid returns valid mode with name {name}, protodata (prd}, index = -1, p1 and halfps values = -1

(index should be set later)

*--------------------------------------------------------*

SWMODE sw-mode new (char *name, PROTODATA prd) (

SWMODE mode;

// allocate space mode

=

(SWMODE) sw-malloc (sizeof (sw mode),

"mode"); if (name 1= NULL) {

I mode->name = (char *) sw-malloc (strlen(name), "mode name"); strcpy (mode->name, name);

} else { mode->name

=

(char *) swmalloc (strlen ("unnamed"), "mode name"); strcpy (mode->name, "unnamed"); mode->index = -1; mode->prd = prd; mode->pl = -1; mode->halfps

= -1;

} return mode;

/*--------------------------------------------------------*

Function: sw-mode-set-pl

Desc: set (mode}'s default pl value

164

Pre: (mode) is valid

Post: mode->pl = p1

*--------------------------------------------------------* void sw mode-set-pl (SW_MODE mode, float p1) { if (p1 < 0.0) { printf ("Warning: pl is negative, results may be incorrect.\n");

} mode->pl = pl;

}

/*--------------------------------------------------------*

Function: swmodeset halfps

Desc:

Pre: set (mode)'s default halfps value

(mode) is valid

Post: mode->halfps = halfps

*--------------------------------------------------------* void swmodeset-halfps (SWMODE mode, float halfps) { if (halfps < 0.0) ( may be incorrect.\n"); printf ("Warning: halfps is negative, results

) mode->halfps

= halfps;

/*--------------------------------------------------------*

Function: swmodeset index

Desc: set {mode}'s index

Pre: (mode) is valid, index should be set when adding mode to proto box, and should be set to the number of modes before the addition

Post: mode->index = index

*--------------------------------------------------------* void swmodesetindex (SWMODE mode, int index) { mode->index = index;

}

/*--------------------------------------------------------*

Function: swmodeclear

Desc: clear (mode}'s contents and (mode}

Pre:

Post:

(mode) is valid and not NULL all (mode) fields are freed

*--------------------------------------------------------*

} free (mode->name); free (mode); swnetdata.C

#include "swswitching.h"

/*----------------------------------------------------------*

Function: swnetdataset keyword

Desc: sets keyword for {n)

Pre: (n) is valid

Post: (n)'s netdata keyword is {nd)

*-------------------------------------------------------* void swnetdatasetkeyword (NETDATA nd, NET n) { set-keyword-value (n, keynetdata, nd, C);

)

/*--------------------------------------------------------*

Function: swnetdatadoesexist

Desc: returns whether or not netdata has ever been created for (n)

Pre:

Post:

(n} is valid returns TRUE if (n)'s key-netdata is not

NULL, false otherwise

*--------------------------------------------------------* bool swnetdatadoesexist (NET n) (

165

NETDATA nd;

// try to get the netdata keyword locate-keyword value (n, keynetdata, &nd, C);

} return (nd

I=

NULL);

/*--------------------------------------------------------*

Function: swnetdatahasdata

Desc: returns whether {nd) has data (whether it

Pre: should be queued)

{nd) is valid

Post: returns TRUE if netdata has data,

FALSE otherwise

*--------------------------------------------------------*

) bool sw-netdatahas data (NETDATA nd) { return (nd->presentbdd !=

/*--------------------------------------------------------*

Function: swnetdata-get

Desc:

Pre:

Post: get (n)'s netdata, initializing if necessary

(n} is valid or NULL on success, a valid netdata is returned if initialized, a netdata with a NULL present bdd, next-bdd, ps and -1 level and 0 flag is returned on error, returns NULL

*--------------------------------------------------------*

NETDATA swnetdataget (NET n) {

NETDATA nd;

// can't work with a NULL n if (n == NULL) { printf ("Warning: no netdata because of null net.\n"); return NULL;

}

// try to get the netdata, and return it if its not NULL locatekeyword value(n, keynetdata, &nd, C);

} if (nd 1= NULL) { return nd;

// initialize netdata nd = (NETDATA) sw-malloc (sizeof (netdata), "netdata"); nd->presentbdd = NULL; nd->nextbdd = NULL; nd->level = -1; nd->ps = NULL; nd->flags = 0; nd->n = n;

// set keyword set keyword value (n, keynetdata, nd, C);

// add netdata to list swprotodatanlistadd (nd, n);

} return nd;

/*--------------------------------------------------------*

Function: swnetdata setpresentbdd

Desc:

Pre:

Post: sets {nd}'s presentbdd

(nd) is valid

(nd)->present-bdd = pbdd;

166

*-------------------------------------------------------void swnetdata-set-present-bdd(NETDATA nd, BDDPTR pbdd) {

//

// add checkpoint if a) the bdds are different, and

b) the previous level is not -1 (this means that

// the bdds change between calculations) if (nd->present bdd 1= pbdd) {

if (nd->present-bdd == NULL) { sw-checkpointaddcreatednet (nd->n);

} else ( sw-checkpoint-add-changed-net (nd->n, nd->present-bdd);

}

} nd->present-bdd = pbdd;

/*--------------------------------------------------------*

Function: swnetdatasetnextbdd

Desc:

Pre: sets {nd)'s next bdd

{nd} is valid

Post: {nd}->nextbdd = nbdd;

*--------------------------------------------------------* void swnetdatasetnext bdd(NETDATA nd, BDDPTR nbdd) { nd->nextbdd = nbdd;

/*--------------------------------------------------------*

Function: swnetdatasetlevel

Desc: sets {nd)'s level

Pre: (nd) is valid

Post: on success, (nd}->level on error, no action

*--------------------------------------------------------*

= level void sw-netdatasetlevel(NETDATA nd, int level) { nd->level = level;

/*--------------------------------------------------------*

Function: swnetdatasetps

Desc: sets (nd}'s ps data

Pre:

Post:

(nd) is valid on success, {nd)->ps on error, no action

= ps

*--------------------------------------------------------* void sw-netdata-set-ps(NETDATA nd, float *ps, int num-Modes) { int i;

// don't set if nd->presentbdd is NULL if (nd->present-bdd == NULL && ps 1= NULL) { return;

}

// check that data is valid for (i = 0; i < num_modes; i++) { if (ps[i] <= 0.0) ( printf ("Warning: will not store negative probability values for netdata.\n");

}

} nd->ps = ps;

/*--------------------------------------------------------*

Function: swnetdatasetflag

Desc: sets netdata (mask) flag to (value)

Pre: (nd), (mask), (mode) valid

Post: flag is set

*--------------------------------------------------------* void swnetdatasetflag (NETDATA nd, int mask, int value) {

167

} swset_flag (&(nd->flags), mask, value);

/*---------------------------------------------------------*

Function: sw-netdataclear

Desc: clear {nd)'s contents and (nd)

Pre: (nd} is valid and not null

Post: all {nd} fields are freed

*--------------------------------------------------------* void swnetdataclear (NETDATA nd) { if (nd->ps 1= NULL) { free (nd->ps);

} if (nd->present-bdd

!=

NULL) { if (BDDREFCOUNT(nd->present-bdd) > 0) swjbdd free (&(nd->present-bdd));

}

} if (nd->nextbdd 1= NULL) { if (BDDREFCOUNT(nd->next-bdd) > 0) swbddfree (&(nd->next-bdd));

} free (nd); swnlist.C

#include "swswitching.h"

/*--------------------------------------------------------*

Function: swnlistadd

Desc: adds a netdata to {nl}

Pre: {*nl) is valid or NULL, {nd) is valid, {n) is valid and belongs to {nd}

{nd} is not yet in {nlist}

Post: {nd} is added to the head of (*nl}

*--------------------------------------------------------* void sw-nlist add (NLIST *nl, NETDATA nd, NET n) {

NLIST tnl;

// allocate space for new entry tnl = (NLIST) sw-malloc (sizeof (nlist), "nlist entry");

// initialize nlist item tnl->nd = nd; tnl->n = n; tnl->next = *nl;

}

// add it to list

*nl = tnl;

/*--------------------------------------------------------*

Function: swnlist-remove

Desc: removes a netdata item from the list

Pre: (nl) is valid or NULL, (nd} is valid,

{nd} occurs only once in {nlist}

Post: there are no instances of (nd} in (nl}

*--------------------------------------------------------* void sw-nlistremove (NLIST *nl, NETDATA nd) {

NLIST tnl, tnlparent;

// try to find it tnl = *nl; tnlparent = *nl; while (tnl 1= NULL && tnl->nd I= nd) { tnlparent = tnl; tnl = tnl->next; i

// if its not found

168

if (tnl == NULL)

{ return;

// if its at the head

} else if (tnl == tnlparent) {

*nl = (*nl)->next; free(tnl);

// its in the middle or at the end

} else { tnlparent->next = tnl->next; free(tnl);

}

}

// clear the netdata swnetdataset.keyword (NULL, nd->n); swnetdataclear(nd); free (nd);

/*--------------------------------------------------------*

Function: sw nlist clear

Desc: {nl)'s contents and {nl} is cleared

Pre: (nl} is valid or NULL

Post: {nl} is NULL and its contents are freed

*--------------------------------------------------------* void swnlist-clear (NLIST *nl)

{ while (*nl) { sw-nlist remove (nl, (*nl)->nd);

}

} sw_pidata.C

#include "swswitching.h"

/*--------------------------------------------------------*

Function: sw-pidata-get keyword

Desc: returns value of pidata keyword

Pre: (npin} valid and {n} is NULL or

{n} is valid and {npin} is NULL

Post: returns a valid keyword or NULL

*--------------------------------------------------------*

PIDATA swpidatagetkeyword (NETWORKPIN npin, NET n) {

PIDATA pd;

// if this is pidata for a npin if (npin != {

// if this npin is a proto pin if (isprotopin (npin, C)) { locatekeyword value ((PROTOPIN) npin, keyprotopidata,

&pd, C);

}

// else this is a usage pin

} else ( locatekeyword value ((USAGEPIN) npin, keyusagepidata,

&pd, C);

// this is pidata for a net

} else ( locatekeyword value (n, keynetpidata, &pd, C);

}

} return pd;

/*--------------------------------------------------------*

I Function: swpidata-set keyword

169

Desc:

Pre: sets value of pidata keyword

{npin) valid and (n) is NULL or

(n) is valid and {npin) is NULL

(pd} valid or NULL

Post: sets keyword to

{pd}

*--------------------------------------------------------* void swpidatasetkeyword (PIDATA pd, NETWORKPIN npin, NET n) {

// if this is pidata for a npin if (npin 1= NULL) {

// if this npin is a proto pin if (isprotopin (npin, C)) { set-keyword-value ((PROTOPIN) npin, keyprotopidata, pd, C);

//

} else this is a usage pin else { set keyword value ((USAGEPIN) npin, keyusagepidata, pd, C);

}

}

// this is pidata for a net

} else { set-keyword value (n, key-net-pidata, pd, C);

}

/*--------------------------------------------------------*

Function: sw-pidatadoes-exist

Desc: returns whether the pidata keyword of

Pre:

(npin} or (n} is NULL

(npin} valid and (n) is NULL or

Post:

(n} is valid and {npin) is NULL returns TRUE if a valid keyword exists or FALSE otherwise

*--------------------------------------------------------* bool sw-pidatadoesexist (NETWORKPIN npin, NET n) { return (swpidataget keyword (npin, n) 1= NULL);

}

/*--------------------------------------------------------*

Function: sw-pidata-get

Desc: returns pidata keyword of {npin} or (n},

Pre: initializes if necessary

(npin} valid and (n} is NULL or

Post:

(n) is valid and (npin} is NULL returns a valid pidata or a new pidata with present-varid and nextvarid = -1, prob data array = NULL, npin and n set accordingly, nummodes set to 0, and flags = 0

*--------------------------------------------------------*

PIDATA swpidataget (NETWORKPIN npin, NET n) {

PIDATA pd;

// try to get keyword pd = sw-pidataget-keyword (npin, n);

// return it if its not NULL if (pd 1= NULL) ( return pd;

}

// initialize pidata pd

=

(PIDATA) sw_malloc (sizeof (primaryinput data),

"pidata"); pd->presentvarid = -1; pd->nextvarid = -1;

170

pd->prob = NULL; pd->num_modes =

0; pd->npin = npin; pd->n = n; pd->flags = 0; swsetflag (&(pd->flags), BOTHNEEDSUPDATE, TRUE);

// set keyword swpidataset keyword (pd, npin, n);

// add pidata to list sw rotodataplistadd (pd);

} return pd;

/*--------------------------------------------------------*

Function: sw-pidata reset variable

Desc:

Pre:

Post: creates two new present/next state variables and stores the VARIDs into the pidata

(pd} is valid, bdd package has been init

{pd}->present-varid and ->next-varid are changed global-bddtable is changed

*--------------------------------------------------------* void swjpidataresetvariable (PIDATA pd) {

BDDPTR pbdd, nbdd;

// reset globalbddtable if necessary if (pd->presentvarid > -1) { swglobalbddtable_set (pd->presentvarid, NULL);

}

// set up new variables pbdd = bddcreatevar-lasto; nbdd = bdd-createvar-after(pbdd);

// group the two variables so that they

// will stay together during dynamic reordering bdd-merge-var-groups (BDDVARID (pbdd), BDDVARID (nbdd)); pd->presentvarid = BDDVARID (pbdd); pd->nextvarid = BDD_VARID (nbdd);

// update globalbddtable swglobal bddtableset (pd->presentvarid, pd); swglobal-bddtableset (pd->next-varid, pd);

}

/*--------------------------------------------------------*

Function: sw-pidata-set-prob

Desc: sets the p1 or halfps value for given mode for this pidata, reallocating the prob data array if necessary

Pre:

Post:

(pd} valid, (index) >= 0

{pd}->numk_modes = max ({pd}->num - modes, index) size of probdata array is {pd)->num-modes prob data array contains probs of -1 or valid probs

(pd}->prob[index]->plhalfps = plorhalfps

{pd}->prob[index]->pljps

*--------------------------------------------------------* defaultp = def_p void sw-pidata-setprob (PIDATA pd, float plorhalfps, bool defp, int index, int which-prob) { int i;

// allocate more probdata space if index >= if (index

>= pd->num-modes)

{ pd->num_modes

171

// do a malloc if prob data has never been initialized if (pd->prob == NULL) { pd->prob = (PROB_DATA *) sw-malloc

(sizeof (PROBDATA) * (index + 1), "probdata array");

} else { pd->prob = (PROBDATA *) swrealloc

(pd->prob, sizeof (PROBDATA) * (index + 1), "probdata array");

}

// initialize data for new probdata spaces for (i = pd->num modes; i < (index + 1); i++) { pd->prob[i] = (PROBDATA) sw-malloc

(sizeof (prob data), "a prob data element"); pd->prob[i]->pl = -1.0; pd->prob[i]->halfps = -1.0; pd->prob[i]->pldefaultp = TRUE; pd->prob[i]->ps-defaultp = TRUE;

}

}

// update num.modes

pd->nummodes = index + 1;

}

// set value for appropriate field depending on (whichprob} if (whichprob == PROB_Pl) { pd->prob[index]->pl = plorhalfps; pd->prob[index]->pldefaultp = defp;

} else { pd->prob[index]->halfps = plorhalfps; pd->prob[index]->ps defaultp = defp;

}

/*--------------------------------------------------------*

Function: sw-pidataclear

Desc:

Pre: clear (pd)'s contents and {pd}

{pd} is valid and not null

Post: all {pd) fields are freed

*--------------------------------------------------------* void sw-pidata-clear (PIDATA pd) { if (pd->present-varid > -1) { sw-globalbddtable set (pd->present-varid, NULL); sw-global-bddtable-set (pd->next-varid, NULL);

} free (pd->prob); free (pd);

/*--------------------------------------------------------*

Function: sw-pidatasetflag

Desc:

Pre: sets (pd}'s (mask) flag to (value)

(pd} is valid and not null

Post: sets (pd}->flag mask to value

*--------------------------------------------------------* void sw-pidatasetflag (PIDATA pd, int mask, int value) {

PROTODATA prd;

PROTOBOX pbox;

NET n; swsetflag (&(pd->flags), mask, value);

//

//

//

// if this is flagged for updating, queue net only if this is pidata for a net pin, because if its just for a cut net, then the pidata change should not affect the cut net if (swflag-setp (mask, ANYNEEDSUPDATE) && value

== TRUE

&& pd->npin I= NULL) (

172

// get net

if (isprotopin (pd->npin, C)) { n = get net-from_proto-pin ((PROTOPIN) pd->npin, C);

I else { n = getnetfromusage-pin ((USAGEPIN) pd->npin, C);

} pbox = swgetprotoboxfromnetworkpin (pd->npin);

// get protodata in order to queue net prd = swprotodataget (pbox);

}

// queue net sw-protodataqueue (prd, n, BDDCHG I LEVEL CHG);

} swplist.C

#include "sw_switching.h"

/*--------------------------------------------------------*

Function: sw-plist add

Desc: adds a pidata to {*pl)

Pre: (*pl} is valid or NULL, (pd} is valid,

(pd} is not yet in (plist}

Post: {pd) is added to the head of (*pl}

*--------------------------------------------------------* void swplistadd (PLIST *p1, PIDATA pd) {

PLIST tpl;

// allocate space for new entry tpl = (PLIST) sw-malloc (sizeof (plist), "plist entry");

// initialize plist item tpl->pd = pd; tpl->next =

*91;

}

// add it to list

*pl = tpl;

/*--------------------------------------------------------*

Function: sw-plist-remove

Desc: removes a pidata item from the list

Pre: (p1) is valid or NULL, {pd} is valid,

(pd} occurs only once in (plist)

Post: there are no instances of {pd} in (pl)

*--------------------------------------------------------* void swplist remove (PLIST *pl, PIDATA pd) {

PLIST tpl, tplparent;

// try to find it tpl = *91; tplparent = *91; while (tpl 1= NULL && tpl->pd 1= pd) { tplparent = tpl; tpl tpl->next;

}

// if its not found if (tpl == NULL)

{ return;

// if its at the head

} else if (tpl == tplparent) (

*pl = (*pl)->next; free(tpl);

173

// its in the middle or at the end

} else { tplparent->next = tpl->next; free(tpl);

}

}

// clear pidata swpidatasetkeyword (NULL, pd->npin, pd->n); swpidata clear(pd); free (pd);

/*--------------------------------------------------------*

Function: sw-plistclear

Desc: (pl}'s contents and (p1) is cleared

Pre: {pl} is valid or NULL

Post: (p1) is NULL and its contents are freed

*--------------------------------------------------------* void sw-plistclear (PLIST *pl) { while (*pl) { swplistremove (pl, (*pl)->pd);

}

} sw-protodata.C

#include "swswitching.h"

/*--------------------------------------------------------*

Function: sw-protodatadoesexist

Desc: returns whether or not protodata has ever been

Pre: created for {pbox}

{pbox} is valid

Post: returns TRUE if {pbox)'s keyprotodata is not

NULL, false otherwise

*--------------------------------------------------------* bool sw-protodatadoes-exist (PROTOBOX pbox) {

PROTODATA prd;

// try to get the keyword locatekeyword value (pbox, keyprotodata, &prd, C);

} return (prd 1= NULL);

/*--------------------------------------------------------*

Function: sw-protodata-get

Desc: get (pbox}ls protodata, initializing if necessary

Pre: (pbox} is valid or NULL

Post: on success, a valid prd is returned global-pbox-list is updated on error, returns NULL

*--------------------------------------------------------*

PROTODATA swprotodataget (PROTOBOX {

PROTODATA prd; if (pbox == NULL) ( printf ("Warning: no protodata because of null pbox.\n"); return NULL;

}

// try to get the keyword and return it if its not NULL locatekeyword-value (pbox, keyprotodata, &prd, C); if (prd I= NULL) { return prd; i

// initialize a new protodata

174

prd = (PROTODATA) sw-malloc (sizeof (protodata), "protodata"); prd->pbox = pbox; prd->qd = sw_queuedata-newo; prd->mode = NULL; prd->num-modes

=

0; prd->flags = 0; prd->plist = NULL; prd->nlist = NULL; prd->cp = NULL; prd->new netslist = NULL;

// set keyword set keyword-value (pbox, keyprotodata, prd, C);

// adds proto box to global pbox list that keeps

/I track of all current proto boxes

} return prd;

/*--------------------------------------------------------*

Function: sw-protodata-add-mode

Desc:

Pre:

Post: adds mode to protodata mode array

{prd} is valid, (mode} is valid on success, size of {prd}->mode is incremented

by one prd->num_modes is incremented by one all modes in the array are valid mode->index = prd->nummodes 1 global-maxnummodes is updated on error, no action

*--------------------------------------------------------* void swprotodataaddmode (PROTODATA prd, SW_MODE mode) { int i; if (mode == NULL) printf

{

("Warning: null return;

} mode not added.\n");

// set mode's index swmodeset-index (mode, prd->num-modes); if (prd->num_modes == 0) {

// create space for new mode prd->mode

=

(SWMODE *) sw-malloc (sizeof (SWMODE),

"protodata mode");

// insert new mode

} prd->mode[0] = mode; else (

// reallocate array to make roam for new mode prd->mode

=

(SWMODE *) sw-realloc

(prd->mode, sizeof (SWMODE)

*

(prd->num_modes

+

1),

"protodata modes");

}

// insert new mode prd->mode[prd->num-modes] = mode;

// update number of modes prd->num_modes++;

// update global number of modes swglobal maxnum_modes-update (prd->nummodes);

/*--------------------------------------------------------*

175

Function: swjprotodataset-flag

DeSc: sets protodata (mask} flag to (value}

Pre: {prd), (mask}, (mode} valid

Post: flag is set

*--------------------------------------------------------* void sw_protodataset-flag (PROTODATA prd, int mask, int value) { swsetflag (&(prd->flags), mask, value);

}

/*--------------------------------------------------------*

Function: sw-protodata queue

Desc: queues a net

Pre:

Post:

{prd) is valid, {n} is valid or NULL if netdata has data then n}'s netdata is flagged for {mask}, it may have been added to the queue if it was not yet in the queue otherwise, no action

*--------------------------------------------------------* void sw-protodata queue (PROTODATA prd, NET n, int mask) (

NETDATA nd;

I if (n == NULL) { return; nd = sw-netdata get(n);

// don't queue if there is no data if (!swnetdatahas data(nd)) { return;

}

// if net has not been queued for anything if (Isw flagsetp (nd->f (

}

// add it to the queue swqueuedataqueue (prd->qd, n, nd->level);

}

// set flags swnetdatasetflag (nd, mask, TRUE);

/*--------------------------------------------------------*

Function: sw-protodataqueue-outputs

Desc: queues output nets of usage box connected

Pre: to the sink pin of (n}

{prd}, {n) valid or NULL

Post: all outputs nets queued

*--------------------------------------------------------* void swprotodata_queue outputs (PROTODATA prd, NET n, int change_flag) (

NET n2;

QUEUE outcursor; if (n == NULL) { return;

)

// get cursor to traverse output nets outcursor = swoutput net-cursor(n);

// queue outputs for bdd recalculation while (out-cursor) { n2 = sw-outputnet(out cursor); sw_output net cursor-inc(&out_cursor); swprotodataqueue(prd, n2, change_flag);

} /* end for output net */

176

)

/*--------------------------------------------------------*

Function: sw-protodata dequeue

Desc: dequeues a net

Pre:

Post:

(prd} is valid if queue is empty, returns NULL otherwise, returns first minimum-levelled net and removes it from the queue

*--------------------------------------------------------*

NET swprotodata-dequeue (PROTODATA prd, int *flag) {

NETDATA nd;

NET n; if (sw-queuedataisempty (prd->qd)) { printf ("Warning: no queued item to dequeue.\n"); return NULL;

*flag = 0;

} else {

// get net n = swqueuedatadequeue(prd->qd);

// reset its flag nd = sw_netdata-get (n);

*flag = nd->flags; sw-netdata-set flag (nd, ANYCHG, FALSE);

}

} return n;

/*--------------------------------------------------------*

Function: sw-protodata-dequeuenet

Desc: dequeues a given net

Pre: (prd) is valid

Post: if {n) has been queued, it is removed from the queue otherwise, no action

*--------------------------------------------------------* void sw-protodata-dequeuenet (PROTODATA prd, NET n) {

NETDATA nd; nd = sw_netdataget (n);

//

// if net is queued, it is guaranteed to be located at nd->level, because the only way that nd->level

// would have changed is if the bdd calculator

// changed it, in which case it must have been

// queued before and dequeued after the change

// check whether its queued if (sw-flagsetp (nd->flags, ANYCHG)) {

}

// dequeue the net swqueuedata-dequeue-net (prd->qd, n, nd->level);

}

// reset the flag swnetdataset-flag (nd, ANYCHG, FALSE);

/*--------------------------------------------------------*

Function: sw-protodata-plist add

Desc: adds (pd) to appropriate protodata's plist

Pre:

Post:

{pd} is valid on success, pidata is added to appropriate protodata list on error, no action

*--------------------------------------------------------*

177

void swprotodataplistadd (PIDATA pd) {

PROTODATA prd;

PROTOBOX pbox;

// try to find protobox and protodata

// get protobox of network pin if (pd->npin 1= NULL) { pbox = swgetprotoboxfromnetwork-pin (pd->npin);

// get proto box of net

} else if (pd->n != { pbox = getparentproto boxfromnet (pd->n, C);

// error

} else { printf return;

("Warning: no data objects for pidata.\n");

}

} prd = swprotodataget (pbox); swplistadd (&(prd->plist), pd);

/*--------------------------------------------------------*

Function: sw-protodatanlist-add

Desc:

Pre: adds {nd} to appropriate protodata's plist

(nd), {n} is valid

Post: on success, netdata is added to appropriate protodata list on error, no action

*--------------------------------------------------------* void sw-protodatanlist add (NETDATA nd, NET n) {

PROTODATA prd;

PROTOBOX pbox;

// try to find protobox and protodata

// get protobox of net pbox

= getparentproto boxfrom_net (n, C);

} prd = swprotodataget (pbox); swnlistadd (&(prd->nlist), nd, n);

/*--------------------------------------------------------*

Function: sw-protodatanew nets-listadd

Desc: adds {n} to protodata's new nets list

Pre: (n}, fprd) is valid

Post: on success, new net is added to (prd) new nets list on error, no action

*--------------------------------------------------------* void sw-protodatanewnetslistadd (PROTODATA prd, NET n) {

QUEUE n1 = prd->newnetslist;

// make sure net is not yet in the new net list while (nl) { if (nl->qnet == n) return;

{

} n1 = nl->next;

}

// allocate space for new item nl = (QUEUE) swmalloc (sizeof (queue), "new net list item");

// initialize new item nl->clnet = n;

178

nl->next = prd->new-nets list;

}

// add item to list prd->newnets_list = ni;

/*--------------------------------------------------------*

Function: sw-protodatanewnetslistclear

Desc: clears all items on {prd)'s new nets list

Pre:

{prd} is valid

Post: prd->newnetslist

*--------------------------------------------------------*

= NULL void swprotodatanewnets_list_clear (PROTODATA prd) f

QUEUE nl; while (prd->newnetslist) { nl = prd->newnets_list; prd->new netslist = nl->next;

}

} free(nl);

/*--------------------------------------------------------*

Function: sw-protodatapidataupdate

Desc: updates pidata by either setting the right

Pre: defaults or calculating the right probs

(prd} valid, {pd} initialized

Post: (pd} is correct

*--------------------------------------------------------* void swprotodatapidata update (PROTODATA prd, PIDATA pd) { int i;

NETDATA nd; float *pl, *ps;

BDDPTR switchbdd; bool samep = TRUE;

// if this is not a cut net if (pd->npin 1= NULL) { if (pd->num modes < prd->num.-modes) { swpidatasetprob (pd, -1, TRUE, prd->nummodes

1,

PROBPl);

}

// update defaults for (i = 0; i < prd->nummodes; i++) { if (pd->prob[i]->pldefaultp) ( swpidata-set-prob (pd, prd->mode[i]->pl,

TRUE, i, PROBPl);

} if (pd->prob[i]->ps-defaultp) { swpidata-set-prob (pd, prd->mode[ i]

TRUE, i, PROBPS);

}

//

} get and transfer probabilities else {

// get the netdata of this pidata's net nd = swnetdataget (pd->n);

// calculate the probability switchbdd = bddxor (nd->present-bdd, nd->nextbdd); ps = sw-calcprob (switchbdd, prd->num modes); pl

= sw-calcprob (nd->present-bdd,

179

prd->numnmodes); swbddfree (&switchbdd);

}

// copy it over for (i = prd->numrModes 1; i >= 0; i--) { swpidatasetprob (pd, pi[i] OFFSET, FALSE, i, PROBP1); sw-pidataset-prob (pd, (ps[i] OFFSET)/2.0, FALSE, i, PROBPS);

}

// reset the variable because information has changed swpidataresetvariable (pd);

// reset flag swpidataset flag (pd, -0, FALSE);

}

/*--------------------------------------------------------*

Function: sw-protodata-pidata-flag-defaults

Desc: flag pidata whose defaults depend on the

Pre:

Post: given mode for needing updates

{prd} valid, {m} is valid all pidata that is on (prd}->plist that uses {m}'s default is flagged for needing an update

*--------------------------------------------------------* void sw_protodatapidataflagdefaults (PROTODATA prd,

SWMODE m) {

PLIST p1; pl

= prd->plist; while (pl) {

}

}

// if number of modes is less than or equal to

// mode index, pidata flag should already be set

// to be needing update if (pl->pd->num.modes > m->index) { if (pl->pd->prob[m->index]->pldefault-p) swpidatasetflag (pl->pd, ONENEEDSUPDATE, TRUE); if (pl->pd->problm->index]->ps-default-p) swpidatasetflag (pl->pd, SWITCHNEEDSUPDATE, TRUE);

} pl

= pl->next;

/*--------------------------------------------------------*

Function: sw-protodataclear

Desc: clears all protodata

Pre: (prd} valid

*--------------------------------------------------------* void sw-protodataclear (PROTODATA prd) { int i;

SWCHECKPOINT cp;

// clear all the modes for (i = 0; i < prd->nummodes; i++) ( free (prd->mode[i]);

}

// clear the plist, and all its pidata swplist-clear(&rd->plist);

// clear the nlist, and all its netdata swnlist-clear (&prd->nlist);

// clear the queuedata swqueuedataclear (prd->qd);

180

// clear the checkpoint while (prd->cp 1= NULL) { cp = prd->cp; sw clear checkpoint (&cp);

}

// clear the new nets list swprotodatanewnetslist_clear (prd);

} set-keyword value (prd->pbox, keyprotodata, NULL, C); swqueue.C

#include "swswitching.h"

/*--------------------------------------------------------*

Function: swqueuedata_new

Desc:

Post: returns an initialized queuedata returns a queuedata structure with a

NULL-filled queuelist array of size (INIT_LEVEL_SIZE} and maxlevel = 0, minlevel = maxalloc, and maxalloc = INITLEVELSIZE

*--------------------------------------------------------*

QUEUEDATA sw_queuedata-new(void) {

QUEUEDATA qd; int i;

// allocate queuedata memory qd = (QUEUEDATA) sw-malloc (sizeof (queuedata), "queuedata");

// allocate queuedata list memory qd->list = (QUEUE *) sw-malloc (sizeof (queue) * INITLEVELSIZE,

"queuedata list");

// fill array for (i = 0; i qd->list[i] with NULLs

< INITLEVELSIZE; i++)

(

= NULL; qd->maxalloc qd->minlevel qd->max-level

= INITLEVELSIZE;

=

= qd->max-alloc;

0; return qd;

}

/*--------------------------------------------------------*

Function: swqueuedataqueue

Desc: adds a net to the queue

Pre: (qd}, {n} is valid and has data, (n) not already

Post: queued on success, n is added to head of queue list at index (level) if qd->maxalloc <= (level), size of qd->list

=

(level) + 10 and qd->max-alloc = (level) + 10 qd->min-level = min(level, qd->minlevel)

qd->max level

= max(level, qd->maxlevel) all queue list items are either null or valid on error, no action

*--------------------------------------------------------* void swqueuedataqueue (QUEUEDATA qd, NET a, int level) {

QUEUE q; int i; if (level < 0) { printf ("Warning: cannot queue net at negative position.\n"); return;

181

} else if (level >= qd->max-alloc) (

// reallocate space in list qd->list = (QUEUE *) sw-realloc

(qd->list, sizeof (QUEUE) * (level + 10), "queuedata list reallocation");

}

// fill new list items with null for (i = qd->max-alloc; i < level + 10; i++) { qd->list[i] = NULL;

// if current minimum is equal to the max allocated,

// update it if (qd->min level == qd->max-alloc) { qd->minlevel = level + 10;

}

// update queue list size qd->maxalloc = level + 10;

};

// allocate space for new queue item q

=

(QUEUE) sw-malloc (sizeof (queue), "queue item");

// set up queue q->qnet = n; q->next = qd->list[level];

// add to queue list qd->list[level] = q;

// update min/max if (level < qd->min level) { qd->minlevel = level;

}

} if (level > qd->max level) { qd->maxlevel = level;

}

/*--------------------------------------------------------*

Function: sw_queuedata-updateminmax

Desc:

Pre:

Post: updates correct minimum and maximum level values procedure is only called from a dequeue

(qd} is valid and non-empty

(qd}->minlevel and maxlevel were correct before the dequeue if queue not empty, minlevel = minimum level of all nets on queue, max-level = maximum level of all nets on queue if queue is empty, minlevel

= qd->max-alloc, max-level =

0

*--------------------------------------------------------* void swqueuedata_update minmax (QUEUEDATA qd) {

// if the maximum level queue is empty,

// then all queues are empty if (qd->list[qd->max-level] == NULL) { qd->max_level

=

0; qd->minlevel = qd->max-alloc;

} else (

// increment the minimum level number (if necessary)

// until it reaches a level that has a non-empty queue while (qd->list[qd->min level] == NULL && qd->min-level < qd->maxlevel) { qd->min-level++;

}

}

182

}

/*--------------------------------------------------------*

Function: sw-queuedata-dequeue

Desc: removes and returns the first net on the minimum levelled-list calls:

Pre:

Post: swqueuedataupdate-minmax

(qd} is valid and non-empty first net removed all queue list items are NULL or valid

*--------------------------------------------------------*

NET swqueuedatadequeue (QUEUEDATA qd) {

QUEUE delq;

NET delnet;

// obtain top queue item delq = qd->list[qd->min_level];

// update queue list structure qd->list[qd->minlevel] = delq->next;

// get net delnet = delq->qnet;

// free queue item free(delq);

// update min and max values swqueuedataupdate-minmax(qd);

}

// return net return delnet;

/*--------------------------------------------------------*

Function: swqueuedataisempty

Desc:

Pre:

Post: returns whether any items are queued

(qd} is valid returns TRUE if there are any items on queue, false otherwise

*--------------------------------------------------------* bool swqueuedata_is_empty (QUEUEDATA qd) { return (qd->minlevel == qd->max-alloc);

)

/*--------------------------------------------------------*

Function: sw-queuedata-dequeue_net

Desc: removes and returns the given net on the

Calls:

Pre: queue list swqueuedataupdateminmax

(qd}, {n) is valid, (n) is either on

Post: qd->list[levelJ or not on any other list index on success, given net removed from queue all queue list items are NULL or valid on error, no action

*--------------------------------------------------------* void swqueuedata_dequeuenet (QUEUEDATA qd, NET n, int level) {

QUEUE delq, delparent;

NET delnet;

// invalid level number if (level

<

0 11 level

> qd->max-alloc) { printf ("Warning: invalid level for dequeueing net.\n"); return;

// try to find queued net delparent = qd->list[level]; delq = qd->list[level]; while (delq I= NULL && delq->qnet I= n) {

183

} delparent = delq; delq

= delq->next;

} if (delq == NULL) {

printf ("Warning: net not found on level %d\n", level); return;

// update queue list structure if (delparent == delq) { qd->list[level] = delq->next;

} else { delparent->next = delq->next;

}

// free queue item free(delq);

}

// update min and max values swqueuedata-update-minmax (qd);

/*--------------------------------------------------------*

Function: sw-queuedata-clear

Desc: clear {qd)'s contents and {qd}

Pre: {qd} is valid and not NULL

Post: all {qd} fields are freed

*--------------------------------------------------------* void swqueuedata clear (QUEUEDATA qd) { int i; while (1sw_queuedata-isempty(qd)) swqueuedata_dequeue (qd); f free (qd->list); free (qd);

} switchingdll.C

#include "vim.h"

#include "idm.h"

#include "/afs/eda/dev/nutshell/3.0/include/Ci.h"

#include "/afs/eda/dev/nutshell/3.0/include/String.h"

#include "/afs/eda/dev/idm/16/include/IDM.h'

#include "sw switching.h"

#define CSTR( s ) ( (char *) (s).cstr()

//------------------------------------------------------------------------------

// Ci types

//-----------------------------------------------------------------------------static CiType PROTOBOX citype; static CiType DEFBOX-citype; static CiType NET citype; static CiType NETWORKPIN-citype; static CiType SWMODE citype; static CiType SWCHECKPOINT_citype; static CiType SWCHANGECURSOR-citype;

//------------------------------------------------------------------------------

// Ci bindings

//-----------------------------------------------------------------------------static void cmdswdefine_mode( CiCommand* amd)

{

PROTOBOX string pbox; name; const CiCoxmmandArg args[] = (

184

{ "proto box",

{ "name",

NULL

&pbox,

&name,

PROTOBOXcitype, CIREQ

),

CISTRING, CIREQ },

} if( cmd->parseArgs( args ) ) {

SWMODE m; swdefine mode (pbox, (char *) name.c_stro, &m); cmd->setReturnValue( (void*) m, SWMODEcitype ); i static void cmd_sw_set_default_oneprob(

CiCommnand* cnid)

{

SWMODE m; string name; double f; const CiCommandArg

{ "mode", &m,

{ "prob", &f,

NULL

}; args [] = {

SWMODEcitype, CIREQ },

CIDOUBLE, CIREQ

),

} if( cmd->parseArgs( args ) ) { swsetdefault_one-prob(m, f);

} static

{ void cmdswsetswitch-prob(

SWMODE m;

CiConunand*

NETWORKPIN n; double f; const CiConunandArg args[] = {

( "mode", &m, SWMODEcitype, CIREQ }, cmd)

{ "netpin", &n, NETWORKPINcitype,

( "prob", &f, CIDOUBLE, CIREQ ),

CIREQ },

NULL

} if( cmd->parseArgs( args

) ) { swsetswitchprob(m, n, f);

} static void cmdswsetone-prob( CiComumand*

{

SWMODE m;

NETWORKPIN n; double f; cmd) const CiCounandArg args[] = {

{ "mode", &m, SWMODEcitype, CIREQ },

{ "netpin", &n, NETWORKPINcitype, CIREQ },

{ "prob", &f, CIDOUBLE, CIREQ ),

NULL

};

} if( cmd->parseArgs( args ) ) { sw_setoneprob(m, n, f); i static void cmd_Sw_Bet_default_switch~prob(

CiCoimand* cm)

{

SWMODE m; double f; const CiCommandArg

{ "mode", &m,

{ "prob", &f, args[] = {

SWMODEcitype, CIREQ },

CIDOUBLE, CIREQ ),

NULL

185

} if( cmd->parseArgs( args ) ) { swsetdefaultswitch-prob(m, f);

} static void

{ cmdsw-registercallbacks( const CiCommandArg args[] = {

CiCommand* cmd)

NULL

} if( cmd->parseArgs( args ) ) { swregistercallbacks (;

} static void cmd_swunregistercallbacks( CiConmand* cmd)

{ const CiConmandArg args[] =

(

NULL

} if( cmd->parseArgs( args ) ) { swunregister-callbacks );

} static void cmdsw_net switchprob( CiCommand* cmd)

{

SWMODE m;

NET n; const CiCommandArg args[] = {

{ "mode",

{ "net",

NULL

&m,

SWMODE-citype,

&n,NETcitype, CIREQ },

};

CIREQ }, if( cmd->parseArgs( args ) ) { float d;

}

} swnet switch-prob (m, n, &d); cmd->setReturnValue( d ); static void cmd_swnet-oneprob( CiCommand* cmd)

{

SWMODE m;

NET n; const CiConmandArg args [] = {

{ "mde",

{ "net",

NULL

&m, SWMODEcitype,

&n,NETcitype, CIREQ },

I; if( cmd->parseArgs( args ) ) { float d;

}

} swnet one-prob (m, n, &d); cmd->setReturnValue( d ); static void cmd_swfirstmode( CiConmand* cmd)

{

SW_MDDE m;

PROTOBOX pbox;

CIREQ

),

186

const CiCommandArg args [] = {

{ "proto box", &pbox,

NULL

};

PROTOBOXcitype, CIREQ },

} if( cmd->parseArgs( args ) ) { swfirst_mode (pbox, &m); cmd->setReturnValue( (void*) m, SWMODE-citype );

} static void cmdswnext mode( CiConmand*

{

SWMODE m, n; const CiCommandArg args[] = {

{ "mode", &M,

NULL cmd)

SWMODE_citype,

};

CI-REQ }, if( cmd->parseArgs( args ) ) { swnext_mode

(m,

&n); cmd->setReturnValue( (void*) n, SWMODE citype

} static void cmdswset_checkpoint( CiCommand* cmd)

{

PROTOBOX pbox;

SWCHECKPOINT cp; const CiCommandArg args[] = {

{ "proto box", &pbox,

NULL

PROTOBOXcitype, CIREQ },

} if( cmd->parseArgs( args ) ) ( swsetcheckpoint (pbox, &cp); cmd->setReturnValue( (void *) cp, SWCHECKPOINT-citype );

} static void

{ cmd-sw-clear-checkpoint(

SW_CHECKPOINT cp;

CiCommand* cmd) const CiCommnandArg args[] = {

{ "checkpoint", &cp,

NULL

I;

SWCHECKPOINT_citype,

} if( cmd->parseArgs( args ) ) { swclearcheckpoint (&cp);

} static void

{ cmd_swclear data( CiCozmmand* amd) const CiCoumandArg args[]

= {

NULL

};

} if( cmd->parseArgs( args ) ) { swcleardata 0;

} static void cmd_ swgetchange-cursor ( CiCommand* cmd)

{

SWCHECKPOINT cp;

SWMODE m;

CIREQ },

187

SWCHANGECURSOR cc; const CiCommandArg args[] = {

{ "checkpoint", &cp,

( "node",

&M,

NULL

};

SWCHECKPOINTcitype,

SWMODEcitype, CIREQ },

} if( cmd->parseArgs( args ) ) { swget-changecursor (cp, m, &cc); cmd->setReturnValue( (void *) cc, SWCHANGECURSOR_citype);

} static void cmdsw_getchangeinfo ( CiConmand* cmd)

{

SW-CHANGECURSOR cc;

NET n; float p1, dpi, ps, dps; char *rem; const CiConmmandArg args[] = {

{ "changecursor", &cc,

NULL

SWCHANGECURSORcitype,

CIREQ ),

CIREQ },

} if( cmd->parseArgs( args ) ) { swgetchangeinfo(cc, &n, &pl, &dpl, &ps, &dps); if (in->isdeletedo) { printf ("Change info: %s\tpl: %f\tdpl:%f\tps: %f\tdps: %f\n", netname(n, C), p1, dpi, ps, dps);

} else { printf ("Change info: %s deleted \tpl: %f\tdpl:%f\tps: %f\tdps: %f\n", netname(n, C), pl, dpi, ps, dps);

}

} static void cmdswinc-changecursor ( CiComand* cmd)

{

SWCHANGECURSOR cc; bool eol; const CiCommandArg args[] = {

{ "changecursor", &cc,

NULL

SWCHANGECURSORcitype, CIREQ ),

} if( cmd->parseArgs( args ) ) { sw_incchangecursor (&cc, &eol); cmd->setReturnValue( (void *) cc, SWCHANGECURSORcitype);

} amd) d double size; const CiConmandArg args[] = {

{ "size",

NULL

&size,

};

CIDOUBLE, CIREQ

}, if( cmd->parseArgs( args ) ) (

}

} global_sizethreshold = (int) size; static void cmdswtestlevel( CiCommand* cmd)

188

{

NET n; const CiCommandArg args[] = {

{ "net", &n, NET-citype, CIREQ },

NULL if( cmd->parseArgs( args ) ) { if (n {

}

}

} else { cmd->setReturnValue( -10 );

} static void

{ cmd-sw-toggle-undelete( const CiCounandArg args[]

=

{

CiComand* cmd)

};

NULL

);

} if( cmd->parseArgs( args ) ) {

IDMRESOURCES::undelete-mode =

}

1IDMRESOURCES::undelete-mode; static const CiComnmandEntry

{"swdefine mode", cmds[ = { cmdswdefinemode, "Performs switching factor analysis"),

("swsetdefaultswitch-prob", cmdswsetdefaultswitchprob, "P"),

("swsetdefaultone-prob", cmd_sw_setdefaultone-prob, "P"},

{"swsetone-prob", cmdswset_oneprob, "P"),

{"sw_set_switchprob", cmd sw setswitchprob, "P"),

{"sw-first mode", cmd_swfirst_mode,

"P"),

{"swnextmode", cmd-swnextmode,

"P"},

("sw net-switchjprob", cmd-sw-net_switchprob, "P"}I,

{"sw_netoneprob", cmdswnet_oneprob, "P"),

("5sw_set_checkpoint", cmd_swset-checkpoint, "P"}),

("sw_clearcheckpoint", cmd-sw-clear_checkpoint, "P"I),

("swget-change-cursor", cmd_swget-change cursor, "P"),

{ "swincchangecursor", cmdsw-incchange cursor, "P" } ,

{ "P"),

{"sw-register_callbacks", cmdsw-register_callbacks, "P"}I,

{"sw-unregister_callbacks", cmd_sw-unregister_callbacks, "P"),

("sw_cleardata", cmd_swcleardata, "P"),

{"swset sizethreshold", cmd-swsetsizethreshold, "P"),

};

{"sw_test_level", cmdswtest_level,

"P"),

("sw-toggleundelete", cmd_sw-toggle-undelete, "P"I),

0

//

/------------------------------------------------------------------------------

Ci initialize and terminate

//-----------------------------------------------------------------------------extern "C"

CiStatus switchingci-init ()

{

Ci *ci = Ci::getInterpo;

PROTOBOXcitype = ci->getUserType ( "PROTOBOX" )

-> type (;

DEFBOXcitype

= ci->getUserType ( "DEFBOX" ) -> type (;

NET citype = ci->getUserType ( "NET" )

-> type ();

189

NETWORKPIN citype = ci->getUserType ( "NETWORKPIN" ) -> type (;

SWMODEcitype = ci->getUserType ( "SW MODE" ) -> type ();

SWCHECKPOINTcitype

SWCHANGE_CURSORcitype

= ci->getUserType ( "SWCHECKPOINT" ) -> type );

= ci->getUserType ( "SW_CHANGECURSOR" )

-> type );

CiModule *mod = ci->getModule( "Sw", 0, "sw" ); mod->registerCommand( cmds

); bdduse negedges

=

0; bdddodynamicordering = 1;

C = get contexto; // from IDM dll

// enable undeletion

IDMRESOURCES::undelete_mode = 1; global_init-p = FALSE; global-max-num_modes = 0; global-bddtablesize = 0; global bddtable = NULL; globalpblist = NULL; global sizethreshold = 1000;

// create keywords

// a key for the proto pin primary input data key-protopidata = locateorcreate keyword def (CLASPROTOPIN, "keyprotopidata",

VARTYPEUNKNOWN, C); set keyworddefault value(keyproto-pidata, NULL, C);

// a key for the usage pin primary input data key-usagepidata = locateorcreate-keyword-def (CLASPROTOPIN, "keyusagepidata",

VARTYPEUNKNOWN, C);

// a key for the net primary input data keynetpidata = locateorcreate-keyword-def (CLASNET, "keynetpidata",

VARTYPEUNKNOWN, C); set-keyword-default-value(keynet-pidata, NULL, C);

// a key for the net data keynetdata = locateorcreate-keyword-def (CLASNET, "keynetdata",

VARTYPEUNKNOWN, C); setjkeyword-default-value(keynetdata, NULL, C);

// a key for the net checkpoint id keycheckpoint-id = locateorcreate-keyword-def (CLASNET, "keycheckpoint_id",

VARTYPEINTEGER, C); setkeyword-default-value(keycheckpointid, -1, C);

// a key for the a substitution net keysubnet = locateorcreate-keyword-def (CLASNET, "keysubnet",

VARTYPEUNKNOWN, C); set keyword default value(keysubnet, NULL, C);

// a key for the proto data keyprotodata = locate or-create-keyword-def (CLAS_PROTOBOX, "keyprotodata",

VARTYPEUNKNOWN, C); set keyword-default value(key-protodata, NULL, C); return CIOK;

} extern "C"

190

CiStatus switching_ci-term ()

{ return CIOK;

} swswitching.h

#ifndef

SWSWITCHING_H

#define SWSWITCHINGH

/*--------------------------------------------------------*

Include files

*--------------------------------------------------------*

#include <errno.h>

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <math.h>

#include

"ltype.h"

#include "vim.h"

#include "pi2.h"

#include

"synutils.h"

#include "synpi.h"

#include

"bdextern.h"

#include "tibfunction.h"

#include "IDM.h"

#include

"/afs/eda/prod/bdd/3.0/include/bdd.h"

#include "switching.h"

/*--------------------------------------------------------*

Definitions

*--------------------------------------------------------*

// bit definitions for netdata flags

// marks whether a bdd change, etc. is queued

#define NOCHG Ox0

#define

BDDCHG Ox1

#define

LEVELCHG

0x2

#define

PROBCHG

Ox4

#define ANYCHG (BDDCHG I LEVELCHG PROBCHG)

#define INCURSOR

0x8

#define

INCHECKPOINTLIST OxlO

// bit definitions for protodata flags

# define INITREADYP

0x2

# define ALLNETSCALCP

0x4

// bit definitions for pidata flags

# define ONENEEDSUPDATE Oxi

# define SWITCHNEEDS_UPDATE

0x2

# define BOTHNEEDSUPDATE (ONENEEDSUPDATE SWITCHNEEDSUPDATE)

# define ANYNEEDSUPDATE (ONENEEDSUPDATE SWITCHNEEDSUPDATE)

#define ANYFLAG (-0)

#define INITBDDSIZE 500

#define

INITLEVELSIZE 30

#define PROBP1 0

#define

PROBPS 1

//

//

bdd user data probability values are offset

by this amount to indicate that

// they have been calculated

#define OFFSET 1.0

/*--------------------------------------------------------*

Data structures

*--------------------------------------------------------*

191

struct netdata (

BDDPTR present-bdd;

BDDPTR next bdd; float *ps; int level; int flags;

NET n;

// switching probability of net

// 3 bits used: BDD_CHG, LEVELCHG, PROBCHG typedef struct netdata *NETDATA;

// helper structure struct prob data { float float p1; halfps; bool pldefaultp; bool ps-default-p;

}; for primary input data

// state probability

// switching probability / 2 typedef struct probdata *PROBDATA; struct primary-input data { int presentvarid; int next-varid; int numn modes; int flags;

PROBDATA *prob;

NETWORKPIN npin;

NET n;

/ / either npin will have data

/ / or n will, not both typedef struct primaryinput data *PIDATA; struct queue {

NET qnet; struct queue *next; typedef struct queue *QUEUE; struct queuedata { int min level; int max level; int max-alloc;

QUEUTE *list; typedef struct queuedata *QUEUEDATA; struct protodata; struct sw mode

{ char *name; int index; float p1; float halfps;

PROTOBOX pbox; struct protodata *prd;

// default state probability

// default switching probability/2

// protodata struct plist {

PIDATA pd; struct plist *next; typedef struct plist *PLIST; struct nlist {

NETDATA nd;

NET n;

192

struct nlist *next; typedef struct nlist *NLIST; struct protodata {

PROTOBOX pbox; struct queuedata *qd;

SWMODE *mode; int num_modes; int flags;

PLIST plist;

NLIST nlist;

SWCHECKPOINT cp;

QUEUE new nets list;

// list of all initialized pi keywords

// list of all initialized net keywords

// points to the most recent of the

// checkpoint list

// list of all nets created while

// there was no checkpoint

}; typedef struct protodata *PROTODATA; struct protobox list {

PROTOBOX pbox; struct protoboxlist *next;

}; typedef struct protoboxlist *PBOXLIST; struct swcheckpointitem { float *pl; float *ps;

NET n; struct swcheckpoint item *next;

1; typedef struct swcheckpoint-item *SWCP_ITEM; struct swcheckpoint {

SWCPITEM item;

PROTOBOX pbox; int id; struct swcheckpoint *prev; struct swcheckpoint *next;

1; typedef struct swcheckpoint *SWCHECKPOINT; struct swchangecursor

NET n; float p1;

{ float ps; float deltapl; float deltaps; struct swchangecursor *next; typedef struct sw-change_cursor *SW_CHANGECURSOR;

/*--------------------------------------------------------*

Global variables

*--------------------------------------------------------*

CONTEXT C;

KEYWORDDEF keynetdata;

KEYWORDDEF key netpidata;

KEYWORDDEF keyproto-pidata;

KEYWORDDEF key usagepidata;

KEYWORDDEF keyaprotodata;

KEYWORDDEF key checkpointid;

KEYWORDDEF key checkpointnetdelete;

KEYWORDDEF key checkpoint_net_create;

193

KEYWORDDEF key-subnet; bool global init-p; int globalmaxnum_modes; int globalbddtable-size;

PIDATA *globalbddtable; int globalsizethreshold;

PBOXLIST global-pblist;

/*--------------------------------------------------------*

External procedures

*--------------------------------------------------------* extern "C" int bldeqn(void); extern "C" int newgen(void); extern "C" void BDsynset currentproto box (PROTOBOX);

/*--------------------------------------------------------* sw-aux

*--------------------------------------------------------* void swbdd free (BDDPTR *); bool swflagsetp (int flag, int mask); bool swsetflag (int *flag, int mask, bool value); void *swmalloc (int size, char datastring[]); void *swrealloc (void *old_data, int size, char datastring[]);

PROTOBOX swgetprotobox_fromnetworkpin (NETWORKPIN npin); bool swfloatequals (float fl, float f2);

/*--------------------------------------------------------* sw-calc

*--------------------------------------------------------* float *sw-calc-prob(BDDPTR f, int total); void swcalctraverseentire_queue (PROTODATA prd);

/*--------------------------------------------------------* sw-callback

*--------------------------------------------------------* void sw register callbacks (); void sw_unregister-callbacks ();

/*--------------------------------------------------------*

| sw-checkpoint

*--------------------------------------------------------* bool swcheckpoint addcreated net (NET n); bool swcheckpoint add-changed-net (NET n, BDDPTR oldbdd);

/*--------------------------------------------------------* sw-cursor

*--------------------------------------------------------*

QUEUE sw output net cursor (NET in); bool swoutput-net-cursorinc(QUEUE *cursor, bool *cursor-null_p); bool swoutput net cursorinc(QUEUE *cursor);

QUEUE sw input netcursor (NET out);

NET swinput net(QUEUE cursor); bool swinput-net-cursorinc(QUEUE *cursor, bool *cursor-nullp); bool swinput netcursorinc(QUEUE *cursor);

/*--------------------------------------------------------* swglobal

*--------------------------------------------------------* bool swglobalbddtableset (nt index, PIDATA pd);

PIDATA swglobal bddtableget (int index); void sw-global-pblist-add (PROTOBOX pbox); void sw-globalmaxnummodesupdate (int value); void sw-global-pblist-remove (PROTOBOX pbox);

194

sw_init

*--------------------------------------------------------* void swinitone-time ();

/*--------------------------------------------------------* swmode

*--------------------------------------------------------*

SW_MODE swmode new (char *name, PROTODATA prd); void sw modesetpl (SW_MODE mode, float p1); void swmode set halfps (SWMODE mode, float halfps); void swmode setindex (SWMODE mode, int index); void sw mode-clear (SW-MODE mode);

/*--------------------------------------------------------* sw-netdata

*--------------------------------------------------------* bool sw-netdatahas_data (NETDATA nd);

NETDATA sw_netdata get (NET n); void swnetdata-setpresent-bdd(NETDATA nd, BDDPTR pbdd); void sw-netdatasetlevel(NETDATA nd, int level); void swnetdata set-ps(NETDATA nd, float *ps, int numnmodes); void sw-netdatasetflag (NETDATA nd, int mask, int value); void swnetdata clear (NETDATA nd); void sw-netdatasetkeyword (NETDATA nd, NET n);

/*--------------------------------------------------------* swnlist

*--------------------------------------------------------* void swrnlist add (NLIST *nl, NETDATA nd, NET n); void swnlist remove (NLIST *nl, NETDATA nd); void swnlist clear (NLIST *nl);

/*--------------------------------------------------------* swpidata

*--------------------------------------------------------* bool swpidatadoesexist (NETWORKPIN npin, NET n);

PIDATA swpidataget (NETWORKPIN npin, NET n); void sw-pidata-reset-variable (PIDATA pd); void swpidatasetprob (PIDATA pd, float value, bool def-p, int index, int whichprob); void sw-pidata-clear (PIDATA pd); void swpidata set flag (PIDATA pd, int mask, int value); void sw-pidata-set keyword (PIDATA pd, NETWORKPIN npin, NET n);

/*--------------------------------------------------------* sw-plist

*--------------------------------------------------------* void swplist-add (PLIST *pl, PIDATA pd); void sw-plist remove (PLIST *pl, PIDATA pd); void sw-plist clear (PLIST *pl);

/*--------------------------------------------------------* swprotodata

*--------------------------------------------------------*

PROTODATA swprotodataget (PROTOBOX pbox); void swprotodataadd_mode (PROTODATA prd, SWMODE mode); void swvprotodataset_flag (PROTODATA prd, int mask, int value); void sw-protodataqueue (PROTODATA prd, NET n, int mask); void sw-protodataqueue outputs (PROTODATA prd, NET n, int changeflag);

NET sw-protodata-dequeue (PROTODATA prd, int *flag); void swvprotodata dequeue net (PROTODATA prd, NET n); void sw-protodataplist_add (PIDATA pd); void swprotodatanlist add (NETDATA nd, NET n); void sw-protodata-pidataupdate (PROTODATA prd, PIDATA pd); void sw-protodatapidataflagdefaults (PROTODATA prd,

SWMODE m); void swprotodatanew_netslistadd (PROTODATA prd, NET n);

195

void sw-protodatanewnetslist clear (PROTODATA prd); void sw-protodataclear (PROTODATA prd);

/*--------------------------------------------------------*

| swqueuedata

*--------------------------------------------------------*

QUEUEDATA swqueuedatanew(void); void swqueuedataqueue (QUEUEDATA qd, NET n, int level);

NET swqueuedatadequeue (QUEUEDATA qd); bool sw-queuedatais-empty (QUEUEDATA qd); void swcqueuedatadequeuenet (QUEUEDATA qd, NET n, int level); void swqueuedataclear (QUEUEDATA qd);

#endif /* SWSWITCHINGH */ switching.h

#ifndef SWITCHING_H

#define SWITCHING_H typedef unsigned char bool; struct sw-mode; typedef struct swmode *SWMODE; struct sw-change_cursor; typedef struct swchangecursor *SWCHANGECURSOR; struct sw checkpoint; typedef struct swcheckpoint *SWCHECKPOINT;

/*--------------------------------------------------------* each function returns a boolean value indicating whether or not an error has occurred

*--------------------------------------------------------*

/*--------------------------------------------------------* allows a user to specify different modes for calculating transition probabilities, i.e. idle mode, on

...

main difference between each mode is the user-specified

I probabilities at the primary inputs

*--------------------------------------------------------* extern bool sw-define-mode (PROTOBOX pbox, char *name, SWMODE *return-mode);

/*--------------------------------------------------------* these two functions allow the user to retrieve the switching probability and state probability at a net

*--------------------------------------------------------* extern bool swnet_switchprob (SWMODE m, NET n, float *returnprob);

/*--------------------------------------------------------*

| these two functions allow the user to set and clear checkpoints, which specify a time instance to begin logging structural and probability changes to the circuit

*------------------------------------------------------*/ extern bool swset_checkpoint (PROTOBOX pbox, SWCHECKPOINT *cp); extern bool swclear_checkpoint (SWCHECKPOINT *cp);

/*--------------------------------------------------------* the following functions use a cursor to traverse through all of the nets whose transition probabilities and state probabilities have changed since a given checkpoint.

it returns the current values of probabilities and the difference in values since the checkpoint

*--------------------------------------------------------* extern bool swget-changecursor (SWCHECKPOINT cp, SWMODE m, SWCHANGECURSOR

*returnchange-cursor);

*return_pl, float *return_plchange, float *return_ps, float *return_pschange);

196

extern bool swincchangecursor (SWCHANGECURSOR *change-cursor, bool *return-eol); extern bool swdeletechange-cursor (SWCHANGECURSOR *changecursor);

/*--------------------------------------------------------* allows a user to clear all of the probability calculations on a proto box

*--------------------------------------------------------* extern bool swcleardata(void);

/*--------------------------------------------------------* the following functions allow the user to set

I probabilities on a network pin for a given mode.

this would generally be used on input proto pins and latch output pins.

setting a probability on any network pin for any mode would stop propagation of bdds through that pin for all modes

*--------------------------------------------------------* extern bool swsetdefault one prob(SWMODE m, float prob); extern bool swsetdefaultswitchprob(SW_MODE m, float prob); extern bool sw-set one-prob(SW MODE m, NETWORKPIN npin, float prob); extern bool swsetswitch-prob(SWMODE m, NETWORKPIN npin, float prob);

/*--------------------------------------------------------* these two functions allow a user to traverse through each mode of a proto box

*--------------------------------------------------------* extern bool swfirst_mode(PROTOBOX pbox, SWMODE *return-mode); extern bool swnextmode(SWMODE mode, SWMODE *return-mode);

#endif /* SWITCHINGH */

197