UBC Theses and Dissertations

UBC Theses Logo

UBC Theses and Dissertations

A layout generator for stray insensitive switched capacitor filters Lindholm, John Erik 1986

You don't seem to have a PDF reader installed, try download the pdf

Item Metadata

Download

Media
[if-you-see-this-DO-NOT-CLICK]
UBC_1986_A7 L56.pdf [ 10.93MB ]
[if-you-see-this-DO-NOT-CLICK]
Metadata
JSON: 1.0096921.json
JSON-LD: 1.0096921+ld.json
RDF/XML (Pretty): 1.0096921.xml
RDF/JSON: 1.0096921+rdf.json
Turtle: 1.0096921+rdf-turtle.txt
N-Triples: 1.0096921+rdf-ntriples.txt
Original Record: 1.0096921 +original-record.json
Full Text
1.0096921.txt
Citation
1.0096921.ris

Full Text

c. A LAYOUT GENERATOR FOR STRAY INSENSITIVE SWITCHED CAPACITOR FILTERS by JOHN ERIK LINDHOLM A THESIS SUBMITTED IN PARTIAL FULFILMENT OF THE REQUIREMENTS FOR THE DEGREE OF MASTER OF APPLIED SCIENCE in THE FACULTY OF GRADUATE STUDIES DEPARTMENT OF ELECTRICAL ENGINEERING We accept this thesis as conforming to the required standard THE UNIVERSITY OF BRITISH COLUMBIA FEBRUARY, 1986 © JOHN ERIK LINDHOLM, 1986 7 8 In presenting this thesis in partial fulfilment of the requirements for an advanced degree at the University of British Columbia, I agree that the Library shall make it freely available for reference and study. I further agree that permission for extensive copying of this thesis for scholarly purposes may be granted by the head of my department or by his or her representatives. It is understood that copying or publication of this thesis for financial gain shall not be allowed without my written permission. Department of The University of British Columbia 1956 Main Mall Vancouver, Canada V6T 1Y3 Date Mft£OH QO}^(o Abstract Two software programs have been developed to automatically generate the layout of stray insensitive switched capacitor filters. The first program, CIRCE, uses a SWITCAP filter description to generate an intermediate format filter description that is suitable for direct layout. It groups the filter elements into integrators and then sorts these integrators and their elements. The SWITCAP description can be with or without switch-sharing. The second program, SISCL, lays out the filter in CIF format using a double-polysilicon ISOCMOS process. The layout is done with a capacitor array placed over the switches and the standard-cell operational amplifiers placed beneath the switches. The layout is done with full switch-sharing. Capacitors may be rearranged in the intermediate file to produce better layouts. The software' is written in the C language. i i Table of Contents Abstract .. i i Table of contents iii List of tables vList of figures viAcknowledgement , 1 . Introduction 1 2. ISOCMOS process technology 2 2.1 The fabrication process2.2 CMOS switches 2 2.3 CMOS resistors 4 2.4 CMOS capacitors3. The switched capacitor 9 3.1 The parallel switched capacitor 9 3.2 The switched capacitor integrator 13 3.3 Parasitic capacitance considerations 16 3.4 Monolithic filter accuracy 20 3.5 Filter design 22 4. The circuit extractor (CIRCE) 23 4.1 Introduction4.2 Breaking down the input file 26 4.2.1 Simplifying the filter file (REDUCE) 26 4.2.2 Inserting the subcircuits (REPLACE) 29 4.3 Gathering the integrators 32 4.3.1 Removing the input stage (ISOLATE) 32 4.3.2 Forming the integrators (STAGES) 35 4.4 Sorting the filter 43 4.4.1 Processing the input stages (INPUT) 43 iii 4.4.1.1 INPUT1 (Lee) 44 4.4.1.2 INPUT2 (Martin)4.4.1.3 INPUT3 (Datar and Sedra) 45 4.4.1.4 INPUT4 (AROMA) 44.4.2 Sorting the integrators (ORDER1) 45 4.4.3 Sorting the elements and nodes (0RDER2) ...50 5. The layout generator (SISCL) .54 5.1 Introduction 55.2 The operational amplifier 54 5.3 Reading the input data (INIT) 57 5.4 The capacitors 60 5.4.1 The capacitor array 65.4.2 Layout method 62 5.4.3 Capacitor accuracy analysis 67 5.4.4 Generating the array (CAPARRAY) 72 5.5 Selecting the switches to be placed (PREOP) 77 5.6 The capacitor wiring 79 5.6.1 Introduction5.6.2 The input nodes (WIRE1) 80 5.6.3 The output nodes (WIRE2) 2 5.6.4 The shared node at the input (WIRE3) 82 5.6.5 The shared nodes at the output (WIRE4) ....85 5.6.6 The switch placement and connections (STREAK) 85.7 Placing and connecting the operational amplifiers 8 5.7.1 Connecting the input and output nodes (WIRE5) 85.7.2 Connecting the ground nodes (WIRE6) 89 iv 5.7.3 Placing the operational amplifiers (AMPSON) 89 5.8 Placing the global features (WRAPUP) 92 5.9 Layout of the input stage 96 6. Results and discussion 99 6.1 A 3825 Hz bandpass elliptic filter (Lee) 99 6.2 A 500 Hz lowpass elliptic filter (Martin) 109 6.3 A 3 kHz ^ 5 kHz band-elimination elliptic filter (AROMA) 117 6.4 Discussion 125 7. Conclusion 8 7.1 Future work ....12REFERENCES 131 APPENDIX A 3 APPENDIX B 135 APPENDIX C 8 APPENDIX D 173 v List of Tables Table Page 2.1. Layer resistances 5 2.2. Layer capacitances 8 4.1. Parameter substitutions 32 vi List of figures Figure Page 2.1. CMOS switch schematic 3 2.2. CMOS switch model 4 2.3. Layout of a switch-pair 5 2.4. Polysilicon1-polysilicon2 capacitor ..' 7 2.5. Parasitic capacitances 7 3.1. Parallel switched capacitor 10 3.2. Clock waveforms 13.3. Resistor equivalent 1 3.4. Series switched capacitor 13.5. RC integrator 13 3.6. Parallel SC inverting integrator .14 3.7. Series SC inverting integrator 13.8. Stray insensitive SC noninverting integrator 17 3.9. Stray insensitive SC inverting integrator 17 3.10. Stray capacitances 18 3.11. Parallel switching during 0, 19 3.12. Parallel switching during <j>2 20 4.1. Input stage (Lee) 24 4.2. Input stage (Datar & Sedra) 24.3. Integrator model 25 4.4. CIRCE flowchart 7 4.5. REDUCE function flowchart 28 vii List of figures Figure Page 4.6. SWITCAP filter description (filter) 30 4.7. Output from REDUCE function 31 4.8. REPLACE function flowchart 3 4.9. Output from REPLACE function 34 4.10. ISOLATE function flowchart 6 4.11. Input section (filter.in) 37 4.12. Isolated input section . 37 4.13. Remainder of filter description 38 4.14. STAGES function flowchart 39 4.15. SISC function flowchart 40 4.16. Integrator with switch-sharing 42 4.17. Stray insensitive SC element4.18. Output from STAGES function 43 4.19. Final input stage description 4 4.20. Linear topology 46 4.21. Band-pass filter topology 47 4.22. AROMA filter topology4.23. ORDER1 function flowchart 48 4.24. Output from ORDER1 function 9 4.25. CIRCE output file (filter.nd) 50 4.26. ORDER2 function flowchart " 51 4.27. CIRCE output file (filter.ct) 52 viii List of figures Figure • Page 5.1. SISCL flowchart 55 5.2. Operational amplifier parameters 56 5.3. Filter.com file format 55.4. Operational amplifier layout 58 5.5. INIT function flowchart 59 5.6. First capacitor plate 63 5.7. Additional capacitor plates ..65.8. Small fractional add-on capacitance 64 5.9. Large fractional add-on capacitance 66 5.10. Polysiliconl systematic error 68 5.11. Polysilicon2 systematic error 70 5.12. Array layout flowchart (LAYARRAY) 74 5.13. Horizontal capacitor spread 75 5.14. Vertical capacitor spread5.15. Optimal capacitor array 76 5.16. PREOP function flowchart 8 5.17. Wiring model 80 5.18. WIRE1 function flowchart 81 5.19. Output from WIRE 1 83 5.20. Output from WIRE25.21. Output from WIRE3 84 5.22. Output from WIRE4ix List of figures Figure , Page 5.23. STREAK function flowchart 86 5.24. Output from STREAK function 7 5.25. WIRE5 function flowchart 90 5.26. Output from WlRE5 function 1 5.27. Output from the WIRE6 function 95.28. Output from the AMPSON function 93 5.29. AMPSON output for reversed inputs 94 5.30. Output from the WRAPUP function 95 5.31. Final layout 97 6.1. LC prototype of filterl 100 6.2. SC implementation of filterl 101 6.3. SWITCAP filterl file 102 6.4. Filterl .in file 104 6.5. Filterl.nd file6.6. Filterl.ct file 105 6.7. Filter1.com file6.8. Filterl layout 106 6.9. Revised filterl.ct file 107 6.10. Revised filterl layout 108 6.11. LC prototype of filter2 110 6.12. SC implementation of filter2 111 6.13. SWITCAP filter2 file ' 112 x List of figures Figure Page 6.14. Filter2.nd file 114 6.15. Filter2.ct file 5 6.16. Filter2.com file 116.17. Filter2 layout 6 6.18. SC implementation of filter3 118 6.19. SWITCAP filter3 file 119 6.20. Filter3.nd file 121 6.21 . Filter3.ct file 1 22 6.22. Filter3.com file 123 6.23. Filter3 layout 4 7.1. Switch cell , 1 29 B.1. Sample SWITCAP file 137 xi Acknowledgement I would like to thank my supervisors, Dr. L. Young, and Dr. D. Moore for their guidance and support during the course of this work. I would also like to acknowledge the financial and technical help given by the people at Microtel Pacific Research Ltd. (MPR), especially Mr. P. Thiel, and Mr. H. Schweikle. Thanks are extended to Mr. C. Huntley, Mr. K. Wei, and Mrs. E. Willoner, of MPR for their technical guidance. I also wish to thank my parents for their continual support of my education. xi i 1. INTRODUCTION Monolithic switched capacitor filters were introduced in 1977 [1][2], and the technology has advanced rapidly since then. Stray insensitive switched capacitor filters based on passive LC ladder prototypes are commonly used today in commercial products, as a variety of methods exist for transforming the prototypes into switched capacitor filters [3]-[9]. Programs such as SWITCAP (see Appendix B), provide accurate performance analysis of these filters and the technology may be considered mature [10], The layout of stray insensitive switched capacitor filters is still mainly done by hand; however, the maturity of the design techniques provides incentive to develop a program that can automatically generate the layout from a filter description. Such a program has been developed in this thesis. It uses a SWITCAP filter description to generate the layout in Caltech Intermediate Form (CIF) [11 ]. The software is written in the C language and was developed on the Metheus X750 system at the University of British Columbia. 1 2. ISOCMOS PROCESS TECHNOLOGY 2.1 THE FABRICATION PROCESS The ISOCMOS (isolation Oxide CMOS) process uses a single p-well in an n- substrate. The process is characterized by the steps tabulated below with the CIF code for each layer given after the layer. 1. Active (AC) 2. P-well implant (PW) 3. Polysiliconl (P1) 4. Polysilicon2 (P2) 5. N+ Implant (NP) 6. P+ Implant (PP) 7. Contact cuts (C1) 8. Metallization (M1) 9. Passivation (GL) A thin oxide layer separates the polysiliconl-polysilion2 layers producing a high capacitance. A 5um process was used. 2.2 CMOS SWITCHES It is possible to implement an excellent switch in CMOS technology (Fig. 2.1). The clock controls the switch. A simple non-ideal model of a CMOS switch is shown in Fig. 2.2. The on resistance is typically 1k$2, and the off resistance is in the 1Tfl range, producing a conductance ratio of a billion to one. 2 3 Capacitors CGS and CGD represent parasitic capacitances between the gate and the switch terminals. These parasitics are in the 1fF range and contribute to a feedthrough effect where a portion of the control voltage appears at the switch terminals. These parasitics are caused by lateral diffusion under the gate causing a gate-source and gate-drain overlap. Capacitors CSS and CDS represent parasitic capacitances from the switch terminals to the substrate and their values depend on the drain and source areas, but they are in the 1pF range. The switches are laid out in pairs since the switched capacitors are alternately switched from ground to the circuit. The switches are overlapped to reduce the overall area, resulting in a shared source and drain for two of the D. In Out Fig. 2.1: CMOS switch schematic 4 Gate C 5 GS C GD Source • Wv Dra In C SS C DS Fig. 2.2: CMOS switch model transistors (Fig. 2.3). The switches are of minimum geometry to minimize the switch-induced error voltage [12]. 2.3 CMOS RESISTORS Resistors can be fabricated in a number of ways using the p-well, polysilicon, or active regions. The absolute accuracy of these resistors is typically 50%, making precision resistors impossible. Table 2.1 summarizes the effective resistances achieved by these methods. 2.4 CMOS CAPACITORS Three types of capacitors suitable for analog sampled data applications can be fabricated. One is between the gate and the channel, another is between the metal and the 5 Fig. 2.3; Layout of a switch-pair  Table 2.1; Layer resistances Layer Resistance (ohms/n) p_weli 1000 p+ act ive 90 n+ 3ctIve 10 polys iI iconl 40 polys i i icon2 55 metal 0.023 6 substrate, and the third is between the polysilicon layers. The gate-oxide-channel capacitor has a value in the 0.4 pF/u2 range. Its main disadvantage is that a voltage-dependent parasitic capacitance exists from the channel to the substrate. This parasitic capacitance has a value from 5% - 20% of the desired capacitance, and this renders the gate-oxide-channel capacitor useless for switched capacitor filters. The metal-substrate capacitor and the polysilicon1-polysilicon2 capacitors do not have any voltage dependent parasitic capacitances. The polysilicon1-polysilicon2 capacitor (Fig. 2.4) has a slightly thicker oxide layer than the gate-oxide-channel capacitor and hence its capacitance is slightly less. The metal-substrate capacitor oxide is some twenty times thicker resulting in a much smaller capacitance. For these reasons, the polysiliconl-polysilicon2 capacitor is the preferred choice in switched capacitor filters. The capacitances are summarized in Table 2.2. All capacitors have parasitic capacitances associated with them. For the polysiliconl-polysilicon2 capacitor, the top plate parasitics are mainly due to circuit connections, and the overlap capacitors of the drain or source to the bulk of switches attached to them. These parasitics are modelled as capacitors to ground (Fig. 2.5). The top plate parasitic capacitance is typically 0.1% - 1.0% of the desired capacitance, and the bottom plate parasitic 7 polys11lcon2 oxide polys 11Iconl oxide substrate Fig. 2.4: Polysilicon1-polysilicon2 capacitor c v2 Cpt Cpb Fig. 2.5: Parasitic capacitances Table 2.2: Layer capacitances Layers Capacitance (FF/um2) gate ~ channel 0.42 polyl - poly2 0.40 -polyl - substrate 0,024 metal - substrate 0,019 capacitance is typically 10% of the desired capacitance. These parasitics are unavoidable, and their size depends on the layout, the technology, and the capacitor size. The absolute accuracy of a capacitor is a few percent and is edge dependent. This error is due to oxide undercutting in the photolithography process, and to mask resolution. These errors are associated with the periphery of the capacitors. 3. THE SWITCHED CAPACITOR 3.1 THE PARALLEL SWITCHED CAPACITOR Consider the switched capacitor (SC) network of Fig. 3.1, clocked by the <t>, and <j>2 waveforms of Fig. 3.2. It will be shown that this circuit is equivalent to the circuit of Fig. 3.3. Assume that V, and V2 are two independent DC voltage sources that are constant during most of the phase period. Assume initially that both switches are open and that the capacitor C is uncharged. During <t>}, the capacitor will charge to V,, and the charge transferred into the capacitor C is During <p2, the charge transferred into the capacitor is and during 0, again, the charge transferred into the capacitor is Q(T/2) = CV, (3.1) Q(T) = C(V2-V1) (3.2) Q(3T/2) = C(V,-V2) (3.3) and steady-state has been reached. Let Vi-V2 = v2-v (3.4) The current at a point in the circuit is 9 10 1 1>1 ^2 v2 : B c Fig. 3.1; Parallel switched capacitor 0 T/2 T 3T/2 2T 5T/2 t Fig. 3.2; Clock waveforms 11 R A/W -Q Fig. 3.3; Resistor equivalent 1 : • C Fig. 3.4: Series switched capacitor 12 i - f (3.5) Consider the flow of charge in the sense of i, in Fig. 3.1. The total charge flow is Q, 3T/2 3T/2 Qi = Jm iidt = J. i,dt (3.6) T T/2 since no charge flows during the previous phase period. Equating 3.3 to 3.6 and dividing by T results in Q(3T/2) 1 3T/2 . Ii = T = T 'T/2 1,<3T (3'7) or : = c(v,-va) 1 = \ ' (3.8) Now substituting 3.4 into 3.8 gives R = ^ (3.9) This switched capacitor implementation is called a parallel switched capacitor. It is also possible to implement a series switched capacitor as shown in Fig. 3.4. A similar analysis to the one given above for the parallel case yields the same relationship. 1 3 3.2 THE SWITCHED CAPACITOR INTEGRATOR It is neccessary to introduce the operational amplifier to completely transfer the charge of one capacitor to another capacitor. All operational amplifiers are considered ideal for the following analysis. The RC integrator of Fig. 3.5 is the basic building block of active filters. The transfer function of this integrator is \Ml>" - SET Replacing the resistor R by the parallel switched capacitor of Fig. 3.1 results in the circuit of Fig. 3.6. This circuit can be analyzed by z-transform techniques. During the charges on the capacitors are Fig. 3.5; RC integrator Fig. 3.7: Series SC inverting integrator 15 Qi = C,V2(n-.5) (3.11) Q2 = C2V](n-.5) (3.12) where the superscripted number refers to the clock phase. During <p2, charge conservation yields C,V|(n) = C,V2(n-.5) - C2V](n-.5) (3.13) or Vl(z) = Z~1/2V2(Z) - ( ^ )z"1/2V](z) (3.14) On the transformation <f>2 to 0t V|(n-1) = V2(n-.5) (3.15) or V|(z) = Z1/2V2(Z) (3.16) Substituting 3.16 into 3.14 gives zV2(z) = V2(z) - ( )V}(z) (3.17) c 1 or fflfy • ' >' > (3.18) Now substituting 3.9 into 3.10 gives 1 6 - (3 19) V,(s) STC, U.iy> and comparing 3.19 with 3.18 results in s = (3.20) which is the forward transformation. Repeating this analysis for the series switched capacitor of Fig. 3.7 gives the transfer function v?(z) 1 c, M 1-z-1 ; i3.^i; and comparing 3.21 with 3.19 gives 1-z- 1 s = J-|— (3.22) which is the backward transformation. 3.3 PARASITIC CAPACITANCE CONSIDERATIONS The bottom plate of the parallel switched capacitor is grounded, hence the bottom plate parasitics are shorted across ground and have no effect. The top plate parasitic which is some 0.1% - 1.0% of the capacitor value degrades the capacitor accuracy when it charges and discharges. To negate any parasitic capacitances, the switching schemes of the parallel and series switched capacitor inverting integrators are changed into those of Fig. 3.8 and Fig. 3.9. Notice that the top and bottom plates of the 17 Fig. 3.9: Stray insensitive SC inverting integrator 18 parallel switched capacitor are now alternating to ground, and that the integrator is now noninverting. The transfer function of the integrator is V,(z) 1 C, M 1-z-1 ; K*-**) while the transfer function of the series integrator remains unchanged. The parasitic capacitances of the parallel integrator are shown in Fig. 3.10. In this implementation, the stray capacitances have no effect on the transfer function of either integrator. During , the switched capacitor of Fig. 3.8 looks like Fig. 3.11. The bottom plate parasitic CBP is shorted Fig. 3.10; Stray capacitances 19 across ground and the top plate parasitic CTP is charged to V, with the capacitor C. During <j>2 (Fig. 3.12), CTP is shorted across ground and has no effect on the charge transfer. Capacitor CBP is now virtually shorted across ground and hence has no effect either. The charge on C is transferred through the operational amplifier and to the integrating capacitor C,. One plate of C, is always connected to the virtual ground, hence its parasitic capacitance has no effect while the other plate is always connected to the operational amplifier output. If the operational amplifier has a high gain, a good virtual ground is assured, and if it has a high gain and drive capability, the other parasitic has no effect. Fig. 3.11: Parallel switching during <f> 20 Fig. 3.12: Parallel switching during <t>2 It is important to note that all stray insensitive switched capacitors must be connected from a voltage source i to a virtual ground. The same applies to the integrating and coupling capacitors. 3.4 MONOLITHIC FILTER ACCURACY The time constant T of the RC integrator of Fig. 3.5 is T = RC, (3.24) with differential dr = RdC, + C,dR (3.25) Interpreting dr/r as the relative error in T gives 21 dT dR dC, . . - = ~ + (3.26) In a typical MOS technology, dC^C, is accurate to a few percent and dR/R is accurate to ±50%. This is not adequate for filter implementation. The switched capacitor integrators of Fig. 3.8 and Fig. 3.9 have a time constant T of TC, r = ^ (3.27) C 2 giving dr dT dC, dC, , „ "7 = + ~ct " ~ct {3-28) An accurate clock is assumed, giving dT/T = 0. Then dr dC_L _ dC^ T C, C2 K6'Z*} For two adjacent capacitors with the same technology, this relative error has a value less than 0.1%. Absolute values are very hard to achieve, but errors affect both capacitors the same way maintaining the ratio. The linearity and temperature coefficients are also well behaved in this ratio. 22 3.5 FILTER DESIGN A better way of transforming the filter response from the s to z plane is through the bilinear transform. Much work was spent in the early eighties on techniques to transform a passive LC prototype filter to a suitable switched capacitor implementation [3]-[9]. The desired filter must use stray insensitive switched capacitors and should be derived through the bilinear transform. Such techniques were developed by Lee [7], and Datar and Sedra [8]. These techniques replace the series and shunt branches of the LC prototype with integrators. The software developed in this thesis was based on these techniques as well as those of Martin [6], and of the AROMA program [9], which uses biquadratic sections consisting of two integrators. 4. THE CIRCUIT EXTRACTOR (CIRCE) 4.1 INTRODUCTION The circuit extractor program (CIRCE), converts a SWITCAP filter file (here called filter), into a filter description more suitable for direct layout. It groups the filter elements into integrators, each consisting of stray insensitive switched capacitors, coupling capacitors, an integrating capacitor, and an operational amplifier. The integrators as well as the integrator elements are then sorted from the filter input to its output to simplify the layout. In addition to the SWITCAP file, CIRCE requires a file containing the filter input stage elements (filter.in). The software generates two output files: one contains the node ordering information (filter.nd), and the other contains the final filter description (filter.ct). The software can currently process the input stages of Lee, and Datar and Sedra. These are shown in Fig. 4.1 and Fig. 4.2. There is no input stage for filters designed by AROMA, or by the techniques of Martin. The input stage of the filter is the set of circuit elements feeding the input voltage to the first integrator's operational amplifier. The rest of the filter must be comprised of integrators (Fig. 4.3) possessing any number of coupling and switched capacitors, that obey the following rules: 23 24 V, Fig. 4.1: Input stage (Lee) Fig. 4.2: Input stage (Datar & Sedra) 25 1. Only stray insensitive switched capacitors, coupling capacitors, and operational amplifier elements are allowed. 2. The noninverting input of each operational amplifier is always grounded. 3. Each operational amplifier must have one integrating capacitor. 4. Each operational amplifier feeds at least one switched capac itor. 5. The only distinct nodes in the filter are the operational amplifier noninverting input and output nodes. 6. Each operational amplifier is fed charge on only one of the two clocks. V5 Fig. 4.3: Integrator model 26 7. The input stage connects to one operational amplifier noninverting input. The design techniques of Refs. [6], [7], [8], and [9], obey these restrictions. The CIRCE program consists of seven main function calls, and twenty-nine functions in all. A flowchart of CIRCE is shown in Fig. 4.4, and the main function calls are further described in this chapter. A listing is provided in Appendix C. 4.2 BREAKING DOWN THE INPUT FILE 4.2.1 SIMPLIFYING THE FILTER FILE (REDUCE) The SWITCAP filter file is first simplified by removing all non-essential data in the file. The filter input and output nodes are noted here. ' The filter elements are all in the SUBCKT and CIRCUIT sections of the file, so everything else is removed. The filter input node is taken as the first node of the voltage source statement, and the filter output node is taken as the first node of the PRINT or PLOT statement(s) in the ANALYZE block. The CIRCUIT and SUBCKT blocks are copied from the input file as follows: 1. Capitalize all letters. 2. Remove comments and blank lines. 3. One statement per line. 4. Left-adjust all lines. 27 START REDUCE - clean up the l npu t File REPLACE - insert any subc i rcu it cal I s ISOLATE - isolate the input stage STAGES _ group elements into integrators INPUT ~ process the appropriate input stage 0RDER1 _ sor t the integrator stages DRDER2 - sort the elements and nodes END Fig. 4.4: CIRCE flowchart 28 STRRT 4 : Open SUITCRP File i DO readcle9n(l ine, inFiIe ) UHILE no su.bcir-cu.it or circuit UHILE not 8 n 9 I y z e bl ock IF line is not empty IF voltage sounce note input node ELSE uniteCline^outFile) re9dcle9n(I i ne j i n F i I e ) i UHILE not en d oF File IF pr i. n t/plct I i ne note output node readcIe9n( I i ne} in File) 1 Close SUITCRP File > END Fig. 4.5: REDUCE function flowchart 29 A flowchart of the REDUCE function is shown in Fig. 4.5. A sample SWITCAP filter file (filter) is shown in Fig. 4.6, and the corresponding file after processing is shown in Fig. 4.7. The filter file contains a switched capacitor filter design by Datar and Sedra, with random capacitor values. 4.2.2 INSERTING THE SUBCIRCUITS (REPLACE) The subcircuit blocks are now inserted into the circuit. The file is scanned and if a SUBCKT block is found, it is removed from the file. The rest of the file is then scanned for any calls of that subcircuit. If any are found, the call is replaced by the subcircuit elements with the appropriate parameters inserted. All subcircuit calls start with a capital X in SWITCAP files. This process is repeated until there are no more SUBCKT blocks in the file. The parameter replacement process works as follows. The parameters of the SUBCKT block header, as well as any other nodes existing in the SUBCKT block are tabulated. The parameters of the call are then tabulated next to the first set and any extra nodes are inserted to complete the second list. Node 0 is always ground. The subcircuit elements are then written to the file with the parameter substitutions made between the two lists. A sample table is shown in Table 4.1 for the first subcircuit call of Fig. 4.7. An entry is made only once in the first column of the table, and any extra nodes are of the format !AA which are 30 OPTIONS ; GRID ; END ; TITLE: Switched-Capacitor Filter (Datar & Sedra) ; TIMING ; /* Timing Section */ PERIOD le-6 ; CLOCK C 1 (0 3/8) ; END ; /* switched-capacitor sub-circuit */ SUBCKT (1 4) swc (K:phil K:phi2 K:phi3 K:phi4 P:capl) ; 51 (1 2) phil ; 52 (2 0) phi2 ; S4 (3 0) phi4 ; CI (2 3) capl ; S3 (3 4) phi3 ; END ; CIRCUIT ; /* network section */ /* switched-capacitors * / Xc (12 10) swc (#c C #C C 3 .00) Xd (12 20) swc (#C C C #c 4 .00) Xe (22 10) swc (#C C #c c 6 .00) Xf (42 10) swc (#C C #c c 12 .00) Xg (30 32) swc (#C C #c C 8 .00) Xh (40 32) swc ( C #C : #c c 9 .00) Xi (42 30) SWC (#C C #c c 11 .00) Xj (22 30) SWC (#C C #c c 13 .00) /* capacitors */ C2 (10 12) 2.00 ; C5 (22 20) 5.00 C14 (10 32) 14.00 ; C10 (40 42) 10.00 ; C15 (12 30) 15.00 ; C7 (30 32) 7.00 ; /* input section */ CO (2 0) 1.00 ; CI (52 53) 1.00 ; CI (54 55) 1.00 ; S (1 2) #C ; S ( 3 52) C ; S (52 0) #C ; S (53 10) C ; S (53 0) #C ; S ( 3 54) #C ; S (54 0) C ; S (55 10) #C ; S (55 0) C ; /* op-amps */ E5 (42 0 0 40) 5000 ; El (3 0 2 3) 5000 ; E3 (22 0 0 20) 5000 ; E4 (32 0 0 30) 5000 ; E2 (12 0 0 10) 5000 ; VI (10) ; /* input voltage node */ END ; ANALYZE SSS ; /* Analysis Section */ INFREQ 0.01 100000 LOG 15 ; SET VI AC 1.0 0.0 ; /* amplitude and phase */ PRINT VR(32) VI(32) ; /* real and imaginary parts */ END ; END ; Fig. 4.6: SWITCAP filter description (filter) SUBCKT (1 4) SWC (K:PHI1 K:PHI2 K:PHI3 K:PHI4 P:CAP1) ; 51 (1 2) PHI1 ; 52 (2 0) PHI2 ; S4 (3 0) PHI4 ; Cl (2 3) CAP1 ; 53 (3 4) PHI3 ; END ; CIRCUIT ; XC (12 10) SWC (#c C #c c 3. 00) XD (12 20) SWC (#c c c #c 4. 00) XE (22 10) SWC (#c c #c c 6. 00) XF (42 10) SWC (#c c #c c 12. 00) XG (30 32) SWC (#c c #c c 8. 00) XH (40 32) SWC ( c #c #c c 9. 00) XI (42 30) SWC (#c c #c c 11. 00) XJ (22 30) SWC (#c c #c c 13 . 00) C2 (10 12) 2.00 7 C5 (22 20) 5. 00 . C14 (10 32) 14. 00 • 9 CIO (40 42) 10. 00 • C15 (12 30) 15. 00 • C7 (30 32) 7.00 • CO (2 0) 1. 00 ; Cl (52 53) 1. 00 • 9 Cl (54 55) 1.00 • 9 S (1 2) #C • 9 S ( 3 52) C ; S (52 0) #C ; S (53 10) C ; S (53 0) #C ; S ( 3 54) #C ; S (54 0) C ; S (55 10) #C ; S (55 0) C ; E5 (42 0 0 40) 5000 ; El (3 0 2 3) 5000 ; E3 (22 0 0 20) 5000 ; E4 (32 0 0 30) 5000 ; E2 (12 0 0 10) 5000 ; END ; Fig. 4.7: Output from REDUCE function 32 Table 4.1: Parameter substitutions SUBCKT Parameters Call Parameters I 12 4 10 PHI1 #C PHI2 c PHI3 ftC PHI4 C CRP1 3,00 2 !RR 0 0 z J !RB not allowed in SWITCAP files. The flowchart of the REPLACE function is shown in Fig. 4.8, and the resulting output file is shown in Fig. 4.9. 4.3 GATHERING THE INTEGRATORS 4.3.1 REMOVING THE INPUT STAGE (ISOLATE) The ISOLATE function removes all input stage elements from the filter description file. All elements in the filter.in file are removed from the filter file. The flowchart of the ISOLATE function is shown in Fig. 4.10. The data in the filter.in file (Fig. 4.11) is first processed in the same way as the filter file was. Any lines START re add inej in File) i UHILE more subcircui t calls note subcircuit name copy subcircuit to spare File tabulate subcircuit parameters DO read(I Lne ) inF LIe ) IF same subcircuit called tabuI ate calI p3r8me t ers Fill parameter table copy subcircuit block with substitutions to output File ELSE ur i te( I i ne j ou tFile) UHILE not end-oF-File reuerse input and output File read(I ine, in File) END Fig. 4.8: REPLACE function flowchart 34 CIRCUIT ; SI (12 IAA) #C • r S2 (!AA 0) C ; S4 (!AB 0) C ; Cl (!AA !AB) 3. 00 S3 (!AB 10) #C • 9 SI (12 !AC) #C m 9 S2 (!AC 0) C ; S4 (!AD 0) #C ; Cl (!AC !AD) 4. 00 S3 (!AD 20) C ; SI (22 !AE) #C • 9 S2 (! AE 0) C ; S4 (!AF 0) C ; Cl (!AE JAF) 6. 00 S3 (!AF 10) #C • SI (42 1AG) #C • S2 (!AG 0) C ; S4 (!AH 0) C ; Cl (!AG !AH) 12 .00 S3 (!AH 10) #C • 9 SI (30 !AI) #C • S2 (!AI 0) C ; S4 (!AJ 0) C ; Cl (!AI !AJ) 8. 00 S3 (!AJ 32) #C • 9 SI (40 !AK) C ; S2 (!AK 0) #C ; S4 (!AL 0) C ; Cl (! AK ! AL) 9. 00 S3 (!AL 32) #C • SI (42 !AM) #C • S2 (!AM 0) C ; S4 (! AN 0) C ; Cl (!AM !AN) 11 .00 S3 (!AN 30) #C • SI (22 !AO) #C • 9 S2 (!AO 0) C ; S4 (!AP 0) C ; Cl (!AO !AP) 13 .00 S3 (!AP 30) #C • 9 C2 (10 12) 2.00 • C5 (22 20) 5.00 • 9 C14 (10 32) 14. 00 CIO (40 42) 10. 00 C15 (12 30) 15. 00 C7 (30 32) 7.00 • CO (2 0) 1.00 ; Cl (52 53) 1.00 • 9 Cl (54 55) 1.00 • Fig. 4.9: Output from REPLACE function 35 S (1 2) #C ; S ( 3 52) C ; S (52 0) #C ; S (53 10) C ; S (53 0) #C ; S ( 3 54) #C ; S (54 0) C ; S (55 10) #C ; S (55 0) C ; E5 (42 0 0 40) 5000 ; El (3 0 2 3) 5000 ; E3 (22 0 0 20) 5000 ; E4 (32 0 0 30) 5000 ; E2 (12 0 0 10) 5000 ; END ; Fig. 4.9: Output from REPLACE function (cont'd) in the filter file that are in the filter.in file are put into one output file (Fig. 4.12) while the remaining lines are put into another output file (Fig. 4.13). This isolates the input stage elements from the integrator stages of the filter. 4.3.2 FORMING THE INTEGRATORS (STAGES) The circuit elements are now gathered into integrators with the elements sharing a common inverting operational amplifier node (Fig. 4.4). Each integrator consists of one operational amplifier, one integrating capacitor, at least one switched capacitor, and any coupling capacitors. This grouping is done for each operational amplifier as it is found in the filter file. The flowchart of the STAGES function is shown in Fig. 4.14. Each element is also recoded here for convenience. The operational amplifiers are called OA, the stray insensitive switched capacitors are called SC, the integrating 5TRRT Open File, in readc i e3n( I i ne, F 11 e . i n ) UHILE not end~oF_F tie IF i ine not empty ur L t e(i i ne,1 :11 el ) resdci e9nCi ine,F 1 i e . in) Ci ose File. Ln readiI Inej inF[i e ) UHILE not end-oF-File set Flag readiI ine2;F LI el ) UHILE Flag and not end-oF-File IF I Inel equals. I ine2 reset Fi 3g  read(i lne2,F 11 el ) IF Rag ur11 e(I i ne(on tFlie) new i n d(Fllel) readi i ine, inF i1e ) END Fig. 4.10; ISOLATE function flowchart /* input section */ CO (2 0) 1.00 ; Cl (52 53) 1.00 ; Cl (54 55) 1.00 ; S (1 2) #C ; S ( 3 52) C ; S (52 0) #C ; S (53 10) C ; S (53 0) #C ; S ( 3 54) #C ; S (54 0) C ; S (55 10) #C ; S (55 0) C ; El (3 0 2 3) 5000 ; Fig. 4.11: Input section (filter.in) CO (2 0) 1.00 ; Cl (52 53) 1.00 ; Cl (54 55) 1.00 ; S (1 2) #C ; S ( 3 52) C ; S (52 0) #C ; S (53 10) C ; S (53 0) #C ; S ( 3 54) #C ; S (54 0) C ; S (55 10) #C ; S (55 0) C ; El (3 0 2 3) 5000 ; Fig. 4.12: Isolated input section SI < '12 !AA) #C • 9 S2 < '!AA 0) C ; S4 | [!AB 0) C ; Cl | [!AA !AB) 3. 00 S3 { [!AB 10) #C • 9 SI [12 !AC) #C • 9 S2 !AC 0) C ; S4 '!AD 0) #C ; Cl !AC !AD) 4. 00 S3 [!AD 20) C ; SI [22 !AE) #C • 9 S2 [!AE 0) C ; S4 [!AF 0) C ; Cl [!AE !AF) 6. 00 S3 [!AF 10) #C • SI [42 !AG) #C • S2 '!AG 0) C 7 S4 [!AH 0) C ; Cl •AG !AH) 12 .00 S3 !AH 10) #C • 9 SI 30 !AI) #C • 9 S2 [!AI 0) C ; S4 [!AJ 0) C ; Cl [!AI !AJ) 8. 00 S3 [!AJ 32) #C • SI [40 !AK) C ; S2 [IAK 0) #C ; S4 [! AL 0) C ; Cl [! AK ! AL) 9. 00 S3 [!AL 32) #C • 9 SI 42 !AM) #C • S2 '!AM 0) C ; S4 ' 1AN 0) C ; Cl ;!AM !AN) 11 .00 S3 ;!AN 30) #C • SI |22 !AO) #C • S2 (!AO 0) C ; S4 (!AP 0) C ; Cl (!AO !AP) 13 .00 S3 [!AP 30) #C • 9 C2 [10 12) 2.00 ; C5 [22 20) 5.00 ; C14 (10 32) 14. 00 CIO (40 42) 10. 00 C15 (12 30) 15. 00 C7 (30 32) 7.00 ; E5 (42 0 0 40) 5000 E3 (22 0 0 20) 5000 E4 (32 0 0 30) 5000 E2 (12 0 0 10) 5000 Fig. 4.13: Remainder of filter description START UHILE nor end_o F-Flle IF op_amp ur I ieC I Ine,oui File) save Input and output nodes save File oFFsei reu Ind File readCI Ine, InF11e ) UHILE noi end-oF-Flle IF capac I lor save nodes IF shares boih op~amp nodes encode as IC ELSE encode as CC IF su Itch save nodes IF share node w I th op_amp SISC readCIIne, InFlle) write blank IIne to ou tFlle restore File location readCIIne,InFlie) END Fig. 4.14; STAGES function flowchart START sBt>e clockl save File oFFset rewind File resdC I Ine, InFlle) UHILE not endJoF-Flle IF c3pBcI tor S8ce nodes IF shared node with switch sBi/e cBpScltor value seue neu node sSwe File oFFset reuInd File resd( I Inej inF 11, e) UHILE not end-oF-Ftle IF su Itch sB^e nodes IF First ground switch sBwe clock2 IF second ground switch sSt>e cl. ock4 IF output switch save clock3 resdC I Ine, InF lie) write SISC element restore File location resdCIIne, InF11e) restore File location END Fig. 4.15: SISC function flowchart 41 capacitors are called IC, and the coupling capacitors are called CC. All capacitors have a 'C as the second letter of their labels. The inverting input node of each operational amplifier is used to gather up the integrator elements. A capacitor sharing both input and output node with the operational amplifier is an integrating capacitor, while a capacitor that only shares the input node is a coupling capacitor. If a switch is found connected to the input node, it must belong to a switched capacitor element. The SISC function (Fig. 4.15) gathers up the remaining elements of the switched capacitor. Since switch-sharing may be used, it is neccessary to check for more than one switched capacitor for each switch (Fig. 4.16). The stray insensitive switched capacitor element (Fig. 4.17) is then recoded as follows: SC (nodeA nodeB) C <j>2 $3 <i>n ; where nodeA connects to the operational amplifier inverting input node. This node is the reference point for the clocking scheme. The complementary clock must be designated by the '#' character. The output from the STAGES function is shown in Fig. 4.18. Fig. 4.17: Stray insensitive SC element 43 4.4 SORTING THE FILTER 4.4.1 PROCESSING THE INPUT STAGE (INPUT) The input stage of the filter is now recoded and the elements sorted into a suitable order. The node by which the input stage connects to the filter is saved here. There is one INPUT function for each of the design techniques. The elements of the input stages are switches (BS), capacitors (BC), stray insensitive switched capacitors (SC), and operational amplifiers (OA). Any operational amplifier is listed first, followed by any switches. Any capacitors are listed next, followed by any switched capacitors. The OA (42 0 0 40) 5000 ; SC (40 32) 9.00 C #C #C C IC (40 42) 10.00 ; OA (22 0 0 20) 5000 ; SC (20 12) 4.00 C #C #C C IC (22 20) 5.00 ; OA (32 0 0 30) 5000 ; SC (30 32) 8.00 #C C #C C SC (30 42) 11.00 #C C #C C SC (30 22) 13.00 #C C #C C CC (12 30) 15.00 ; IC (30 32) 7.00 ; OA (12 0 0 10) 5000 ; SC (10 12) 3.00 #C C #C C SC (10 22) 6.00 #C C #C C SC (10 42) 12.00 #C C #C C IC (10 12) 2.00 ; CC (io 32) 14.00 ; Fig. 4.18: Output from STAGES function 44 recoded and sorted output is written to the filter.ct file (Fig. 4.19). The different input functions are described further below. 4.4.1.1 INPUT1 (Lee) This input stage (Fig. 4.1) consists of four elements: two capacitors, and two switches. The switches are written first, followed by the capacitor connected to the input node, followed by the grounded capacitor. The input node is listed first for the first capacitor, and the filter connection node is the other node of this element. 4.4.1.2 INPUT2 (Martin) The STAGES function can process all elements of this design technique, hence the filter.in file is empty. The filter connection node is the first node of the SC element connected to the filter input node. OA (3 0 2 3) 5000 ; BC (2 0) 1.00 ; BS (1 2) #C ; SC (3 10) 1.00 C #C C #C ; SC (10 3) 1.00 #C C #C C ; Fig. 4.19: Final input stage description 45 4.4.1.3 INPUT3 (Datar and Sedra) This input stage consists of one operational amplifier, one switch, one capacitor, and two switched capacitors (Fig. 4.2). The operational amplifier is written first, followed by the switch and the grounded capacitor. One of the SC elements can be switch-shared with the first integrator, and it is written last. The other SC element is written next, followed by the above SC element. The SC elements are gathered up by the SISC function. The filter connection node is the second node of either SC element. 4.4.1.4 INPUT4 (AROMA) The biquad stages used by the AROMA program are similar to the design technique of Martin. The filter.in file is again empty, as the STAGES function can handle all the elements. The filter connection node is obtained from SC element(s) connected to the filter input node. If only one SC exists connected to the filter input node, the connection node is its second node. If there is a choice of possible connection nodes, the node occurring only once is chosen. 4.4.2 SORTING THE INTEGRATORS (ORDER1) The integrator stages are sorted into an order suitable for direct layout by the ORDER1 function. This sorting starts with the node provided by the appropriate INPUT function. 46 Many biquad filters as well as bilinear low-pass filters have a filter topology similar to that of Fig. 4.20. Bandpass filters are more complex as shown in Fig. 4.21 and the AROMA program generates biquad sections as shown in Fig. 4.22. Each integrator is represented by one box. Only SC elements are used as links in the sorting process. The sort proceeds by the SC elements fed by each operational amplifier, and once counted, an operational amplifer may not be counted again. In all cases, the filter connection node provides the first integrator stage, and its ouput node is used to start the search path. It is assumed that no integrator can feed more than two unsorted integrators. If only one is found, the sort is simple and linear. If two new integrators are V, Fig. 4.20; Linear topology 47 Fig. 4.21: Band-pass filter topology 4 * 3 Fig. 4.22: AROMA filter topology STRRT reBdCIine. InF iIe ) UHILE not end~oF~F Ie IF op-8mp s8ve nodes IF share connect ion node note op_Bmp output node I reBdCIine j inF i1e ) reu ind File DD get stage oFFset 9nd Feeds write stage to output File IF single Feed  update seSrchpath ELSE UHILE more double Feeds get stage2 oFFset 3nd Feeds get stage3 oFFset and Feeds IF stSge2 has no Feeds ur ite stage2 to output File write stsge3 to output File update seBrchpath ELSE IF stege3 has no Feeds write stage3 to output File write st8ge2 to output File update seBrchpath UHILE more Feeds urite node table to File.nd END Fig. 4.23: ORDER1 function flowchart 49 found, they are in turn processed, and the one yielding no new paths is written first, followed by the other. The sorting continues until no new integrators are found. This sorting always puts the filter output stage last or next-to-last. The flowchart of the ORDER1 function is shown in Fig. 4.23, and the output from the function is shown in Fig. 4.24. As each node pair is found by the software, it is saved for use by the 0RDER2 function, and is also written to the filter.nd file. The filter input and output nodes are written first, followed by any nodes existing in the input stage, then the nodes of the operational amplifiers. The OA (12 0 0 10) 5000 ; SC (10 12) 3.00 #C C #C C ; SC (10 22) 6.00 #C C #C C ; SC (10 42) 12.00 #C C #C C ; IC (10 12) 2.00 ; CC (10 32) 14.00 ; OA (22 0 0 20) 5000 ; SC (20 12) 4.00 C #C #C C ; IC (22 20) 5.00 ; OA (32 0 0 30) 5000 ; SC (30 32) 8.00 #C C #C C ; SC (30 42) 11.00 #C C #C C ; SC (30 22) 13.00 #C C #C C ; CC (12 30) 15.00 ; IC (30 32) 7.00 ; OA (42 0 0 40) 5000 ; SC (40 32) 9.00 C #C #C C ; IC (40 42) 10.00 ; Fig. 4.24: Output from ORDER1 function 50 inverting input node is written before the output node for each operational amplifier. The filter.nd file is shown in Fig. 4.25. 4.4.3 SORTING THE ELEMENTS AND NODES (ORDER2) The elements and their nodes are now sorted for each integrator by the ORDER2 function. It uses the nodal ordering information saved by the ORDER1 function to do this. The ORDER2 flowchart is shown in Fig. 4.26. Each element of an integrator is stored in an array and is written to the filter.ct file when the node not connected to the inverting input of the operating amplifier is found in the nodal ordering table. The nodal table is scanned from beginning to end causing elements feeding towards the filter 1 32 2 3 10 12 20 22 30 32 40 42 Fig. 4.25: CIRCE output file (filter.nd) START readC I Ine, InF lie) UHILE not end-oF-Flle sBL>e pp~Bmp nodes wrlteClIne;File,ct) sace rest oF stage tn array reset Flag FDR each node In Filter  FDR each element tn Brray SBwe element nodes IF node Is op~3mp output IF IC element  IF IC across op~3mp  set Flag sort nodes wrlteCl lne,Flle,ct) ELSE IF npde Is op~3mp tnput IF SC element  IF SC across op~3mp sort nodes [ | wrlteCl lne,Fl. le.ct) i ELSE IF First node s3me  IF CC element  sort nodes with Flag iteCl Ine,File,cO ELSE IF second node same IF CC element  sort nodes utth Flag [ LirlteCl lne;Flle,ct)  1 write blank line to Ftte.ct readC I Ine, InF lie) END Fig. 4. 26: ORDER2 function flowchart 52 OA (3 0 2 3) 5000 ; BC (2 0) 1.00 ; BS (1 2) #C ; SC (3 10) 1.00 C #C C #C ; SC (10 3) 1 .00 #c c #c c ; OA (12 0 0 10) 5000 ; IC (10 12) 2.00 ; SC (10 12) 3.00 #C C #C C ; SC (10 22) 6.00 #C C #C C ; CC (10 32) 14.00 ; SC (10 42) 12.00 #C C #C C ; OA (22 0 0 20) 5000 ; SC (20 12) 4.00 C #C #C C ; IC (20 22) 5.00 ; OA (32 0 0 30) 5000 ; CC (12 30) 15.00 ; SC (30 22) 13.00 #C C #C C ; IC (30 32) 7.00 ; SC (30 32) 8.00 #C C #C C ; SC (30 42) 11.00 #C C #C C ; OA (42 0 0 40) 5000 ; SC (40 32) 9.00 C #C #C C ; IC (40 42) 10.00 ; Fig. 4.27: CIRCE output file (filter.ct) input to be written before elements feeding towards the filter output for each integrator. The operational amplifier input node is placed first for the IC and the SC elements, while the nodes for the CC elements are sorted so that the first node feeds towards the filter input. A SC element connected from the operational amplifier input to its output is placed after the IC element. 53 The filter.ct file is completed by the ORDER2 function (Fig. 4.27), with the first part written by the INPUT function. The filter.ct and the filter.nd files are the output from the CIRCE program. These files are used by the layout generator program in generating the filter layout. 5. THE LAYOUT GENERATOR (SISCL) 5.1 INTRODUCTION The layout generator program (called SISCL, for Stray Insensitive Switched Capacitor Layout) generates an ISOCMOS layout of the switched capacitor filter in Caltech Intermediate Form (CIF). It uses the information in the filter.nd and the filter.ct files as well as a layout parameter file called filter.com. The operational amplifier CIF code is stored in a file called opamp.cif. The program can generate filter layouts from the four design techniques described in the previous chapter. There are thirteen main functions to the layout generator program and forty-one functions in total. The output file (called filter.cif) is written by three functions. One writes BOX commands, one writes WIRE commands and the last one writes cell calls. This makes it easier to convert the software into doing layouts in another format. The flowchart of the layout generator program is shown in Fig. 5.1. A listing of the software is provided in Appendix D. 5.2 THE OPERATIONAL AMPLIFIER A standard cell operational amplifier is used, which must have certain general features (Fig. 5.2). The operational amplifier data is put into the filter.com file as shown in Fig. 5.3. The power lines must be in metal, and VDD must be on top. The inputs and output must emerge on top 54 55 START INIT - Read the input parameters From the Fiies CRPRRRRY - Generate the capacitor array PREDP - Select the switch-pair and op_amp locations UI RE _ Uire the capacitors to the placed suitch_pairs PLACE - Connect t o operat iona su i t ch~pa i rs 1 amp 1 i F i ers URAPUP - Layout global Features INPUT - Uire the appropriate input stage END Fig. 5.1: SISCL flowchart 56 •cent 2] conC1 1 -con[0] — VDD uid[0] id[] ] f in + i n • xorg 1 CD L n m wid[23 T~ idth Fig. 5.2: Operational amplifier parameters X ( urn) xorg ( X) height ( X) cor,[ 0 ] ( X) ^os[0] ( X) wid[0] ( X) arrayhe ight yorg ( X) width ( X) conf 1 ] ( X) ws[ 1 ] ( X) uldtl] (X) 9rr3ysu) i tch I eveI C X) con[2J ( X) uos[2] ( X) wld[2] ( X) Fig. 5.3: Filter.com file format 57 in polysiliconl of width 2X. The inputs should be grouped together but it does not matter which one is to the left or right. The origin of the operational amplifier (xorg,yorg), can be used to adjust the vertical placement of the cell, as well as the gaps on the left and right sides of the operational amplifier. All the operational amplifier parameters should be in units of X. The operational amplifier used in this thesis is plotted in Fig. 5.4. The operational amplifier CIF code must be symbol #2. The filter layout itself is symbol #1. The first line of the filter.com file consists of the scaling factor X of the fabrication process. This is followed by the height of the capacitor array and the capacitor size at which the capacitor layout strategy changes. The remaining parameters describe the physical shape of the operational amplifier standard cell. 5.3 READING THE INPUT DATA (INIT) The data stored in the filter.nd, filter.ct, and filter.com files is read by the INIT function. The node data is put into a character array called TABLE, which is scanned whenever connections have to be made to the nodes. The operational amplifier parameters are put into a data structure called OPAMP which is used for the operational amplifier placement and wiring. The capacitor and switch data is put into a data structure called CAPAC, which is 58 Fig. 5.4: Operational amplifier layout used to generate the capacitor array, its wiring, and the switches. Each capacitor has its value and nodes saved. The IC elements are given the clocking scheme of the first switch-pair of the SC elements to which integrator it belongs. The SC elements are given the clocking scheme of the second switch-pair of its description. The total number of capacitors and operational amplifiers is also counted here. The flowchart of the INIT function is shown in Fig. 5.5. START Read F11ier.com data Read Filter.nd data readlIInej F 11ter, cO UHILE not end-oF-Flle IF suItch save c I ock IF capacitor s8ue capacitor lvalue sewe nodes set layout style IF su I tched~capac I tor set capacitor type set capacitor clock save additional clock IF Integrating capacitor  set capacitor type IF coup I I. no capacitor set capacitor type Increment capacitor count IF op~Bmp  Increment stage count readCI Ine,F11ter.ct ) FOR e ach capBcI tor IF In tegratlng capacitor FOR each capacitor IF same Input node save clock For IC END Fig. 5.5; INIT function flowchart 60 5.4 THE CAPACITORS 5.4.1 THE CAPACITOR ARRAY The capacitor array layout is done by the CAPARRAY function. It is important to achieve a high accuracy (typically 0.1%) in the capacitor area ratios to ensure a high quality filter response. The time constant r of the integrator is given by r = ^ (5.1) where T is the clockrate. Assuming an accurate clock, the problem is to minimize the capacitor ratio error in the capacitor placement [13][14]. Let the error in capacitor C, be AC1f and let the error in capacitor C2 be AC2. The capacitor ratio is LL . C, ± AC, C2 C2 ± AC2 Kt>'Z} where and C2 are the realized capacitances. This can be rearranged as ct ( ct )( 1 ± AC2/C2 * (5*3) The capacitance C, is equal to (5.4) 61 where e is the Si02 permittivity, A, is the capacitor area, and d is the capacitor plate separation. Assuming that d and e are constant for all capacitors, equation 5.3 can be rewritten as LL _ ( C_L 1 ± AA i /A i . C2 C2 1 ± AA2/A2 (5.5) To satisfy the condition C2 C 2 it is required that (5.6) ^ - ^ (5.7) A, A2 Assuming a systematic error in the capacitor areas, the area error is approximately equal to AA = Pdx (5.8) where P is the capacitor perimeter. Equation 5.7 is then equivalent to A, A2 that is, the perimeter-to-area ratio of the capacitors should be a constant. This can be accomplished by making the smaller capacitor a square, and the larger capacitor an integral number of these squares plus a fractional amount if 62 necessary. This is also convenient from the viewpoint of layout strategy because the capacitors can be placed one square at a time. Typically one capacitor square equals one unit of capac itance. The layout strategy must yield accurate area ratios, good perimeter-to-area ratios, and immunity from the effects of polysilicon1-polysilicon2 mask misalignment. 5.4.2 LAYOUT METHOD The unit capacitor plate is shown in Fig. 5.6. The edges of the polysilicon2 square are each of length E, and the polysiliconl square overlaps it by 1X. Each unit plate is joined to the previous unit plate by a 2X by 2X polysiliconl link. The first unit plate will have ' a polysilicon2 wire joined to it later, when the capacitors are wired together. To provide polysilicon1-polysilicon2 mask misalignment immunity, a similar polysilicon2 link is later put on top of one of the capacitor plates. These extra polysilicon2 links make it impossible to achieve a perfect perimeter-to-area ratio, but it is still possible to maintain accuracy to 0.1%. The perimeter-to-area ratio of a unit size capacitor is then P r = A~ = 4E+4 E2 + 4 (5.10) 63 H = E2+ 4 P = 4E + 4 Fig. 5.6: First capacitor plate E E+2 R+= E2+ 4 P+ - 4E Fig. 5.7: Additional capacitor plates 64 and the ratio of an additional plate (Fig. 5.7) is 4E (5.11) r = E2 + 4 where P+ is the additional perimeter and A+ is the additional area of the added square. The plates join together providing a continuous polysiliconl layer. A fractional capacitance is laid out in one of two possible ways. If the fraction is small, the following method is used. Let the fractional value be f, and the parameters a and b as shown in Fig. 5.8. The perimeter-to-area ratio is b Fig. 5.8: Small fractional add-on capacitor hence and 65 r = . (5.12) and it is required that fA+ = ab (5.13) This gives P. 2a r = it = ab (5'U) b = f (5.15) a = ^ (5.16) Now substituting in the values of A and P A = E2+4 (5.17) P = 4E (5.18) gives a = 2fE (5.19) and 66 b = § + | (5.20) A larger fractional capacitance is laid out as shown in Fig. 5.9, where the parameters a and b are defined. The desired ratio is again (5.21) and fA+ = aE + 2b (5.22) The additional perimeter is P+ = 2E + 2a - 2b + 4 (5.23) — b— 2\ P+ = 2E+2a-2b+4 Fig. 5.9: Large fractional add-on capacitor 67 giving the following relations (5.24) b = E - f(EP+-2A.) 2E+4 (5.25) Now substituting in 5.17 and 5.18 gives a = f(E + 2) - 2 (5.26) b = E - f(E - 2) (5.27) The first style is good for smaller fractions as a will be larger than E if the fraction is larger than .5, and this will not fit in the array. The second style is useful for larger fractions as a must be larger than 2X. This means that the fraction must be larger than 4/(E+2). 5.4.3 CAPACITOR ACCURACY ANALYSIS This layout method results in total immunity to polysilicon1-polysilicon2 mask misalignments of less than 1X. Assume now that all polysiliconl edges are slightly off by an amount x (Fig. 5.10). Let capacitor one have a value of m, and capacitor two have a value of n+m, where m and n are positive integers. The achieved values of these capacitors are Ci = m(E2+4) - 4x (5.28) 68 Fig. 5.10: Polysiliconl systematic error XL, = (n+m)(E2 + 4) - 4x giving the ratio (5.29) C_i = (n+m)(E2+4) ~ 4x C, m(E2+4) - 4x (5.30) or C_i _ + n(E2+4) C, " m(E2+4) - 4x (5.31 ) then 69 CZ/C-TCZ/CT _ _n_ -4x Cz/C, " 1 m+n M m(E2+4) - 4x ' ^'*z> or to maximize this error, let m = 1, and n = °°, then 4x \MC2/C,)\ = zrj^ (5.34) Now it is required that 4x < 0.001 (5.35) E2 + 4 so E2 + 4 x * looo (5'36) For 0.1% accuracy and E = 18X x < T| (5.37) This value of E is picked as it is the minimum width of a switch-pair, and keeping the capacitor plate the same size simplifies the layout. Now assume that all polysilicon2 edges are slightly off by an amount x (Fig. 5.11). Using the same capacitors as in the previous analysis gives 70 X Fig. 5.11: Polysi1icon2 systematic error C, [(E-2x)2+2(2-2x)]+(m+n-2)[(E-2x)2+(2-2x)(2+2x)] [(E-2x)2+2(2-2x)]+(m-1)[(E-2x)2+(2-2x)(2+2x)] (5.38) or C, = 1 + (n-1)[(E-2x)2+(2-2x)(2+2x)3 [(E-2x)2+2(2-2x)]+(m-1)[(E-2x)2+(2-2x)(2+2x)] (5.39) so C2 , ^ / ,\r i 4x2-4x = 1 + (n-l)[m + ( _ A C, E2-4xE+4 since x « E, this can be simplified to C, 4x or Ci = 1 + (n-D(m " p )"1 C, m - 4(x/E2) then A(C2/C,) = ( , " \. )( -If ) m(m+n-1) E2 to maximize this error, let m = 1, and n = e |A(C2/C,)| = fr Now it is required that 4x •^7 <: 0.001 E2 SO 72 For 0.1% accuracy and E = 18X x < j| (5.47) This method is equally tolerant of polysiliconl and polysilicon2 systematic errors. For a 5nm technology, this requires a maximum error of 0.2lym on 45/txm edges. 5.4.4 GENERATING THE ARRAY (CAPARRAY) The capacitors are arranged in an array, their bases on the bottom for later connections. The array height is set by the arrayheight variable in the filter.com file. An initial guess for this variable is the average capacitor value. Each capacitor • can be laid out in two styles: one emphasizes up-down placement of the capacitor plates and the other emphasizes left-right placement. The capacitor size at which the style changes is set by the arrayswitch variable. If a capacitor is larger than this value it is placed with an up-down emphasis. The up-down spread is better for larger capacitors as it keeps them more compact, while the left-right spread is better for the smaller ones, letting them use the space between the larger ones. An initial guess for this value is one-and-a-half times the array height. Each capacitor has its base plate placed along the base of the array. Additional plates are added one at a time for each capacitor until the capacitor is finished or there is 73 no more room. A check is done at the end, and if a capacitor was not finished, an additional space is allocated along the base for the next attempt. This process is repeated until all the capacitors are placed successfully. When all the capacitors are finished, a check is made on the width of the array. If the operational amplifiers will take up more room than the array, the extra space is inserted into the array on one more array generation. The extra polysilicon2 tip on each capacitor is added with a fractional capacitor plate placement if possible, otherwise it is placed after the array generation. If a capacitor of value less than one is given, it will be laid out as a rectangle, causing a more serious perimeter-to-area violation. A sixth order band-pass filter designed by MPR is used in this chapter to demonstrate how the SISCL program works. The data for the filter is in Chapter 6. The flowchart of the array generation function is shown in Fig. 5.12. A layout with the arrayswitch variable set larger than all the capacitors is shown in Fig. 5.13. The width of this array is 706X. A layout with the arrayswitch variable set to 0 is shown in Fig. 5.14 giving an array width of 746X. A layout with the arrayswitch variable set to one-and-a-half times the array heigth is shown in Fig. 5.15, giving a width of 670X. A combination of the two strategies usually yields the smallest layout. 74 START Initialize plate directions. In 11 ial ize GIF File empty capacitor grid FOR each capacitor place First plate on base reduce capacitance value increment horizontally set bounds on capacitor 3rp3y UHILE not Finished  FDR each capacitor  FDR each direct Ion FDR each previous plate restore plate position IF neu plate Fits get plate size -ill array IF neccessSr y update parameters place the plate IF more to do not. yet Finished UHILE more capacitors IF not Finished allocate one extra space IF Srr-Sy not complete call array layout Function again END Fig. 5.12: Array layout flowchart (LAYARRAY) 75 Fig. 5.14: Vertical capacitor spread 77 5.5 SELECTING THE SWITCHES TO BE PLACED (PREOP) The decision of where to place the operational amplifiers and where to place the switches is made by the PREOP function. The width of the capacitor array is again checked against the minimum width of the operational amplifiers and any extra space is inserted between the operational amplifiers. The placement point of the operational amplifier, with the co-ordinates of the three inputs/output, is stored in the OPAMP data structure. The integrating capacitor for each operational amplifier gives the connection point for the inverting input. The switched capacitors connected to the operational amplifier output gives the possible connection points for the output. The closest switched capacitor to the output is selected. The clocking scheme of this switched capacitor is saved so that any switched capacitors with the complementing clocking scheme can be noted. The selected switched capacitor and one switched capacitor with the complementing clocking scheme are then marked for later switch-pair placement. All integrating capacitors have one switch-pair placed below them. The operational amplifier is mirror imaged if the connections are simplified that way. The inputs/output are then moved and this will often greatly simplify the wiring from the switch-pairs to the operational amplifier inputs/output. A flowchart of the PREOP function is shown in Fig. 5.16. 78 START i calculate extra oper61 tonal space between amp I I F I ers FUR e3ch connection IF Input connection FOR each capacitor IF IC sha r i ng connecI i on sdwB connection points LLSE output connection FDR each capacitor IF SC sh i3rlng connection IF closer to connection s8ue connection points s9ue clock I no scheme 1 1 , J i FUR each capacitor and not Flag IF SC shar ing connect IDn IF reuerse clocking scheme set sw 11ch FIag IF op_3mp Is to be reversed FI Ip connection points Increment posit ion END Fig. 5.16; PREOP function flowchart 79 5.6 THE CAPACITOR WIRING 5.6.1 INTRODUCTION All wiring connections are made to the first capacitor plate placed for each capacitor. The base of this plate is wide enough for three connections, of which two connect to the plate. All the wiring is done in an array. The wires are all 2X wide and are separated by 3X. The horizontal wiring is done in metal as they tend to be longer, and the vertical wiring is done in polysilicon. There are five types of connections to be made: the operational amplifier input node, its output node, the shared node at the input, and the two shared nodes at the output. Each type of connection is done by one function, however all the wiring functions are similar. The length of the wire joining the capacitors is found, and a slot is found in the wiring array for it. The wire is then placed in metal. Each capacitor is then checked to see if it should be connected to the wire. The polysilicon wires are then placed and connected to the metal wire. All integrating and switched capacitors have three vertical connections to the wiring, while the coupling capacitors only have two. The integrating and switched capacitors tend to have switches associated with them, causing the need for a third connection. The nodes stored from the filter.nd file are scanned for each connection. If a capacitor should be connected to 80 the wire for a node, it is noted for the wire length, and the vertical connections. The wiring model is shown in Fig. 5.17. The flowcharts for the wiring functions are very similar to that of the first wiring function (WIRE1) which is shown in Fig. 5.18. 5.6.2 THE INPUT NODES (WIRED All the elements connected to the operational amplifier inverting input node are wired up by the WIRE1 function. Each such node connects to one integrating capacitor and any coupling capacitors. If there are no coupling capacitors in the filter, no horizontal metal wire has to be placed, and no vertical polysilicon2 wire is placed at this time. Any vertical connections are made in polysilicon2 and are made Fig. 5.17: Wiring model STRRT in It ial ize the wiring array FDR e8ch input node initialize the wire end~po ints FDR each capacitor  IF SC element do nothinq ELSE IF same First node | sSue pos i. t i on ELSE IF same second node sa^e pos i t ionC r ight ) IF wire is needed F ind w ire 1euel )I ace wire in me tal FOR each capacitor IF connection required IF First node matches s9ve connec t ion Ieuel connec!ion poin t on leFt ELSE connection point right IF not SC and wire needed  place connection END Fig. 5.18: WIRE 1 function flowchart 82 on the left side of the integrating capacitor and on either side of the coupling capacitor, depending on where the node is. The output from the WIRE1 function is shown in Fig. 5.19. 5.6.3 THE OUTPUT NODES (WIRE2) All the elements connected to the operational amplifier output node are wired up by the WIRE2 function. Each such node connects to one integrating capacitor, any coupling capacitors, and any switched capacitors fed by the operational amplifer. All vertical connections are made in polysiliconl. The integrating capacitor is connected on the right side, while the coupling capacitor is connected on either .side, depending on where the node is. The switched capacitor is not connected to the wire as the connection is made later to the switchpair, on the capacitor's right side. The output from the WIRE2 function is shown in Fig. 5.20. 5.6.4 THE SHARED NODE AT THE INPUT (WIRE3) All switched capacitors connected to the operational amplifier inverting input node are wired together now. The integrating capacitor has to be included in the horizontal wiring, as it is later connected to its switch-pair. The switched capacitors are connected with polysiliconl wires. The output from the WIRE3 function is shown in Fig. 5.21. Fig. 5.19; Output from WIRE 1 Fig. 5.20: Output from WIRE2 84 Fig. 5.21: Output from WIRE3 Fig. 5.22: Output from WIRE4 85 5.6.5 THE SHARED NODES AT THE OUTPUT (WIRE4) All the switched capacitors connected to the operational amplifier output node are divided into two groups, according to which clocking scheme they use. Each group is wired separately. The connections are made on the right side of the switched capacitors in polysiliconl. The wire is later connected to the middle of a switch-pair. The output from the WIRE4 function is shown in Fig. 5.22. 5.6.6 THE SWITCH PLACEMENT AND CONNECTIONS (STREAK) The STREAK function places the switch-pairs directly below the integrating capacitors and the switched capacitors selected by the PREOP function. The switches are then connected to the previous capacitor wiring, and the clocks are connected properly for each switch. The switch-pairs are grounded by metal wires connected to the ground line that is later placed directly below the switches. The integrating capacitors and switched capacitors have their central connection going straight to the middle switch connection in polysilicon2. The unconnected third vertical wire for the integrating and switched capacitors is now connected to the switch-pair directly above those elements. If there is an accessible contact above the switch, the software tries not to place another contact before connecting them. A flowchart of the STREAK function is shown in Fig. 5.23 and the output is shown in Fig. 5.24. STRRT FOR each capacitor restore conneciIon level calculate connection points IF SC element IF snitches are to be placed  place su11ch-psIr  ground suiltch~palr IF level Is Just above  place metal uire ELSE place contact place polystl(con uire IF connection is to be made connect to previous ulrlng ELSE IF IC element  place sultch~palr  ground su11 ch~pa I r IF level not Just above  place contacts place polysilicon uire  ELSE place metal uire  connect to capacitor IF shared Input node connect to ulrlng ELSE connect to capacitor END Fig. 5.23; STREAK function flowchart 88 5.7 PLACING AND CONNECTING THE OPERATIONAL AMPLIFIERS 5.7.1 CONNECTING THE INPUT AND OUTPUT NODES (WIRE5) All the connection data for the operational amplifier inputs/output as well as the switch connection points have been previously gathered. The connections for the operational amplifier inverting inputs and outputs are done by the WIRE5 function. These connections are done the same way as they are all connections from one co-ordinate pair to another co-ordinate pair. There will be metal ground and power lines separating the operational amplifiers from the switches so the connections are done in polysiliconl. It is necessary to place a metal-polysiliconl contact below the switch-pairs as a polysiliconl clock line will separate them. The power lines then go below the contact. This provides room for one level of connections between these contacts. If a connection can be done on this level, it is placed entirely in polysiliconl. Some 80% of the connections are placed on this level. If -this is not possible, horizontal metal wires are placed below the power lines and vertical polysiliconl lines connect them to the switch-pair contacts. The wiring is again done in an array. The horizontal bounds are found for each wire and the wire is placed in the first available level. The connection to the switch is always made on one side of the switch, hence there is room to laterally move the 89 connection point by up to 14X. This is done if the vertical connection happens to be directly above another operational amplifer input/output. This reduces the number of wiring levels as wires do not have to go around previous connections as often. The flowchart of the WIRE5 function is shown in Fig. 5.25 and the output is shown in Fig. 5.26. 5.7.2 CONNECTING THE GROUND NODES (WIRE6) The noninverting inputs of the operational amplifiers are always connected to ground. This wiring is done by the WIRE6 function. Usually the connection is a simple vertical polysiliconl wire, but if there is another connection blocking its path, it has to be laterally moved around the connection. The connection is moved until the offending connection no longer blocks the ground wire. The wire is always moved away from the inverting input. Only the horizontal wires are placed here as the vertical connections to the operational amplifiers are done later. If no lateral moves are necessary the function only places contacts on the ground line directly below the input. The output from the WIRE6 function is shown in Fig. 5.27. 5.7.3 PLACING THE OPERATIONAL AMPLIFIERS (AMPSON) The operational amplifiers are now placed directly below the wiring. The vertical placement can be adjusted with the yorg variable in the filter.com file. The connections are then made from the previous wiring to the 90 STRRT initialize the u i r i ng gr i d FDR e3ch connection Find leFt and n iqh t connec t ion IF room below switches ror wire place polyl wire iF neccessSry place switch contact save wiring level 8nd crossing ELSE place normally IF cross i nq shou1d be moved adjust crossing point Find leFt and right points F i nd w i re I eve I IF no crossing ad j us t mien t place wires 8nd contact ELSE pl.9ce extrS loop p18ce w i res 9nd contact s8ve w i ri ng I eve 1 END Fig. 5.25; WIRE5 function flowchart 91 Fig. 5.27; Output from the WIRE6 function 92 operational amplifier inputs and output. The output from the AMPSON function is shown in Fig. 5.28. If the inputs had been reversed on the operational amplifier .the output in Fig. 5.29 would result. 5.8 PLACING THE GLOBAL FEATURES (WRAPUP) The overall features of the layout are placed by the WRAPUP function. The capacitor array and its wiring is placed inside a p-well to isolate it from switch noise. The well is anchored by the ground line to keep the operational amplifier power lines less noisy. The p-well is also placed for the switches,(and is anchored there by the Vss line. The N+ and P+ areas for the switches are then placed. The output line is drawn outside the capacitor array, beyond the ground line. Substrate contacts are also placed on the bottom of the capacitor array p-well, where space permits. The layout then consists of the top capacitor array p-well, above the -p-transistor switches in the substrate. This is followed by the n-transistors in the second p-well and finally the operational amplifiers. This arrangement cuts down the switch noise in the filter by letting the p-wells act as substrate barriers. The output of the WRAPUP function is shown in Fig. 5.30. 96 5.9 LAYOUT OF THE INPUT STAGE There are currently four INPUT functions as each INPUT function connects one of the different input stages. The input stage of Lee (Fig. 4.1) requires one extra switch-pair and some connections to be made. The switch-pair is placed below the second capacitor and is then connected to it. The bottom plate of the second capacitor is connected to ground, and then the input node is connected to the first capacitor and to the extra switch-pair. The final layout of the design is shown in Fig. 5.31. For the Martin case it is only necessary to connect the input node to the first switch-pair. The input stage of Datar and Sedra (Fig. 4.2) is the most complex one. A switch-pair is placed below the extended first capacitor and another one is placed below the second capacitor. The bottom plate of the first capacitor is then grounded. These switch-pairs are connected to the first switched capacitor of the filter, after which the two input switched capacitors are joined together, and connected to the operational amplifier output and noninverting nodes. A single switch is placed below the first capacitor to be used as the filter input switch. The input node is then connected to this switch. The AROMA input stage is very similar to the Martin case. The input node is connected to the input switched capacitor(s). There can be one or three of these depending on whether the filter has a first order stage or a second 98 order stage at the input. If there is a second order stage, two of the capacitors are connected together, sharing a switch-pair. The switched capacitor with the complementing clocking is connected to the input node, as is the first switched capacitor. 6. RESULTS AND DISCUSSION 6.1 A 3825 HZ BANDPASS ELLIPTIC FILTER (LEE) The first filter is a 3825 Hz, sixth-order bandpass filter^ It was designed by MPR by the techniques of Lee. The filter prototype is shown in Fig. 6.1, and the equivalent switched capacitor filter is shown in Fig. 6.2. The SWITCAP file for this filter is shown in Fig. 6.3. The filterl.in file (Fig. 6.4) is an edited copy of the SWITCAP file, having only the input stage elements. The SWITCAP file was run through the CIRCE program resulting in the filterl.nd file (Fig. 6.5) and the filterl.ct file (Fig. 6.6). The filter1.com file is shown in Fig. 6.7. The capacitor array height is set at 13 plates, and the arrayswitch variable is set to 20. The layout is plotted in Fig. 6.8. To simplify the wiring above the operational amplifiers the filterl.ct file was slightly altered into that of Fig. 6.9. This results in the layout of Fig. 6.10 which has simpler connections to the operational ampli f iers. 99 8.479 uH 6,634 uH 916,6 uF 1856 uF 939,1 uF 246,7 uF 218,5 uF 1,822 uH 0,9332 uH 1,913 uH Fig. 6.1: LC prototype of filterl o o Fig. 6.2: SC implementation of filter! OPTIONS ; GRID ; END ; TITLE: EBP 3825 HZ FILTER (SOURCE: MPR TIMING ; /* timing section */ PERIOD 4.166667E-5 ; CLOCK C 1 (0 1/2) ; END ; CIRCUIT ; /* network section */ /* SWITCHES */ 1 4) #CLK ; 2 4) CLK ; 2 5) CLK ; 5 0) #CLK ; 3 6) CLK ; 6 0) #CLK ; 3 7) #CLK ; 7 0) CLK ; 9 15) #CLK ; 9 0) CLK ; 8 10) CLK ; 8 0) #CLK ; 11 12) CLK ; 12 0) 2 13) 13 0) 3 16) 16 0) 15 17 17 0) 18 32 18 0) 15 19 19 0) 20 32 20 0) 21 22 21 0) 23 24 24 0) 14 25 25 0) 26 27 26 0) 28 29 29 0) 30 31 30 0) 31 33 33 0) #CLK CLK ; #CLK #CLK CLK ; #CLK CLK ; #CLK CLK ; #CLK CLK ; #CLK CLK ; CLK #CLK CLK #CLK CLK #CLK CLK #CLK CLK #CLK CLK #CLK CLK #CLK Fig. 6.3: SWITCAP filterl file 103 541 (32 34) CLK ; 542 (34 0) #CLK ; /* CAPACITORS */ C31 (1 2) 1.0 ; C32 (4 0) 4.4220 ; C33 (2 3) 76.4617 ; C34 (5 6) 2 .3438 ; C35 (3 14) 1.1135 ; C36 (7 8) 5 .5920 ; C37 (8 9) 1 .0 ; C38 (10 11) 6.3792 ; C39 (12 13) 81.2592 • C40 (2 15) 16.0117 ; C41 (14 15) 11.0305 • C42 (15 31) 7.0644 ; C43 (19 26) 1.0 ; C44 (20 26) 4.1181 ; C45 (17 21) 11.4885 • C46 (18 21) 1.1911 ; C47 (16 21) 1.0 ; C48 (22 23) 11.8053 • C49 (24 25) 10.4569 • t C50 (27 28) 4.5596 ; C51 (29 30) 33.9825 • C52 (31 32) 32.5742 • C53 (33 34) 1.0 ; C54 (14 32) 1.0 ; /* VOLTAGE-CONTROLLED VOLTAGE SOURCES */ E2 (11 0 0 10) 1000 ; E3 (23 0 0 22) 1000 ; E4 (15 0 0 14) 1000 ; El (3 0 0 2) 1000 ; E5 (28 0 0 27) 1000 ; E6 (32 0 0 31) 1000 ; /* INDEPENDENT VOLTAGE SOURCES */ VI (1 0) 1; END ; ANALYZE SSS ; /* required analysis */ INFREQ 3000 4600 LIN 41 ; SET VI AC 1.0 0.0 ; SAMPLE INPUT HOLD 1 1/2+ ; SAMPLE OUTPUT HOLD 1 1/2- ; PLOT VDB (32) (-6 -96 7) ; END ; END ; Fig. 6.3; SWITCAP filterl file (cont'd) 104 501 (1 4) #CLK ; 502 (2 4) CLK ; C31 (1 2) 1.0 ; C32 (4 0) 4.4220 Fig. 6.4: Filter!.in file 1 32 2 3 10 11 22 23 14 15 27 28 31 32 Fig. 6.5: Filterl.nd file 105 BS (1 4) #CLK ; BS (2 4) CLK ; BC (1 2) 1.0 ; BC (4 0) 4.4220 ; OA (3 0 0 2) 1000 ; IC (2 3) 76.4617 ; SC (2 3) 2.3438 CLK #CLK CLK #CLK ; SC (2 11) 81.2592 CLK #CLK CLK #CLK ; CC (2 15) 16.0117 ; OA (11 0 0 10) 1000 ; SC (10 3) 5.592 0 CLK #CLK #CLK CLK ; IC (10 11) 6.3792 ; SC (10 15) 1.0 CLK #CLK #CLK CLK ; OA (23 0 0 22) 1000 ; SC (22 3) 1.0 CLK #CLK #CLK CLK ; IC (22 23) 11.8053 ; SC (22 15) 11.4885 CLK #CLK #CLK CLK SC (22 32) 1.1911 CLK #CLK #CLK CLK ; OA (15 0 0 14) 1000 ; CC (3 14) 1.1135 ; SC (14 23) 10.4569 CLK #CLK CLK #CLK IC (14 15) 11.0305 ; CC (14 32) 1.0 ; OA (28 0 0 27) 1000 ; SC (27 15) 1.0 CLK #CLK #CLK CLK ; IC (27 28) 4.5596 ; SC (27 32) 4.1181 CLK #CLK #CLK CLK ; OA (32 0 0 31) 1000 ; CC (15 31) 7.0644 ; SC (31 28) 33.9825 CLK #CLK CLK #CLK IC (31 32) 32.5742 ; SC (31 32) 1.0 CLK #CLK CLK #CLK ; Fig. 6.6: Filter!.ct file 2.0 13 20 -3 -4 114 79 79 13 21 95 4 70 75 4 2 4 Fig. 6.7: Filter1.com file 1 07 BS (1 4) #CLK ; BS (2 4) CLK ; BC (1 2) 1.0 ; BC (4 0) 4.4220 ; OA (3 0 0 2) 1000 ; SC (2 3) 2.3438 CLK #CLK CLK #CLK ; IC (2 3) 76.4617 ; SC (2 11) 81.2592 CLK #CLK CLK #CLK OA (11 0 0 10) 1000 ; SC (10 3) 5.5920 CLK #CLK #CLK CLK ; IC (10 11) 6.3792 ; CC (2 15) 16.0117 ; SC (14 23) 10.4569 CLK #CLK CLK #CLK SC (10 15) 1.0 CLK #CLK #CLK CLK ; OA (23 0 0 22) 1000 ; SC (22 3) 1.0 CLK #CLK #CLK CLK ; IC (22 23) 11.8053 ; SC (22 15) 11.4885 CLK #CLK #CLK CLK SC (22 32) 1.1911 CLK #CLK #CLK CLK OA (15 0 0 14) 1000 ; CC (3 14) 1.1135 ; IC (14 15) 11.0305 ; cc (14 32) 1.0 ; OA (28 0 0 27) 1000 ; SC (27 15) 1.0 CLK #CLK #CLK CLK ; IC (27 28) 4.5596 ; SC (31 28) 33.9825 CLK #CLK CLK #CLK SC (27 32) 4.1181 CLK #CLK #CLK CLK OA (32 0 0 31) 1000 ; CC (15 31) 7.0644 ; IC (31 32) 32.5742 ; SC (31 32) 1.0 CLK #CLK CLK #CLK ; Fig. 6.9; Revised filterl.ct file 109 6.2 A 500 HZ LOWPASS ELLIPTIC FILTER (MARTIN) The second filter is a 500 Hz, seventh-order lowpass filter. It was designed by MPR by the techniques of Martin. The filter prototype is shown in Fig. 6.11, and the equivalent switched capacitor filter is shown in Fig. 6.12. The SWITCAP file for this filter is shown in Fig. 6.13. The filter2.in file is empty. The SWITCAP file was run through the CIRCE program resulting in the filter2.nd file (Fig. 6.14) and the filter2.ct file (Fig. 6.15). The filter2.com file is shown in Fig. 6.16. The capacitor array height is set at 8 plates, and the arrayswitch variable is set to 10. The layout is plotted in Fig. 6.17. 370,5 mh! 282,7 mH 315,2 mH 325,0 nF 453,7 nF 427,9 nF 240,5 nF n 47,241 nF — 173,81 nF 79,883 nF -q n Fig. 6.11: LC prototype of filter2 Fig. 6.12: SC implementation of filter2 1 12 OPTIONS ; GRID ; END ; TITLE: LP 500 HZ FILTER (SOURCE: MPR) ; TIMING ; /* timing section */ PERIOD 2.66041667E-05 ; CLOCK CLK 1(0 1/2) ; END ; CIRCUIT ; /* network section */ /* SWITCHES */ SOI (1 2) #CLK ; S02 (2 C ) CLK ; S15 (11 0) CLK ; S16 (10 11) #CLK ; S18 (13 0) CLK ; S17 (12 13) #CLK ; S25 (21 0) CLK ; S26 (21 22) #CLK ; S27 (20 23) CLK ; S28 (23 0) #CLK ; S35 (31 0) CLK ; S36 (30 31) #CLK ; S37 (32 33) #CLK ; S38 (33 0) CLK ; S45 (41 0) CLK ; S46 (41 42) #CLK ; S47 (40 43) CLK ; S48 (43 0) #CLK ; S55 (51 0) CLK ; S56 (50 51) #CLK ; S57 (52 53) #CLK ; S58 (53 0) CLK ; S65 (61 0) CLK ; S66 (61 62) #CLK ; S67 (60 63) CLK ; S68 (63 0) #CLK ; S75 (71 0) CLK ; S76 (70 71) #CLK ; S77 (72 73) #CLK ; S78 (73 0) CLK ; CAPACITORS */ CA1 (11 21) 1.960 CA2 (21 31; 1.000 CA3 (31 41) 2.500 CA4 (41 51) 1.000 CA5 (51 61) 3.333 CA6 (61 71; 1.000 CB1 (12 io; 15.444 Fig. 6.13: SWITCAP filter2 file 1 13 CB2 (22 20) 28.169 CB3 (32 30) 22.134 CB4 (42 40) 32.237 CB5 (52 50) 30.845 CB6 (62 60) 34.235 CB7 (72 70) 12.303 CC1 (12 30) 1.000 ; CC2 (10 32) 2.992 ; CC3 (32 50) 2.247 ; CC4 (30 52) 19.667 CC5 (52 70) 1.085 ; CC6 (50 72) 10.234 CD1 (13 23) 1.091 ; CD2 (23 33) 1.666 ; CD3 (33 43) 1.000 ; CD4 (43 53) 3.501 ; CD5 (53 63) 1.000 ; CD6 (63 73] 2.830 ; CE ( 2 13) 2.162 ; CF (11 13) 1.080 ; CG (71 73) 1.000 ; /* VOLTAGE-CONTROLLED VOLTAGE SOURCES */ E02 (20 0 0 22) 1000 E05 (50 0 0 52) 1000 E03 (30 0 0 32) 1000 E04 (40 0 0 42) 1000 E06 (60 0 0 62) 1000 E01 (10 0 0 12) 1000 E07 (70 0 0 72) 1000 /* INDEPENDENT VOLTAGE SOURCES */ VI (1 0) ; END ; ANALYZE SSS ; /* required analysis */ INFREQ 3000 4600 LIN 41 ; SET VI AC 1.0 0.0 ; SAMPLE INPUT HOLD 1 1/2+ ; SAMPLE OUTPUT HOLD 1 1/2- ; PLOT VDB (70) (-6 -96 7) ; END ; END ; Fig. 6.13; SWITCAP filter2 file (cont'd) 1 70 1 12 10 22 20 32 30 42 40 52 50 62 60 72 70 Fig..6.14: Filter2.nd file 115 OA (10 0 0 12) 1000; SC (12 1) 2 .162 #CLK CLK #CLK CLK; IC (12 10) 15.444; SC (12 10) 1.080 #CLK CLK #CLK CLK; SC (12 20) 1.091 #CLK CLK CLK #CLK; CC (12 30) 1.000; OA (20 0 0 22) 1000; SC (22 10) 1.960 #CLK CLK #CLK CLK; IC (22 20) 28.169; SC (22 30) 1.000 #CLK CLK #CLK CLK; OA (30 0 0 32) 1000; CC (10 32) 2.992; SC (32 20) 1.666 #CLK CLK CLK #CLK; IC (32 30) 22.134; SC (32 40) 1.000 #CLK CLK CLK #CLK; CC (32 50) 2.247; OA (40 0 0 42) 1000; SC (42 30) 2.500 #CLK CLK #CLK CLK; IC (42 40) 32.237; SC (42 50) 1.000 #CLK CLK #CLK CLK; OA (50 0 0 52) 1000; CC (30 52) 19.667; SC (52 40) 3.501 #CLK CLK CLK #CLK; IC (52 50) 30.845; SC (52 60) 1.000 #CLK CLK CLK #CLK; cc (52 70) 1.085; OA (60 0 0 62) 1000; SC (62 50) 3.333 #CLK CLK #CLK CLK; IC (62 60) 34.235; SC (62 70) 1.000 #CLK CLK #CLK CLK; OA (70 0 0 72) 1000; CC (50 72) 10.234; SC (72 60) 2.830 #CLK CLK CLK #CLK; IC (72 70) 12.303; SC (72 70) 1.000 #CLK CLK #CLK CLK; Fig. 6.15; Filter2.ct file 2.0 8 10 -3 -4 114 79 79 13 21 95 4 70 75 4 2 4 Fig. 6.16: Filter2.com file 1 17 6.3 A 3 KHZ - 5 KHZ BAND-ELIMINATION ELLIPTIC FILTER (AROMA) The third filter is a 3 kHz - 5 kHz, eigth-order band-elimination filter. It was designed by the AROMA program. The switched capacitor filter is shown in Fig. 6.18. The SWITCAP file for this filter is shown in Fig. 6.19. The filter3.in file is empty. The SWITCAP file was run through the CIRCE program resulting in the filter3.nd file (Fig. 6.20) and the filter3.ct file (Fig. 6.21). The filter3.com file is shown in Fig. 6.22. The capacitor array height is set at 8 plates, and the arrayswitch variable is set to 6. To simplify the capacitor wiring, the twenty-first and twenty-second capacitors were reversed. This removes one wiring level. The final layout is plotted in Fig. 6.23. 5fei< fe§fei'§fe 3fe<§fe§fe' fesfei'fei' 7P?Hi 2^ 1=0 > Y Y gfelfe'?l sfei' gfel' I '^Hi' ^i' 119 OPTIONS ; GRID ; END ; TITLE: EBE 3.3 kHZ - 4.5 kHZ FILTER (SOURCE: AROMA) ; TIMING ; /* timing section */ PERIOD 4.166667E-5 ; CLOCK C 1 (0 1/2) ; END ; /* switched capacitor sub-circuit */ SUBCKT (1 4) swc (K:phil K:phi2 K:phi3 K:phi4 P:capl) ; 51 (1 2) phil ; 52 (2 0) phi2 ; 53 (3 4) phi3 ; 54 (3 0) phi4 ; Cl (2 3) capl ; END ; CIRCUIT ; /* network section */ Xa (1 10) swc (C #C C |C 1.00) ; Xb (1 20) swc (C #C #C C 13.40) ; Xc (1 20) SWC (#C C #C C 13.40) ; Xe (11 20) SWC (C #C #C C 8.50) ; Xf (21 20) SWC (C #C #C C 1.00) ; Xg (21 20) swc (#C C #C C 1.40) ; Xd (21 10) swc (C #C C #C 1.60) ; C (11 10) 3.30 ; C (21 20) 15.90 ; Xh (21 30) swc (C #C C #C 1.00) ; Xi (21 40) SWC (C #C #C C 3.60) ; Xj (21 40) swc (#C C #C C 3.60) ; Xk (31 40) swc (C #C #C C 2.40) ; XI (41 40) swc (C #C #C C 1.00) ; Xm (41 40) swc (#C C #C C 2.00) ; Xn (41 30) SWC (C #C C #C 2.10) ; C (31 30) 4.00 ; C (41 40) 2.30 ; XO (41 50) SWC (C #C C #C 2.10) ; Xp (41 60) SWC (C #C #C C 8.60) ; Xq (41 60) SWC (#C C #C C 8.60) ; Xr (51 60) SWC (C #C #C C 2.80) ; Xs (61 60) SWC (C #C #C C 1.00) ; Xt (61 60) SWC (#C C #C C 2.00) ; Xu (61 50) swc (C #C C #C 1.00) ; C (51 50) 5.50 ; C (61 60) 6.90 ; Xv (61 70) SWC (C #C C #C 1.30) ; Xw (61 80) SWC (C #C #C C 28.20) ; Fig. 6.19: SWITCAP filter3 file 120 XX (61 80) SWC (#C C #C C 28.20) ; Xy (71 80) swc (C #C #C C 8.40) ; XZ (81 80) swc (C #C #C C 1.00) ; XI (81 80) SWC (#C C #C C 1.40) ; X2 (81 70) swc (C #C C #C 1.10) ; C (71 70) 3.50 ; C (81 80) 26.90 ; /* VOLTAGE-CONTROLLED VOLTAGE SOURCES */ El (11 0 0 10) 1000 E3 (31 0 0 30) 1000 E4 (41 0 0 40) 1000 E6 (61 0 0 60) 1000 E5 (51 0 0 50) 1000 E7 (71 0 0 70) 1000 E2 (21 0 0 20) 1000 E8 (81 0 0 80) 1000 /* INDEPENDENT VOLTAGE SOURCES */ VI (1 0) ; END ; ANALYZE SSS ; /* required analysis */ INFREQ 1000 10000 LIN 40 ; SET VI AC 1.0 0.0 ; SAMPLE INPUT HOLD 1 1/2+ ; SAMPLE OUTPUT HOLD 1 1/2- ; PLOT VDB (81) (-6 -96 7) ; END ; END ; Fig. 6.19: SWITCAP filter3 file (cont'd) 1 81 1 10 11 20 21 30 31 40 41 50 51 60 61 70 71 80 81 Fig. 6.20: Filter3.nd file 122 OA (11 0 0 10) 1000 ; SC (10 1) 1.00 C #C C #C ; IC (10 11) 3.30 ; SC (10 21) 1.60 C #C C #C . 1 OA (21 0 0 20) 1000 ; SC (20 1) 13.40 #C C C #C ; SC (20 1) 13.40 #C C #c c ; SC (20 11) 8.50 #C C c #c ; IC (20 21) 15.90 ; SC (20 21) 1.00 #C C c #c • / SC (20 21) 1.40 #C C #c c • OA (31 0 0 30) 1000 ; SC (30 21) 1.00 C #C c #c 7 IC (30 31) 4.00 ; SC (30 41) 2.10 C #C c #c • OA (41 0 0 40) 1000 ; SC (40 21) 3.60 #C C c #c • 9 SC (40 21) 3.60 #C C #c c 7 SC (40 31) 2.40 #C C c #c • IC (40 41) 2.3 0 ; SC (40 41) 1.00 #C C c #c • SC (40 41) 2.00 #C C #c c 7 OA (51 0 0 50) 1000 ; SC (50 41) 2.10 C #C c #c • IC (50 51) 5.50 ; SC (50 61) 1.00 C #C c #c • OA (61 0 0 60) 1000 ; SC (60 41) 8.60 #C C c #c • SC (60 41) 8.60 #C C #c c 7 SC (60 51) 2.80 #C C c #c • IC (60 61) 6.90 ; SC (60 61) 1.00 #C C c #c • SC (60 61) 2.00 #C C #c c 7 OA (71 0 0 70) 1000 ; SC (70 61) 1.30 C #C c #c • IC (70 71) 3.50 ; SC (70 81) 1.10 C #C c #c • 9 Fig. 6.21; Filter3.ct file 123 OA (81 0 0 80) 1000 ; SC (80 61) 28.20 #C C C #C ; SC (80 61) 28.20 #C C #C C ; SC (80 71) 8.40 #C C C #C ; IC (80 81) 26.90 ; SC (80 81) 1.00 #C C C #C ; SC (80 81) 1.40 #C C #C C ; Fig. 6.21: Filter3.ct file (cont'd) 2.0 8 6 -3 -4 114 79 79 13 21 95 4 70 75 4 2 4 Fig. 6.22: Filter3.com file Fig. 6.23: Filter3 layout to 125 6.4 DISCUSSION The capacitor array usually takes up at least half the total layout area. If all the capacitor values are of the same general value, then the array will be very dense as each capacitor gets an equal share of the area (Fig. 6.17). If the filter has integrators with large Q factors at the beginning and end, large capacitor spreads result for these integrators. These capacitors will spread out, but an emptier area usually results in the middle of the capacitor array (Fig. 6.23). The array height is a very important variable for the minimization of the capacitor area. Each filter tends to have an optimum height. If the height is set larger than this, there will be excess space in the array. If the height is set too small, the filter will be longer, and space will be inserted between the operational amplifiers. The arrayswitch variable can be used to fine tune the layout. Sometimes it is necessary to ensure that a capacitor stays as low as possible, to allow a large capacitor more room on top. The capacitor plate size and the plate separation can be easily adjusted in the software to larger values. The capacitor wiring works well. By keeping the switches directly below the capacitors the vertical connections are greatly simplified. A typical layout usually requires six or seven levels of wiring. It is usually possible to improve the wiring by one level by using more complex wiring, gaining 5X. 126 The switch-pairs are always placed for full switch-sharing. The main drawback of this placement technique is the large number of crossings between the clock lines and the signal paths, causing noise. There tends to be some unnecessary contact in the wiring to the switches. These can be eliminated with a bit more sophisticated software. The wiring to the operational amplifiers usually takes one wiring level. There has to be some separation between the operational amplifiers and the p-well which gives room for one wiring level. If there is more than one level of wiring here, the layout can usually be simplified by moving some of the capacitors in the filter.ct file. This also provides a means of shortening certain wiring connections if it is desired. The p-wells have many substrate contacts, and the operational amplifier VDD line provides the substrate contacts for the pMOS transistors on the other side of the intervening p-well. These substrate connections work, however it would be desirable to have them closer to the p-transistors. Overall the layout is very neat and elegant because it is very ordered. Modifications are easy to make by moving capacitors in the filter.ct file, and it is possible to change the wiring order by moving nodes in the filter.nd file. This should not be done unless one understands how the filter.nd file is arranged. 1 27 The width of the layout is minimum. The height of the layout tends to be some 5X more than minimum. Overall the programs produce an excellent output. These layouts compare very well with filter layouts done by MPR. A filter layout can be generated in under three minutes using these programs, by someone who has never done a filter layout before. 7. CONCLUSION Two programs have been developed to generate automatically the layout of strays insensitive switched capacitor filters with full switch-sharing and using standard-cell operational amplifiers. The first program (CIRCE), reformats a SWITCAP filter description into one suitable for a direct layout. The second program (SISCL), generates the layout of the filter in CIF. These programs were tested by generating layouts of filter designs from Microtel Pacific Research Ltd. and from the AROMA program. The layouts seem satisfactory in terms of compactness and in flexibility of doing modifications. A chip is being fabricated to test the performance of a filter layout. It is hoped that these programs will be developed into a useful design tool for the layout of strays insensitive switched capacitor filters. 7.1 FUTURE WORK These layouts suffer from a number of undesirable effects. It would be better to keep the operational amplifiers further away from the switches and to remove all crossings of the analog and digital busses. Noise tends to be a very serious problem. The restriction of only allowing the one clock to feed charge into the operational amplifiers should also be removed. 128 129 One way of solving these problems is to move the operational amplifiers above the capacitor array and to connect them directly to the integrating capacitors. This will provide enough distance from the switches. The switches can be arranged into standard cells consisting of four switch-pairs. Two connect to the operational amplifier input and two connect to the output. The proposed cell of Fig. 7.1 also has no crossings of the analog signal paths and the digital clocks. These cells can be placed below the capacitor wiring. The cell has six inputs/outputs. Four connect to the shared nodes of the switched capacitors and the middle two connect to the operational amplifier input and output nodes. If the integrating capacitor is placed directly above the Fig. 7.1: Switch cell 130 switch cell, the connections will be very simple. Another approach is to generate integrator layouts as standard cells, and then to connect them into the filter. Coupling capacitors and varying capacitor sizes can cause problems with this approach. There are two recent conference publications that use this approach [15] [16]. REFERENCES J. T. Caves, M. A. Copeland, C. F. Rahim, and S. D. Rosenbaum, "Sampled Analog Filtering Using Switched Capacitors as Resistor Euivalents," IEEE J. Solid-State Circuits, vol. SC-12, no. 6, pp. 592-599, 1977. B. J. Hostica, R. W. Broderson, and P. R. Grey, "MOS Sampled Data Recursive Filters Using Switched Capacitor Integrators," IEEE J. Solid-State Circuits, vol. SC-12, no. 6, pp. 600-608, 1977. R. W. Broderson, P. R. Gray, and D: A. Hodges, "MOS Switched-Capacitor Filters," Proc. IEEE, vol. 67, no. 1, pp. 61-75, 1979. P. E. Fleischer, and K. R. Laker, "A Family of Active Switched Capacitor Biquad Building Blocks," Bell System Technical Journal, vol. 58, no. 10, pp. 2235-2269, 1979. K. Martin, and A. S. Sedra, "Exact Design of Switched-Capacitor Bandpass Filters Using Coupled-Biquad Structures," IEEE Trans. Circuits Syst., vol. CAS-27, no. 6, pp. 469-474, 1980. K. Martin, "Improved Circuits for the Realization of Switched-Capacitor Filters," IEEE Trans. Circuits Syst., vol. CAS-27, no. 4, pp. 237-244, 1980. M. S. Lee, G. C. Temes, C. Chang, and B. Ghaderi, "Bilinear Switched-Capacitor Ladder Filters," IEEE Trans. Circuits Syst., vol. CAS-28, no. 8, pp. 811-821, 1981. R. B. Datar, and A. S. Sedra, "Exact Design of Strays-Insensitive Switched-Capacitor Ladder Filters," IEEE Trans. Circuits Syst., vol. CAS-30, no. 12, pp. 888-897, 1983. E. Sanchez-Sinencio, and J. Ramfrez-Angulo, "AROMA: An Area Optimized CAD Program for Cascade SC Filter Design," IEEE Trans. Computer-Aided Design, vol. CAD-4, no. 3, pp. 296-303, 1985. P. E. Allen, and E. SSnchez-Sinencio, "Switched-Capacitor Circuits," Van Nostrand Reinhold, New York, 1984. C. Mead, and L. Conway, "Introduction to VLSI Systems," Addison-Wesley Publishing Company, Reading, Massachusetts, 1980. B. J. Sheu, and C. Hu, "Switch-Induced Error Voltage on a Switched Capacitor," IEEE J. Solid-State Circuits, vol. SC-19, no. 4, pp. 519-525, 1984. J. L. McCreary, "Matching Properties, and Voltage and Temperature Dependence of MOS Capacitors," IEEE J. Solid-State Circuits, vol. SC-16, no. 6, pp. 608-615, 1981. 131 132 J. Shyu, G. C. Temes, and K. Yao, "Random Errors in MOS Capacitors," IEEE J. Solid-State Circuits, vol. SC-17, no. 6, pp. 1070-1075, 1982. T. Pletersek, J. Trontelj, L. Trontelj, I. Jones, G. Shenton, Y. Sun, "Analog LSI Design With CMOS Standard Cells," Proc. CICC, 1985, pp. 479-483. P. E. Allen, E. R. Macaluso, S. F. Bily, and A. Nedungadi, "AIDE2: An Automated Analog IC Design System," Proc. CICC, 1985, pp. 498-501. S. C. Fang, "SWITCAP User's Guide," Department of Electrical Engineering, Columbia University, October, 1982. APPENDIX A: ISOCMOS DESIGN RULES The following simplified design rules were used in the layout. LAYOUT DESIGN TOLERANCES Device Active Areas Conductor width Conductor Separation N+ to P+ in same substrate P+ active in N- substrate to p-well N+ active in N- substrate to p-well P-well Width Overlap on active Separation (different potentials) Polysilicon1 Conductor width Conductor separation Transistor channel overlap N+/P+ Overlap on active Distance to P+/N+ active Distance to P+/N+ channel gate Polysi1icon2 Conductor width Conductor separation P1 overlap for precision capacitance MINIMUM VALUE 2X 2X 3X 5X 4X 3X 2X 8X 2X 2X 2X 2X 2X 3X 2X 2X IX 1 33 134 LAYOUT DESIGN TOLERANCES Cuts Size Active overlap P1 overlap P2 overlap Metal overlap Separation from P1/P2 Metal Conductor width Conductor separation Passivation Distance inside pad edge MINIMUM VALUE 2X*2X 1X 1X 1 .5X 1X 2X 2X 2X 2X There should be a p-well substrate contact every 60X. There should be an N- substrate contact every 120X. APPENDIX B: SWITCAP SWITCAP is a general purpose simulation program for the analysis of switched capacitor networks developed at Columbia University [17]. Features include switching intervals, network elements and frequency domain analysis among others. The program uses a number of charge variables as the network variables for analysis. A SWITCAP input file consists of a TIMING block specifying the clocks used, an optional SUBCKT block containing any subcircuit calls, a CIRCUIT block containing the network elements, and an ANALYZE block specifying the input voltage, the analysis desired and the output format. The only network elements allowed are switches, capacitors, voltage-controlled voltage sources, and independent voltage sources. A network element statement follows the following general format: <r> <element name> (<node list>) <element value> ; where <r> is a keycharacter indicating the element type. The keycharacter designations are S(switch), C(capacitor), E(voltage-controlled voltage source), and V(independent voltage source). <element name> is a string of alphanumeric characters less 135 136 than seven characters long serving as a label for the element. <node list> is a list of nodes to which the element is connected. A node name is a string of seven or less alphanumeric characters. The ground node is always 0 (the digit zero). <element value> gives the "value" of the element that is appropriate to the element. A switch may also be clocked by the complement of a clock defined in the TIMING block. This is done by adding the character # in front of the clock name for the switch. A sample SWITCAP input file of a switched capacitor integrator is shown in Fig. B.1. 1 37 OPTIONS; REPORT; CHKCLK; END; TITLE: Sample SWITCAP file /* timing section */ TIMING; PERIOD le-6; CLOCK c 1 (0 3/8); END; /* network section */ CIRCUIT; /* switches */ 51 (1 2) c; 52 (2 3) #c; /* period of time base */ /* clock definition */ /* capacitors */ CI (2 0) 0.100; C2 (1 3) 0.233; C3 (3 4) 0.952; /* voltage-controlled voltage sources */ /* El (4 0 0 3) 10000; /* independent voltage source */ VI (1 0); /* value given in analysis section */ END; /* analysis section */ ANALYZE SSS; /* sinusoidal steady-state analysis */ INFREQ 0.01 10000 LOG 12; /* sweep in 12 steps */ SET VI AC 1.0 0.0; /* amplitude and phase */ PRINT VR(4) VI(4); * real and imaginary */ PLOT VDB(4) VP(4); /* magnitude and phase */ END; END; Fig. B.1: Sample SWITCAP file APPENDIX C: THE CIRCUIT EXTRACTOR LISTING The circuit extractor requires the filename and filename.in files to run. It is run as follows: CIRCE filename style <CR> where style refers to one of the following design techniques: A(AROMA), L(Lee), M(Martin), and S(Datar & Sedra). The single character is used. It produces two output files called filename.nd and filename.ct. 138 139 #include <stdio. h> #define LENGTH 72 /* BUFFER LENGTH */ #define WORD 8 /* IDENTIFIER LENGTH */ #define SIZE 50 /* SIZE OF TABLE ARRAY */ #define ZERO 0 /* ZERO CONSTANT */ #define ONE 1 /* ONE CONSTANT */ #define TWO 2 /* TWO CONSTANT */ #define THREE 3 /* THREE CONSTANT */ #define FOUR 4 /* FOUR CONSTANT */ #define EOW •\0« '\n' /* END OF WORD */ #define EOL /* END OF LINE */ char table[2][SIZE][WORD] char firstnode[WORD] ; char midnode[WORD] ; char lastnode[WORD] ; /* SUBSTITUTION TABLE */ /* FILTER INPUT NODE */ /* FILTER LINK NODE */ /* FILTER OUTPUT NODE */ char *psub = "SUBCKT" ; /* SUBCKT POINTER */ char *pcir = "CIRCUIT" ; /* CIRCUIT POINTER */ char *pana = "ANALYZE" ; /* ANALYZE POINTER */ char *pend = "END" ; /* END POINTER */ char *node = "!AA" ; /* NEW NODE POINTER */ char *oa — "OA (" ; /* OPERATIONAL AMP */ char *bs = "BS (" ; /* BUFFER SWITCH */ char *bc SB "BC (" ; /* BUFFER CAPACITOR */ char *sc = "SC (" ; /* SWITCHED CAPACITOR */ char *ic = "IC (" ; /* INTEGRATING CAPACITOR char *cc = "CC (" ; /* COUPLING CAPACITOR */ /**************************************** /* */* MAIN PROGRAM — CIRCUIT EXTRACTOR */ /*/***********************************************************/ main(argc,argv) /* FETCH C SHELL PARAMETERS */ int argc ; /* NUMBER OF ARGUMENTS */ char *argv[] ; /* ARGUMENT POINTERS */ { char head ; /* INPUT SECTION STYLE */ char *fp ; /* FILE POINTER */ char st ; /* CHARACTER STORAGE */ int i ; /* ITERATION VARIABLE */ FILE *fdin ; /* .IN FILE DESCRIPTOR */ FILE *fdct ; /* .CT FILE DESCRIPTOR */ FILE *fdnd ; /* .ND FILE DESCRIPTOR */ FILE *fdsw ; /* SWITCAP FILE DESCRIPTOR */ FILE *fopen() ; /* FILE OPEN FUNCTION */ 140 /* STORE THE INPUT SECTION STYLE */ st = *argv[2] ; head = ((st>='a» && st<=»z') ? st-'a'+'A' st) /* OPEN SWITCAP INPUT FILE FOR READING */ fp = argvfl] ; fdsw = fopen(fp,"r") ; /* OPEN THE .IN FILE FOR READING for (i=0; *(fp+i)!=EOW; i++) ; = t > */ *(fp+i+0) *(fp+i+l) *(fp+i+2) *(fp+i+3) fdin = fopen(fp,"r") = 'i' = 'n' = EOW /* OPEN THE .CT FILE *(fp+i+l) = 'c' ; *(fp+i+2) = 't' ; fdct = fopen(fp,"w") FOR WRITING */ /* OPEN THE .ND FILE FOR WRITING */ *(fp+i+l) = 'n' ; *(fp+i+2) = 'd1 ; fdnd = fopen(fp,"w") ; reduce(fdsw) replace() ; isolate(fdin) stages() ; /* CLEAN UP THE INPUT FILE */ /* SUBSTITUTE ALL SUBCKT CALLS */ /* ISOLATE INPUT SECTION */ /* GROUP INTO INTEGRATORS */ } /* if if if if PROCESS THE APPROPRIATE INPUT SECTION */ (head=='L') inputl(fdct) ; input2(fdct) ; input3(fdct) ; input4(fdct) ; (head=='M') (head=='S«) (head=='A') orderl(fdnd) order2(fdct) fclose(fdin) ; fclose(fdsw) ; fclose(fdnd) ; fclose(fdct) ; /* SORT INTEGRATORS */ /* SORT ELEMENTS AND NODES */ /* CLOSE .IN FILE */ /* CLOSE SWITCAP FILE */ /* CLOSE .ND FILE */ /* CLOSE .CT FILE */ /******************************************** /* */ /* REDUCE FUNCTION — Clean Up The Input File */ 141 /* */ /* The reduce function removes any comments and blank */ /* lines in the SWITCAP input file. It also capitalizes */ /* all characters and ensures that there is only one */ /* statement per line. The filter input and output nodes */ /* are saved here. */* */**************************************** reduce(fdsw) FILE *fdsw ; /* SWITCAP INPUT FILE */ { Char buf[LENGTH] ; /* LINE BUFFER */ FILE *fdto ; /* OUTPUT FILE */ FILE *fopen() ; * FILE OPEN FUNCTION */ fdto - fopenC'SCINP", "w") ; /* OPEN OUTPUT FILE */ /* READ LINES UNTIL A SUBCKT OR THE CIRCUIT SECTION */ do { readclean(fdsw,buf) ; } while (!same(buf,psub) && !same(buf,pcir)) ; /* WRITE LINES TO OUTPUT FILE UNTIL ANALYZE SECTION */ /* THE INPUT NODE IS TAKEN FROM THE VOLTAGE SOURCE */ while (!same(buf,pana)) { if (buf[0]!=EOL) if (buf[0]=='V) getnode(buf,ONE,firstnode) ; else writeline(fdto,buf) ; readclean(fdsw,buf) ; ) /* NOTE OUTPUT NODE FROM PRINT/PLOT STATEMENT */ while (buf[0]!=EOF) { if (buf[0]=='P') getnode(buf,ONE,lastnode) ; readclean(fdsw,buf) ; } } fclose(fdto) ; /* CLOSE OUTPUT FILE */ /*********************************************** /* */* REPLACE FUNCTION — Insert Subckts Into Circuit */ /*/* The replace function inserts any subcircuits into */ /* the CIRCUIT block. */*/************************************************* 142 replace() { char buf[LENGTH] ; char subname[WORD] char callname[WORD] int count = 0 ; int ch ; FILE *fdfrom ; FILE *fdto ; FILE *fdsub ; FILE *fopen() ; /* /* /* /* /* /* /* /* /* LINE BUFFER */ SUBCIRCUIT NAME */ SUBCIRCUIT CALL NAME */ COUNTING INTEGER */ CHARACTER STORAGE */ FILE BEING READ FROM */ FILE BEING WRITTEN TO */ SUBCIRCUIT STORAGE FILE */ FILE OPEN FUNCTION */ fdfrom = fopenC'SCINP'V'r") ; /* OPEN INPUT FILE */ fdto = fopen("SCINQ","W") ; /* OPEN OUTPUT FILE */ /* REPLACE THE SUBCIRCUITS ONE AT A TIME */ /* UNTIL THERE ARE NO MORE SUBCKT BLOCKS */ readline(fdfrom,buf) ; while (same(buf,psub)) /* GET THE SUBCIRCUIT NAME */ { getval(buf,subname) ; empty(ZERO) ; /* WRITE THE SUBCKT BLOCK TO A SPARE FILE WHILE */ /* TABULATING ALL PARAMETERS INTO TABLE[0] */ fdsub = fopenC'SUBC", "w") ; while (!same(buf,pend)) writeline(fdsub,buf) ; fclose(fdsub) ; /* SCAN THE REST OF THE FILE FOR SUBCIRCUIT CALLS */ do ( readline(fdfrom,buf) ; if (buf[0] == 'X') /* GET THE CALLED SUBCIRCUIT1S NAME */ ( getval(buf,callname) ; { writeline(fdsub,buf) tabulate(buf,ZERO) ; readline(fdfrom,buf) /* COMPARE THE NAMES */ if (same(subname,callname)) /* IF THE SAME, TABULATE CALLING */ /* PARAMETERS INTO TABLE[1] */ { empty(ONE) ; tabulate(buf,ONE) ; 143 } /* INSERT ANY ADDITIONAL NODES */ fill() ; /* REPLACE THE CALL BY THE SUBCIRCUIT */ writesub(fdto) ; } else writeline(fdto,buf) ; } else if (buf[0] != EOF) writeline(fdto,buf) ; ) while (buf[0] != EOF) ; /* CLOSE INPUT AND OUTPUT FILES */ fclose(fdto) ; fclose(fdfrom) ; /* REVERSE THE INPUT AND OUTPUT FILES */ /* FOR THE NEXT PASS *if (count % 2) { fdfrom = fopenC'SCINP", "r") ; fdto = fopen("SCINQ","w") ; } else { fdfrom = fopen("SCINQH,"r") ; fdto = fopen("SCINP","w") ; } count++ ; readline(fdfrom,buf) ; } /* CLOSE INPUT AND OUTPUT FILES */ fclose(fdfrom) ; fclose(fdto) ; /* MAKE SURE THAT THE FINAL OUTPUT */ /* FILE IS THE EXPECTED ONE */ if (!(count % 2)) { fdfrom = fopen("SCINP","r") ; fdto = fopen("SCINQ","w") ; /* COPY INPUT FILE TO OUTPUT FILE */ while ((ch=getc(fdfrom))!=EOF) putc(ch,fdto) ; fclose(fdfrom) ; fclose(fdto) ; ) /*****************************^ /* */ /* WRITESUB FUNCTION — Inserts Subcircuit */*/* The writesiib function copies the subcircuit */ /* currently stored into the output file. The parameters */ /* are replaced by those of the calling statement. */ 144 /* V /***********************************************************/ writesub(fdto) FILE *fdto ; /* OUTPUT FILE */ { Char 1in[LENGTH] ; /* SUBCIRCUIT LINE BUFFER */ Char buf[LENGTH] ; * LINE BUFFER FOR OUTPUT */ char par[WORD] ; /* PARAMETER BUFFER */ int a,b,i,j ; /* INDEX PARAMETERS */ int locn ; * INDEX TABLE LOCATION */ int flag ; * SEARCH SUCCESS FLAG */ FILE *fdsub ; /* SUBCIRCUIT FILE */ FILE *fopen() ; * FILE OPEN FUNCTION */ /* PROCESS EACH LINE IN THE SUBCIRCUIT FILE IN TURN */ fdsub = fopenC'SUBC", "r") ; do { readline(fdsub,lin) ; /* DO NOT PROCESS HEADER AND END STATEMENTS */ if (!same(lin,pend) && !same(lin,psub) && lin[0]!=EOF) /* COPY THE FIRST PART OF THE LINE */ { a = b = 0 ; do { buf[a++] = lin[b] ; } while (lin[b++]!='(') ; /* REPLACE ALL PARAMETERS */ do ( while (lin[b]==' •) buf[a++] = lin[b++] ; /* STORE THE PARAMETER */ i = 0 ; while (lin[b]!=' • && lin[b]i=')' && lin[b]!= par[i++] = lin[b++] ; par[i] = EOW ; /* LOCATE THE PARAMETER IN TABLE[0] */ if (i!=0) { locn = 0 ; flag - 1 ; do { if (same(par,&table[0][locn++][0])) flag = 0 ; } while (table[0][locn-1][0]!=EOW && flag) /* INSERT THE REPLACEMENT PARAMETER */ j = (-D ; while (table[1][locn-1]!=EOW) buf[a++] = table[l][locn-1][j] ; } if (lin[b]==«)' II lin[b]==';») buf[a++] = lin[b++] ; } while (lin[b-l]!=';' && i!=0) ; /* WRITE CONVERTED LINE TO OUTPUT FILE */ buf[a] = EOL ; writeline(fdto,buf) ; } } while (lin[0]!=EOF) ; fclose(fdsub) ; /* CLOSE SUBCIRCUIT FILE */ > /******************************************* /* /* TABULATE FUNCTION — Fills Substitution Table /* /* The tabulate function stores all parameters in the /* input string in TABLE[]. When tabulating the lines in /* the subcircuit, no parameter is stored more than once. /* /********************************************************* tabulate(buf,col) Char buf[LENGTH] ; /* INPUT LINE BUFFER */ int COl ; /* TABULATION COLUMN */ { Char par[WORD] ; /* PARAMETER BUFFER */ int i,q ; /* INDEXING VARIABLES */ int set ; * PARAMETER SET */ /* PROCESS INPUT LINE */ q = 0 ; for (set=0; set<2; set++) /* IGNORE DATA BEFORE FIRST BRACKET */ { while (buf[q] != •(' && buf[q] != ';') q++ ; if (buf[q] == •(') q++ ; /* PLUCK OUT THE PARAMETERS */ do { while (buf[q] == • 1) q++ ; /* MAKE ALLOWANCE FOR : IN SUBCKT LINE */ if (set==l && same(buf,psub)) while (buf[q] != •:« && buf[q] ! = •;') q++ if (buf[q] == ':1) q++ ; 146 /* STORE THE PARAMETER */ i - 0 ; while (buf[q]!=' ' && buf[q]!=')• && buf[q]!=•;1) par[i++] = buf[q++] ; par[i] = EOW ; /* INSERT PARAMETER INTO TABLE[] */ if (buf[0] != ';') if (col==0 && !in(par,0) || col==l) insert(par,col) ; } while (buf[q]!=')1 && buf[q]!=';') ; } } /*********************************************** /* */ /* ISOLATE FUNCTION -- Isolate Input Stage */*/* The isolate function cleans up the .in file, and */ /* removes any lines in the filter file that match one in */ /* the input section file. This separates the input */ /* section from the filter description. */* */***********************************************************/ isolate(fdin) FILE *fdin ; /* .IN INPUT FILE */ ( char buf[LENGTH],lin[LENGTH] ; /* LINE BUFFERS */ Char Stl[WORD],st2[WORD] ; /* STORAGE FOR NODES */ Char st3[WORD],st4[WORD] ; /* STORAGE FOR NODES */ int flag ; /* MATCHING FLAG */ FILE *fdto ; * OUTPUT FILE */ FILE *fdfl ; * INPUT FILE1 */ FILE *fdf2 ; /* INPUT FILE2 */ FILE *fopen() ; * FILE OPEN FUNCTION */ /* EMPTY TABLE */ empty(ZERO) ; empty(ONE) ; /* INITIALIZE NODAL INFORMATION IN TABLE */ copy(firstnode,Stable[1][0][0]) ; copy(lastnode,Stable[1][1][0]) ; table[l][2][0] = EOL ; /* WRITE INPUT SECTION TO OUTPUT FILE, USING THE */ /* SAME PROCESSING AS THE REDUCE FUNCTION DOES */ fdfl = fopenp'SUBC'V'w") ; readclean(fdin,buf) ; 147 while (buf[0] != EOF) { if (buf[0] != EOL) writeline(fdfl,buf) ; readclean(fdin,buf) ; } fclose(fdfl) ; fdfl = fopen(,,SCINQ,,,"r") ; fdto = fopen("SCINP","w") ; fdf2 = fopen(»SUBC","r") ; /* OPEN FILTER FILE */ /* OPEN OUTPUT FILE */ /* OPEN INPUT SECTION FILE */ /* WRITE ALL LINES NOT EXISTING IN INPUT */ /* SECTION FILE TO THE OUTPUT FILE */ readline(fdfl,buf) ; readline(fdfl,buf) ; while (!same(buf,pend)) { flag = 1 ; /* READ ONE LINE FROM THE INPUT SECTION FILE */ readline(fdf2,lin) ; while (flag && lin[0]!=EOF) /* CHECK TO SEE IF THEY ARE THE SAME TYPE */ { if (buf[0]==lin[0]) /* GET THE NODES FROM BOTH LINES */ ( getnode(buf,l,stl) ; getnode(buf,2,st2) ; getnode(lin,l,st3) ; getnode(lin,2,st4) ; /* IF NODES ARE THE SAME, LINES ARE EQUAL */ if (same(stl,st3) && same(st2,st4) || same(stl,st4) && same(st2,st3)) flag = 0 ; } /* READ NEXT LINE FROM INPUT SECTION FILE */ readline(fdf2,lin) ; } /* IF NO MATCH WAS MADE, WRITE LINE TO OUTPUT FILE */ if (flag) writeline(fdto,buf) ; /* PREPARE FOR THE NEXT LINE FROM THE FILTER FILE */ rewind(fdf2) ; readline(fdfl,buf) ; } fclose(fdfl) ; /* CLOSE FILTER FILE */ fclose(fdf2) ; * CLOSE INPUT SECTION FILE */ fclose(fdto) ; /* CLOSE OUTPUT FILE */ 148 /******************************^ /* */ /* STAGES FUNCTION — Group Elements Into Stages */*/* The stages function groups the filter elements into */ /* groups based on which op-amp input they are connected */ /* to. SISC elements are collected into one element. */ /* */********************************^ stages() { Char opl[WORD],op4[WORD] ; /* OP-AMP NODES */ char stl[WORD],st2[WORD] ; /* ELEMENT NODES */ char buf[LENGTH] ; /* LINE BUFFER */ long offset ; /* FILE MARKER */ FILE *fdto ; * OUTPUT FILE */ FILE *fdfrom ; /* INPUT FILE */ FILE *fopen() ; * FILE OPEN FUNCTION */ fdfrom = fopenC'SCINP'V'r") ; /* OPEN THE INPUT FILE */ fdto = ^penC'SCINO'V^w") ; /* OPEN THE OUTPUT FILE */ /* THE GROUPING IS BASED ON THE OP-AMPS */ readline(fdfrom,buf) ; while (buf[0]!=EOF) /* CHECK FOR AN OP-AMP ELEMENT */ { if (buf[0]=='E' && "same(buf,pend)) /* WRITE OP-AMP TO OUTPUT FILE */ /* AND SAVE ITS NODES *{ wrout(fdto,buf,oa) ; getnode(buf,ONE,opl) ; getnode(buf,FOUR,op4) ; /* NOW SEARCH THE FILE FOR CONNECTING ELEMENTS */ offset = ftell(fdfrom) ; rewind(fdfrom) ; readline(fdfrom,buf) ; while (buf[0]!=EOF) /* CAPACITORS MUST BE IC OR CC */ { if (buf [0]=='C) { getnode(buf,ONE,stl) ; getnode(buf,TWO,st2) ; /* IC IF CONNECTED ACROSS THE OP-AMP */ if (same(op4,stl) && same(opl,st2) || 149 same(opl,stl) && same(op4,st2)) wrout(fdto,buf,ic) ; /* ELSE IT MUST BE A CC */ else if (same(op4,stl) || same(op4,st2)) wrout(fdto,buf,cc) ; } /* SWITCHES MUST BE PART OF SISC'S */ else if (buf[0]=='S') { getnode(buf,ONE,stl) ; getnode(buf,TWO,st2) ; /* COMPLETE THE SISC ELEMENT */ if (same(op4,stl)) sisc(fdfrom,fdto,buf,st2,stl) ; if (same(op4,st2)) sisc(fdfrom,fdto,buf,stl,st2) ; } readline(fdfrom,buf) ; } /* SEPARATE THE BLOCKS WITH A BLANK LINE */ putc(EOL,fdto) ; /* RETURN THE FILE TO ITS SAVED POSITION */ fseek(fdfrom,offset,ZERO) ; } readline(fdfrom,buf) ; } /* CLOSE INPUT AND OUTPUT FILES */ fclose(fdto) ; fclose(fdfrom) ; /***********************************************************/ /* */* SISC FUNCTION — Identify a Switched Capacitor */ /*/* The sisc function gathers the other four elements */ /* of a stray-insensitive switched capacitor belonging to */ /* the switch provided by the stages function. */* */************************************************ sisc(fdfrom,fdto,buf,con2,conl) char buf[LENGTH] char con2[W0RD] char conl[WORD] FILE *fdfrom ; FILE *fdto ; /* INPUT FILE */ /* OUTPUT FILE */ /* LINE FOR SWITCH ELEMENT */ /* SECOND NODE OF SWITCH */ /* NODE #1 OF SISC ELEMENT */ { Char Stl[WORD],St2[WORD] /* NODE STORAGE STRINGS */ 150 Char COn3[WORD],COn4[WORD] ; /* SISC ELEMENT HIDDEN NODES Char clk[5][WORD] ; /* SISC ELEMENT PARAMETERS */ long offset,offset2 ; /* FILE POSITION MARKERS */ /* STORE THE FIRST CLOCK */ getval(buf,&clk[l][0]) ; /* SAVE THE FILE POSITION AND REWIND THE FILE */ offset = ftell(fdfrom) ; rewind(fdfrom) ; /* SEARCH FOR THE REST OF THE ELEMENTS */ readline(fdfrom,buf) ; while (buf[0]!=EOF) /* FIND THE CAPACITOR FIRST */ { if (buf[0]==«C') ( getnode(buf,ONE,stl) ; getnode(buf,TWO,st2) ; /* DOES IT CONNECT TO THE SWITCH NODE? */ if (same(con2,stl) || same(con2,st2)) /* SAVE THE CAPACITOR VALUE AND SAVE */ /* THE OTHER NODE OF THE CAPACITOR */ ( getval(buf,&clk[0][0]) ; if (same(con2,stl)) getnode(buf,TWO,con3) ; else getnode(buf,ONE,con3) ; /* SAVE THE FILE POSITION */ offset2 = ftell(fdfrom) ; rewind(fdfrom) ; /* NOW SEARCH FOR THE OTHER THREE SWITCHES */ readline(fdfrom,buf) ; while (buf[0] != EOF) /* LOOK FOR A SWITCH ELEMENT */ ( if (buf[0] == 'S') ( getnode(buf,ONE,stl) ; getnode(buf,TWO,st2) ; /* CONNECTS INPUT SWITCH TO GROUND? * if (same(con2,stl) && st2[0]=='0' || same(con2,st2) && stl[0]=='0') getval(buf,&clk[2][0]) ; /* CONNECTS OUTPUT SWITCH TO GROUND? else if (same(con3,stl) && st2[0]=='0 151 same(con3,st2) && stl[0]=='0') getval(buf,&clk[4][0]) ; /* IS IT THE OUTPUT SWITCH? */ else if (same(con3,stl) || same(con3,st2)) { getval(buf,&clk[3][0]) ; if (same(con3,stl)) getnode(buf,TWO,con4) ; else getnode(buf,ONE,con4) ; } } readline(fdfrom,buf) ; } /* WRITE GATHERED INFORMATION TO OUTPUT FILE */ scout(conl,con4,elk,fdto) ; /* RESTORE FILE POSITION */ fseek(fdfrom,offset2,ZERO) ; } } readline(fdfrom,buf) ; } /* RESTORE FILE POSITION */ fseek(fdfrom,offset,ZERO) ; } /******************************************* /* */ /* INPUT1 FUNCTION — Process Input Stage (LEE) */ /* */* The input1 function processes the input stage of */ /* Man Shek Lee, consisting of two switches and two caps. */ /* The switches are listed first, followed by the input */ /* capacitor and then the switched capacitor. */*/******************************^ input1(fdct) FILE *fdct ; /* .CT OUTPUT FILE */ ( char buf[3][LENGTH] ; /* CAP LINE BUFFERS */ Char Stl[WORD],st2[WORD] ; /* NODE STORAGE STRINGS */ Char St3[WORD],st4[WORD] ; /* NODE STORAGE STRINGS */ int i = 0 ; /* INDEX VARIABLE */ FILE *fdfrom ; * INPUT FILE */ FILE *fopen() ; /* FILE OPEN FUNCTION */ /* OPEN THE INPUT SECTION FILE */ fdfrom = fopen("SUBC","r") ; /* WRITE THE TWO SWITCH ELEMENTS TO THE .CT FILE */ 152 /* STORE THE TWO CAPACITOR ELEMENTS FOR NOW */ readline(fdfrom,&buf[i++][0]) ; while (buf[i-1][0]J=EOF) { if (buf[i-1][0]==,SI) { wrout(fdct,&buf[i-1][0],bs) ; i— ; } readline(fdfrom,&buf[i++][0]) ; } fclose(fdfrom) ; /* STORE THE NODES OF THE TWO CAPACITOR ELEMENTS */ getnode(&buf[0][0],ONE,stl) ; getnode(&buf[0][0],TWO,st2) ; getnode(&buf[1][0],ONE,st3) ; getnode(Sbuf[1][0],TWO,st4) ; /* WRITE THE CAPACITOR CONNECTED TO THE INPUT NODE */ /* FIRST, WITH THE INPUT NODE LISTED FIRST. THE */ /* FILTER LINK NODE IS THE OTHER NODE. *if (stl[0]=='0' || st2[0]==l0') { nodesort(&buf[1][0],firstnode) ; wrout(fdct,&buf[1][0],bc) ; getnode(&buf[1][0],TWO,midnode) ; /* UPDATE THE NODAL TABLE */ if (Stl[0]=='0') copy(st2,Stable[1][3][0]) ; else copy(stl,&table[l][3][0]) ; wrout(fdct,&buf[0][0],bc) ; } else { nodesort(&buf[0][0],firstnode) ; wrout(fdct,&buf[0][0],bc) ; getnode(&buf[0][0],TWO,midnode) ; /* UPDATE THE NODAL TABLE */ if (st3[0]=='0') copy(st4,Stable[1][3][0]) ; else copy(st3,Stable[1][3][0]) ; wrout(fdct,&buf[1][0],bc) ; } /* PUT A GAP IN THE NODE TABLE */ table[1][4][0] = EOL ; /* PUT A GAP IN THE .CT FILE */ putc(EOL,fdct) ; } /************************************************* /* */ /* INPUT2 FUNCTION — Process Input Stage (MARTIN) */ 153 /* */ /* The input2 function processes the input stage of */ /* Ken Martin, consisting of one SISC. The regular */ /* software can process this element, hence the .in file */ /* is empty for this input stage. The filter link node is */ /* the other node of this SISC element. */* */******************************************** input2(fdct) FILE *fdct ; { char buf[LENGTH] ; char stl[WORD],st2[WORD] ; FILE *fdfrom ; FILE *fopen() ; int flag = 1 ; /* .CT OUTPUT FILE */ /* LINE BUFFER */ /* NODE STORAGE STRINGS */ /* INPUT FILE */ /* FILE OPEN FUNCTION */ /* SEARCH FLAG */ /* SEARCH THE FILTER FILE FOR A SISC ELEMENT */ /* CONNECTED TO THE FILTER INPUT NODE. */ fdfrom = fopen("SCINQ","r") ; readline(fdfrom,buf) ; while (buf[0]l=EOF && flag) { if (buf[0]=='S') { getnode(buf,ONE,stl) ; getnode(buf,TWO,st2) ; /* SAVE THE FILTER LINK NODE */ if (same(firstnode,stl) || same(firstnode,st2)) { flag = 0 ; if (same(firstnode,st2)) copy(stl,midnode) ; else copy(st2,midnode) ; } } readline(fdfrom,buf) ; } /* UPDATE THE NODE TABLE */ copy(firstnode,Stable[1][3][0]) ; table[l] [4] [0] = EOL ; /********************************************* /* */ /* INPUT3 FUNCTION — Process Input Stage (SEDRA) */ /*/* The input3 function processes the input stage by */ /* Adel Sedra, consisting of one op-amp, one switch, one */ /* capacitor, and two SISC's. The op-amp is written first */ /* followed by the capacitor-switch pair and then the two */ 154 /* SISC's. The SISC's are sorted to simplify the wiring */ /* in the layout program. */* */******************************************** input3(fdct) FILE *fdct ; ( char buf[LENGTH],1in[LENGTH] char stl[WORD],st2[WORD] ; char st3[WORD],st4[WORD] ; int flag,flag2 ; FILE *fdfrom ; FILE *fdto ; FILE *fopen() ; fdfrom = fopen("SUBC'\ "r") ; fdto = fopenC'SCINS", "w") ; /* .CT OUTPUT FILE */ /* LINE BUFFERS */ /* NODE STORAGE STRINGS */ /* NODE STORAGE STRINGS */ /* CLOCK PHASE FLAGS */ /* INPUT FILE */ /* OUTPUT FILE */ /* FILE OPEN FUNCTION */ /* OPEN INPUT STAGE FILE */ /* OPEN STORAGE FILE */ /* GROUP THE INPUT STAGE FROM THE OP-AMP */ readline(fdfrom,buf) ; while (buf[0]!=EOF) /* FIND THE OP-AMP */ { if (buf[0]==,EI) ( getnode(buf,ONE,stl) ; getnode(buf,THREE,st3) ; /* UPDATE THE NODE TABLE */ copy(st3,&table[1][3][0]) ; copy(stl,Stable[1][4][0]) ; /* WRITE THE OP-AMP TO THE .CT FILE */ wrout(fdct,buf,oa) ; /* SEARCH FOR THE REMAINING ELEMENTS */ rewind(fdfrom) ; readline(fdfrom,buf) ; while (buf[0]!=EOF) /* THERE ARE THREE CAPACITORS */ ( if (buf[0]==,C«) ( getnode(buf,ONE,st2) ; getnode(buf,TWO,st4) ; /* IF IT CONNECTS TO THE NON-INVERTING */ /* OP-AMP INPUT, WRITE TO .CT FILE */ if (same(st3,st2) || same(st3,st4)) wrout(fdct,buf,be) ; ) 155 /* THERE ARE FIVE SWITCHES */ else if (buf[0]=='S') { getnode(buf,ONE,st2) ; getnode(buf,TWO,st4) ; /* IF IT CONNECTS TO THE NON-INVERTING */ /* OP-AMP INPUT, WRITE TO .CT FILE */ if (same(st3,st2) || same(st3,st4)) wrout(fdct,buf,bs) ; /* ELSE GATHER UP THE REST OF THE SISC */ else { if (same(stl,st2)) sisc(fdfrom,fdto,buf,st4,st2) ; if (same(stl,st4)) sisc(fdfrom,fdto,buf,st2,st4) ; } } readline(fdfrom,buf) ; } } readline(fdfrom,buf) ; } /* SPACE THE NODE TABLE */ table[l][5][0] = EOL ; /* CLOSE INPUT AND OUTPUT FILES */ fclose(fdfrom) ; fclose(fdto) ; /* THE FILTER LINK NODE IS THE SECOND */ /* NODE OF EITHER SISC ELEMENT */ fdfrom = fopenC'SCINS'V'r") ; readline(fdfrom,buf) ; getnode(buf,TWO,midnode) ; fclose(fdfrom) ; /* IT IS NOW NECESSARY TO SORT THE TWO SISC ELEMENTS */ /* THE ONE THAT IS SWITCHED SIMILAR TO THE FIRST */ /* INTEGRATOR STAGE MUST GO LAST, WITH REVERSE NODES */ /* FIND THE FIRST INTEGRATOR STAGE */ fdfrom = fopen(HSCINQM,"r") ; readline(fdfrom,buf) ; while (buf[0]!=EOF) { if (buf[0]=='O') { getnode(buf,FOUR,stl) ; /* IS IT THE FIRST OP-AMP? */ if (same(midnode,stl)) /* FIND THE PHASE OF THIS STAGE */ ( do ( readline(fdfrom,buf) ; 156 } if (buf[0]=='S') flag = clockphase(buf, ONE) ; } while (buf[0]!=EOL && buf[0]!=EOF) ; } } readline(fdfrom,buf) ; } fclose(fdfrom) ; /* GET THE TWO SISC ELEMENTS AND CHECK THE CLOCK PHASE */ fdfrom = fopenC'SCINS'V'r") ; readline(fdfrom,buf) ; readline(fdfrom,lin) ; flag2 = clockphase(lin,ONE) ; /* WRITE THE SISC ELEMENTS TO THE .CT FILE */ if (flag==flag2) { writeline(fdct,buf) ; getnode(lin,TWO,st2) ; nodesort(lin,st2) ; writeline(fdct,lin) ; } else { writeline(fdct,lin) ; getnode(buf,TWO,st2) ; nodesort(buf,st2) ; writeline(fdct,buf) ; ) /* PUT A GAP IN THE .CT FILE */ putc(EOL,fdct) ; /* CLOSE THE INPUT FILE */ fclose(fdfrom) ; /********************************************** /* */ /* INPUT4 FUNCTION — Process Input Stage (AROMA) */ /*/***************************************************** input4(fdct) FILE *fdct ; /* .CT OUTPUT FILE */ { Char buf[LENGTH] ; /* LINE BUFFER */ char stl[WORD],st2[WORD] ; /* NODE STORAGE STRINGS */ FILE *fdfrom ; /* INPUT FILE */ FILE *fopen() ; * FILE OPEN FUNCTION */ char mid[3][WORD] ; /* NODE STORAGE */ int count = 0 ; /* COUNTER */ mid[0][0] = mid[l][0] = mid[2][0] = EOW ; 157 } /* SEARCH THE FILTER FILE FOR A SISC ELEMENT */ /* CONNECTED TO THE FILTER INPUT NODE. */ fdfrom = fopen(,,SCINQ,\,,rl,) ; readline(fdfrom,buf) ; while (buf[0]!=EOF) { if (buf[0]=='S') { getnode(buf,ONE,stl) ; getnode(buf,TWO,st2) ; /* SAVE THE FILTER LINK NODE */ if (same(firstnode,stl) || same(firstnode,st2)) { if (same(firstnode,st2)) copy(stl,&mid[count++][0]) ; else copy(st2,&mid[count++][0]) ; } } readline(fdfrom,buf) ; } if (mid[l][0]==EOW) copy(&mid[0][0],midnode) ; else { if (same(&mid[0][0],&mid[l][0])) copy(&mid[2][0],midnode) ; if (same(&mid[0][0],&mid[2][0])) copy(&mid[1][ 0 ],midnode) ; if (same(&mid[l][0],&mid[2][0])) copy(&mid[0][0],midnode) ; } /* UPDATE THE NODE TABLE */ copy(firstnode,Stable[1][3][0]) ; table[l][4][0] = EOL ; /******************************************* /* */ /* ORDER1 FUNCTION — Sort Stages */*/* The order1 function sorts the integrator stages of */ /* the filter. The sort starts with the op-amp connected */ /* to the input stage, and then follows the SISC paths */ /* from the op-amp output of the stage. Once a stage has */ /* been sorted, it is ignored by the sorting algorithm. */ /* */****************************^ order1(fdnd) FILE *fdnd ; /* .ND OUTPUT FILE */ { char oldl[WORD],old2[WORD],old3[WORD] ; /* BASE PATH NODES */ 158 char newl[WORD],new2[WORD],new3[WORD] ; /* FORWARD PATH NODES char new4[WORD],new5[WORD],new6[WORD] char buf[LENGTH] ; long ofsi,ofs2,ofs3 int i = 0 ; FILE *fdto ; FILE *fdfrom ; FILE *fopen() ; /* FORWARD PATH NODES /* LINE BUFFER */ /* FILE MARKERS */ /* INDEX VARIABLE */ /* OUTPUT FILE */ /* INPUT FILE */ /* FILE OPEN FUNCTION fdfrom = fopenC'SCINQ'V'r") ; /* OPEN INPUT FILE */ fdto = fopen("SCINP","w") ; /* OPEN OUTPUT FILE */ /* FIND THE OP-AMP CONNECTED TO THE LINK NODE */ readline(fdfrom,buf) ; while (buf[0]!=EOF) ( if (buf[0]=='O') { getnode(buf,ONE,newl) ; getnode(buf,FOUR,new4) ; /* THE OUTPUT NODE IS THE START OF THE SORT */ if (same(midnode,new4)) copy(newl,oldl) ; } readline(fdfrom,buf) ; } rewind(fdfrom) ; /* START THE SORT FROM THE FIRST OUTPUT NODE */ do ( ofsl = newblock(oldl,newl,new2,fdfrom) ; /* WRITE THE INTEGRATOR STAGE TO THE OUTPUT FILE */ dump(fdfrom,ofsl,fdto) ; /* IF A SINGLE FEED, UPDATE THE SEARCH PATH */ if (new2[0]==EOW) copy(newl,oldl) ; /* IF A DOUBLE FEED, CHECK BOTH NEW PATHS */ else ( while(new2[0]!=EOW) ( copy(newl,old2) ; copy(new2,old3) ; /* TRACE THE NEW PATHS */ ofs2 = newblock(old2,new3,new4,fdfrom) ; ofs3 = newblock(old3,new5,new6,fdfrom) ; /* DUMP THE INTEGRATOR WITH NO NEW FEEDS FIRST */ /* FOLLOWED BY THE OTHER INTEGRATOR, THEN */ /* UPDATE THE SEARCH PATH *if (new3[0]==EOW && new4[0]==EOW) { dump(fdfrom,ofs2,fdto) ; 159 dump(fdfrom,ofs3,fdto) copy(new5,oldl) ; copy(new5,newl) ; copy(new6,new2) ; else if (new5[0]==EOW && new6[0]==EOW) { dump(fdfrom,ofs3,fdto) ; dump(fdfrom,ofs2,fdto) ; copy(new3,oldl) ; copy(new3,newl) ; copy(new4,new2) ; } } } } /* CONTINUE UNTIL NO NEW PATHS EXIST */ while (newl[0]!=EOW || new2[0]!=EOW) ; /* WRITE THE NODE TABLE TO THE .ND FILE */ while (table[l][i][0]!=E0W) ( writeline(fdnd,Stable[1][i][0]) ; if (table[1][i++][0]!=E0L) putc(E0L,fdnd) ; } /* CLOSE THE INPUT AND OUTPUT FILES */ fclose(fdfrom) ; fclose(fdto) ; } /********************************^ /* */ /* NEWBLOCK FUNCTION — Find Next Stages */*/* The newblock function finds the paths by which the */ /* given node feeds new integrator stages. It returns the */ /* input nodes of the found stages. The searching is only */ /* along SISC elements. *( Char stl[WORD],st2[WORD] ; /* NODE STORE STRINGS */ Char St3[WORD],st4[WORD] ; /* NODE STORE STRINGS */ newblock(old,newl,new2,fdfrom) char old[WORD] char newl[WORD] char new2[WORD] FILE *fdfrom ; /* START OF SEARCH PATH */ /* END1 OF SEARCH PATH */ /* END2 OF SEARCH PATH */ /* INPUT FILE */ char buf[LENGTH] int flag = 0 ; int flag2 = 0 ; long offsl,offs2 /* LINE BUFFER */ /* FLAG FOR STARTING STAGE */ /* FLAG FOR SECOND PATH */ /* FILE MARKERS */ 160 /* INITIALIZE THE FORWARD PATH NODES */ newl[0] = EOW ; new2[0] = EOW ; /* HAVE TO FIND THE STARTING STAGE LOCATION IN */ /* ADDITION TO THE TWO POSSIBLE FORWARD PATHS */ rewind(fdfrom) ; do { offsl = ftell(fdfrom) ; /* AN OP-AMP IS ALWAYS FIRST */ readline(fdfrom,buf) ; getnode(buf,ONE,stl) ; getnode(buf,FOUR,st4) ; /* CHECK FOR STARTING STAGE */ if (same(old,stl) && !flag) /* SAVE THE FILE OFFSET */ { offs2 = offsl ; flag = 1 ; while (buf[0]!=EOL && buf[0]!=EOF) readline(fdfrom,buf) ; } /* ELSE SEE IF STAGE IS FED BY THE STARTING NODE */ else do { readline(fdfrom,buf) ; /* ONLY SISC ELEMENTS COUNT */ if (buf[0]==«S') { getnode(buf,ONE,st2) ; getnode(buf,TWO,st3) ; /* SAVE IT IF IT SHARES THE STARTING NODE */ if (same(st2,old) && !in(st3,l) || same(st3,old) && !in(st2,l)) { if (!in(stl,0)) { insert(stl,0) ; if (!flag2) copy(stl,newl) ; else copy(stl,new2) ; flag2 - 1 ; } } } ) while (buf[0]!=EOL && buf[0]!=EOF) ; } while (buf[0]!=EOF) ; return(offs2) ; > /******************************************** /* */ /* ORDER2 FUNCTION — Sort Elements and Nodes *161 /* */ /* The order2 function sorts the elements and nodes of */ /* the integrator stages. The elements are put in the */ /* order as the nodes in TABLE are. Integrating caps */ /* are written before integrating SC's. The op-amp input */ /* node is put first for IC and SC elements. The CC nodes */ /* are sorted in the same order as TABLE. */* */******************************************** order2(fdct) FILE *fdct ; /* .CT OUTPUT FILE */ { char buf[10][LENGTH] ; char line[LENGTH] ; char opl[WORD],op4[WORD] ; char stl[WORD],st2[WORD] ; int flag ; int count ; int j,k,r ; FILE *fdfrom ; FILE *fopen() ; fdfrom = fopen("SCINP","r") ; /* LINE BUFFERS FOR STAGE */ /* LINE BUFFER */ /* NODE STORAGE STRINGS */ /* NODE STORAGE STRINGS */ /* NODE BEFORE/AFTER FLAG */ /* COUNTER OF ELEMENTS */ /* INDEX VARIABLES */ /* INPUT FILE */ /* FILE OPEN FUNCTION */ /* OPEN INPUT FILE */ /* SORT THE BLOCKS ONE AT A TIME */ readline(fdfrom,line) ; while (line[0]J=EOF) /* SAVE THE OP-AMP NODES */ ( getnode(line,FOUR,op4) ; getnode(line,ONE,opl) ; writeline(fdct,line) ; /* STORE THE REST OF THE INTEGRATOR BLOCK */ count = 0 ; do { readline(fdfrom,&buf[count][0]) ; } while (buf[count++][0]!=EOL) ; /* WRITE THE ELEMENTS AS THE NODE */ /* SEARCH COMES TO THEIR NODES */ flag = 0 ; for (k=2; table[l][k][0]!=EOW; k++) for (j=0; j<count-l; j++) { getnode(&buf[j][0],ONE,stl) ; getnode(&buf[j][0],TWO,st2) ; /* WRITE IC BEFORE INTEGRATING SC */ if (same(op4,Stable[1][k][0])) 162 { if (buf[j][0] —'I') if (same(stl,opl) && same(st2,op4) || same(stl,op4) && same(st2,opl)) /* SET FLAG AND SORT THE NODES */ { flag = 1 ; nodesort(Sbuf[j][0],op4) ; writeline(fdct,&buf[j][0]) ; } } /* WRITE INTEGRATING SC */ else if (same(opl,Stable[1][k][0])) { if (buf[j][0]=='S«) if (same(stl,opl) SS same(st2,op4) || same(stl,op4) && same(st2,opl)) /* SORT THE NODES */ ( nodesort(&buf[j][0],op4) ; writeline(fdct,&buf[j][0]) ; ) } /* WRITE REMAINING ELEMENTS, CHECK FIRST NODE else if (same(stl,Stable[1][k][0])) /* CCS NODES ARE IN SAME ORDER AS TABLE */ ( if (buf[j][0]=='C) ( if (flag) nodesort(Sbuf[j][0],st2) ; ) /* MUST BE SC */ else nodesort(Sbuf[j][0],op4) ; writeline(fdct,Sbuf[j][0]) ; } /* CHECK THE OTHER NODE */ else if (same(st2,Stable[1][k][0])) /* CCS NODES ARE IN SAME ORDER AS TABLE */ { if (buf[jj [0]=='C) { if (Iflag) nodesort(Sbuf[j][0],st2) ; } /* MUST BE SC */ else nodesort(Sbuf[j][0],op4) ; writeline(fdct,Sbuf[j][0]) ; } } /* INSERT GAP IN .CT FILE */ putc(EOL,fdct) ; readline(fdfrom,line) ; } fclose(fdfrom) ; /* CLOSE INPUT FILE */ 163 /**************************************************** /* */ /* CLOCKPHASE FUNCTION — Check Phase of a Clock */*/* The clockphase function checks the phase of the */ /* specified. This function is only valid for SC elements */ /* and the clocks must be of the C and #C variety. */ /* */***********************************************************/ clockphase(buf,spot) Char buf[LENGTH] ; /* SC ELEMENT LINE BUFFER */ int spot ; /* CLOCK POSITION 1 - 4 */ { int j,i ; /* INDEX VARIABLES */ /* ADVANCE TO THE BEGINNING OF THE CAP VALUE */ j = 0 ; while (buf[j++]!=')•) ; while (buf[j]==' ') j++ ; /* ADVANCE TO THE DESIRED CLOCK */ for (i=0; i<=spot; i++) { while (buf[j]!=' ') j++ ; while (buf[j]==' •) j++ ; } /* RETURN 0 IF #C IS FOUND */ return(((buf[j]=='#') ? 0 : 1)) ; > /***********************************************************/ /* V /* COPY FUNCTION — String Copy Function */ /* */* The copy function copies stringl to string2. The */ /* first string must be terminated by an EOW. */*/*************************************************** copy(str1,str2) char *strl ; /* INPUT STRING */ char *Str2 ; * OUTPUT STRING */ { int i = 0 ; /* INDEX VARIABLE */ /* COPY STRING1 TO STRING 2 */ do { *(str2+i) = *(strl+i) ; } while (*(strl+i++) != EOW) ; 164 } /***********************************************************/ /* */* DUMP FUNCTION — Write Integerator Stage to File */ /*/* The dump function writes the integrator stage found */ /* at the file location specified by the offset. If also */ /* updates the node table. */* */******************************^ dump(fdfrom,offset,fdto) FILE *fdfrom ; /* INPUT FILE */ FILE *fdto ; * OUTPUT FILE */ long offset ; /* INPUT FILE OFFSET */ { char buf[LENGTH] ; /* LINE BUFFER */ Char st[WORD] ; /* NODE STORAGE STRING */ /* INDEX INTO THE INPUT FILE */ fseek(fdfrom,offset,ZERO) ; /* COPY INTEGRATOR STAGE TO OUTPUT FILE */ do ( readline(fdfrom,buf) ; if (buf[0]=='O') /* INSERT OP-AMP INPUT NODE */ ( getnode(buf,FOUR,st) ; insert(st,l) ; /* INSERT OP-AMP OUTPUT NODE */ getnode(buf,ONE,st) ; insert(st,l) ; } > writeline(fdto,buf) ; } while (buf[0]!=EOL && buf[0]!=EOF) ; /************************************************ /* */ /* EMPTY FUNCTION — Clears a Column of TABLE */*/* The empty function initializes one column of TABLE */ /* to EOW. */*/******************************************************* empty(col) 165 int COl ; /* COLUMN OF TABLE */ { int b ; * INDEX VARIABLE */ /* INITIALIZE TABLE COLUMN */ for (b=0; b<SIZE; b++) table[col][b][0] = EOW ; } /***********************************************************/ /* */* FILL FUNCTION — Insert New Nodes */ /*/* The fill function fills up TABLE for subcircuit */ /* substitutions. The inserted nodes are of the form !AD */ /* which are not allowed in SWITCAP. */* *fill() { int y = (-1) ; /* INDEX VARIABLE */ /* SCAN COLUMN ZERO AND SEE WHAT COLUMN ONE HAS */ while (table[0][++y][0]!=EOW) /* THE GROUND NODE IS ALWAYS 'O' */ { if (table[0][y][0]=='0') copy(Stable[0][y][0],&table[l][y][0]) ; /* ELSE INSERT THE NODE AND UPDATE THE NODE */ else if (table[1][y][0]==EOW) { copy(node,&table[l][y][0]) ; node[2] += 1 ; /* CHECK FOR OVERFLOW */ if (node[2]>'Z1) { node[2] = 'A' ; node[l] += 1 ; } } } } /**************************************** /* */ /* GETNODE FUNCTION — Get One Node of a Line */*/* The getnode function returns the requested node */ /* from the provided line. */*/****************************************** 166 getnode(buf,pos,vertx) char buf[LENGTH] ; /* LINE BUFFER */ char vertx[WORD] ; /* NODE BUFFER */ int pos ; /* NODE POSITION */ { int q,i,k ; /* INDEX VARIABLES */ q = i = 0 ; while (buf[i++]!='(') /* STORE THE REQUESTED NODE */ for (k=l; k<=pos; k++) ( while (buf[i]==« •) i++ ; while (buf[i]!=' • && buf[i]!=')1) ( if (k==pos) vertx[q++] = buf[i++] ; else i++ ; } } vertx[q] = EOW ; } /*********************************^ /* */ /* GETVAL FUNCTION — Gets Variable From Line */*/* The getval function returns the variable stored */ /* after the nodes in the line buffer. */*/********************************************** getval(buf,store) Char buf[LENGTH] ; /* LINE BUFFER */ Char Store[WORD] ; /* VARIABLE BUFFER */ ( int q,i ; /* INDEX VARIABLES */ /* ADVANCE BEYOND THE NODES */ q = i = 0 ; while (buf[i++]!=')') while (buf[i]==« ') i++ ; /* COPY THE VARIABLE TO THE STRING BUFFER */ while (buf[i]!=« 1 && buf[i]!=•;1 && buf[i]!='(•) store[q++] = buf[i++] ; store[q] = EOW ; 167 /*************************************^ /* */ /* IN FUNCTION — See if String is in TABLE */*/* The in function determines if the input string is */ /* stored in the given column of TABLE. */*/***********************************************************/ in(str,col) char *str int col ; /* INPUT STRING */ /* TABLE COLUMN */ { int i = 0 /* INDEX VARIABLE */ /* SCAN THE TABLE COLUMN FOR THE GIVEN STRING */ do { if (same(str,Stable[col][i][0])) return(1) ; } while (table[col][i++][0]!=EOW) ; /* IF NOT FOUND RETURN ZERO */ return(0) ; } /*********************************************** /* */ /* INSERT FUNCTION — Insert String in TABLE */*/* The insert function inserts the given string into */ /* the requested column of TABLE. The first open slot is */ /* used.insert(str,col) char *str int col ; /* STRING TO BE INSERTED */ /* COLUMN FOR INSERTION */ { int i = 0 /* INDEX VARIABLE */ /* COPY THE STRING INTO THE FIRST OPEN SLOT */ while (table[col][i++][0]!=EOW) ; copy(str,Stable[col][i-1][0]) ; 168 /* V /* The nodesort function ensures that the the given */ /* node is the first node of the given line. */*/******************************************* nodesort(buf,str) Char buf[LENGTH] ; /* LINE BUFFER */ char str[WORD] ; * NODE BUFFER */ ( char stl[WORD],st2[W0RD] ; /* NODE STORAGE BUFFERS */ int i,j ; /* INDEX VARIABLES */ i = j = 0 ; getnode(buf,ONE,stl) ; getnode(buf,TWO,st2) ; /* IF THE NODE IS IN THE SECOND */ /* SPOT THEN REVERSE THE NODES */ if (!same(str,stl)) { while (buf[i++]!='(•) ; while (st2[j]i=EOW) buf[i++] = st2[j++] ; buf[i++] = • • ; j - 0 ; while (stl[j]!=EOW) buf[i++] = stl[j++] ; while (buf[i]!=')') buf[i++] = ' ' ; } ) /*********************************^ /* */ /* READCLEAN FUNCTION — Read and Clean a Line */*/* The readclean function reads aline from the input */ /* file and modifies it as follows: */*/* 1. Capitalize letters 2. Remove comments */ /* 3. Single statement per line 4. Left adjust the line */ /* */************************************************* readclean(fdfrom,buf) FILE *fdfrom ; /* INPUT FILE */ 169 Char buf[LENGTH] ; /* LINE BUFFER */ { int a,b ; /* COMMENT BOUNDS */ int ch ; * FILE CHARACTER */ int i,q ; /* INDEX VARIABLES */ q = 0 ; a = b = (-1) ; /* START READING CHARACTERS FROM INPUT FILE */ do { ch = getc(fdfrom) ; buf[q++] = ((ch>='a' && ch<='z') ? ch-'a'+'A' : ch) ; /* CHECK FOR COMMENT BEGINNING */ if (q>l && buf [q-2]==V ' && buf[q-l]=='*•) a = q - 2 ; /* CHECK FOR COMMENT END */ if (a>=0 && buf[q-2]==* *• && buf[q-l]=='/1) b = q - 1 ; } while (ch!=EOL && ch!=EOF && !(ch==';' && q-l>b)) ; /* APPEND EOL IF NEEDED */ if (ch==';') buf[q] = EOL ; /* IF COMMENT EXISTS, BLANK IT OUT */ if (a!=b) for (i=a; i<=b; i++) buf[i] = • • ; /* CHECK FOR SPACES AT BEGINNING OF LINE */ q - 0 ; while (buf[q]==« • && buf[q]!=EOL && buf[q]!=EOF) q++ ; /* LEFT ADJUST THE LINE */ i = q ; if (q>0) do { buf[i-q] = buf[i] ; } while (buf[i++] != EOL) ; } /********************************************************* /* */ /* READLINE FUNCTION — Read a Line From Input File */ /*/* The readline function reads a line terminated by an */ /* EOL or EOF from the input file given. *170 /* */ /***********************************************************/ readline(fdfrom,buf) FILE *fdfrom ; /* INPUT FILE */ Char buf[LENGTH] ; /* LINE BUFFER */ { int q = 0 ; /* INDEX VARIABLE */ /* READ CHARACTERS FROM INPUT FILE */ do { buf[q++] = getc(fdfrom) ; } while (buf[q-1]!=EOL && buf[q-1]!=EOF) ; ) /***********************************************************/ /* */* SAME FUNCTION — String Equality Tester */ /*/* The same function compares two strings up to the */ /* last EOW, EOL, or EOF. */*/***************************************** same(buf1,buf2) char *bufl ; /* FIRST STRING */ char *buf2 ;  /* SECOND STRING */ ( int k = (-1) ; /* INDEX VARIABLE */ int set = 1 ; * OFFSET FOR LONG STRINGS */ /* TAKE NOTE IF STRING IS TERMINATED WITH EOL */ do ( if (bufl[++k]==EOL) set = 0 ; } while (bufl[k]!=EOW && bufl[k]!=EOL && buf1[k]!=EOF) ; /* COMPARE THE STRINGS CHARACTER BY CHARACTER */ k = 0 ; do ( if (bufl[k]!=buf2[k++]) return(0) ; } while (buf2[k-set]!=EOW && bufl[k-set]!=EOW) ; return(1) ; } /******************************************* /* */ /* SCOUT FUNCTION — WRITE SC ELEMENT */*/* The scout function assembles the data for the SC */ 171 /* element and writes it to the output file. */ /* */***********************************************************/ scout(conl,con4,elk,fdto) Char conl[WORD] ; /* FIRST NODE OF SC ELEMENT */ Char COn4[W0RD] ; * SECOND NODE OF SC ELEMENT */ Char clk[5][WORD] ; /* CAP VALUE AND CLOCKS */ FILE *fdto ; /* OUTPUT FILE */ { char line[LENGTH] ; /* LINE BUFFER */ int q = 4 int i = 0 int x = 0 /* INDEX VARIABLE */ /* INDEX VARIABLE */ /* INDEX VARIABLE */ } /* LABEL THE SC ELEMENT */ copy(sc,&line[0]) ; /* INSERT THE FIRST NODE */ while (conl[x]!=EOW) line[q++] = conl[x++] ; line[q++] = ' 1 ; /* INSERT THE SECOND NODE */ while (con4[i]!=EOW) line[q++] = con4[i++] ; line[q++] = •)• ; /* INSERT THE CAP VALUE AND THE FOUR CLOCKS */ for (x=0; x<5; x++) { line[q++] = ' ' ; i - 0 ; while (clk[x][i]!=EOW) line[q++] = clk[x][i++] ; } /* TERMINATE THE LINE AND WRITE IT TO THE OUTPUT FILE */ line[q++] = ' 1 ; line[q++] = •;' ; line[q] = EOL ; writeline(fdto,line) ; /************************************************ /* */ /* WRITELINE FUNCTION ~ Write a Line To Output File */ /*/* The writeline function writes a line terminated by */ /* EOL or EOF or EOW to the output file. */*172 /***********************************************************/ writeline(fdto,buf) FILE *fdto ; /* OUTPUT FILE */ char buf[LENGTH] ; /* LINE BUFFER */ { int q = 0 ; /* INDEX VARIABLE */ /* WRITE THE LINE TO THE OUTPUT FILE */ do { putc(buf[q++],fdto) ; } while (buf[q-1]!=EOL && buf[q-1]!=EOF && buf[q]!=EOW) ; } /***********************************************************/ /* */* WROUT FUNCTION — Write Encoded Output */ /*/* The wrout function relabels circuit elements and */ /* writes it to the output file. */*/***********************************************************/ wrout(fdto,buf,title) FILE *fdto ; /* OUTPUT FILE */ Char buf[LENGTH] ; /* LINE BUFFER */ Char *title ; /* NEW LABEL FOR ELEMENT */ ( char line[LENGTH] ; /* LINE BUFFER */ int i = 0 ; /* INDEX VARIABLE */ int q = 4 ; * INDEX VARIABLE */ /* RELABEL THE LINE */ copy(title,&line[0]) ; while (buf[i++]!=•(•) ; /* INSERT THE REST OF THE LINE FROM BEFORE */ while (buf[i-1]!=EOL) line[q++] = buf[i++] ; /* WRITE THE LINE TO THE OUTPUT FILE */ writeline(fdto,line) ; APPENDIX D: THE LAYOUT GENERATOR LISTING The layout generator requires the filename.nd, filename.ct, filename.com, and the opamp.cif files to run. The operational amplifier CIF code must be symbol #2 and must be in a file called opamp.cif. It is run as follows: SISCL filename style <CR> where style refers to one of the following design techniques: A(AROMA), L(Lee), M(Martin), and S(Datar & Sedra). The single character is used. It produces one output file called filename.cif. 173 174 #include <stdio.h> #define LENGTH 72 #define WORD 8 #define ZERO 0 #define ONE 1 #define TWO 2 #define EOW '\0' #define EOL '\n' #define LIMIT 0.4 #define EDGE 20 #define CAPGAP 2 #define TOPMAX 20 #define MAXOP 20 #define MAXCAP 80 #define MAXVAL 100 #define M1W "L Ml ;W" #define M1B "L Ml ;B" #define P1W "L Pl ;W" #define P1B "L Pl ;B» #define P2W "L P2 ;W" #define P2B "L P2 ;B" #define C1W "L Cl ;W" #define C1B "L Cl ;B" #define ACW "L AC ;W" #define ACB "L AC ;B" #define PWB "L PW ;B" #define PPB "L PP ;B" #define NPB "L NP ;B" char table[3][50][WORD] ; short grid[2000][TOPMAX] ; short path[10][3 *MAXCAP] ; short path2[5][5000] ; float LAMBDA ; int U ; int XBASE = 1400 ; int YBASE = 34000 ; int w ; int total ; int topper ; int stages ; /* BUFFER LENGTH */ /* IDENTIFIER LENGTH */ /* ZERO CONSTANT */ /* ONE CONSTANT */ /* TWO CONSTANT */ /* END OF WORD */ /* END OF LINE */ /* FRACTION BOUND */ /* PLATE SIZE */ /* PLATE SEPARATION */ /* CAP ARRAY HEIGHT */ /* TOTAL OP-AMPS */ /* TOTAL CAPACITORS */ /* MAX CAP VALUE */ /* METAL WIRE COMMAND */ /* METAL BOX COMMAND */ /* POLY1 WIRE COMMAND */ /* POLY1 BOX COMMAND */ /* POLY2 WIRE COMMAND */ /* POLY2 BOX COMMAND */ /* CUT WIRE COMMAND */ /* CUT BOX COMMAND */ /* ACTIVE WIRE COMMAND */ /* ACTIVE BOX COMMAND */ /* P-WELL BOX COMMAND */ /* P+ BOX COMMAND */ /* N+ BOX COMMAND */ /* NODE TABLE */ /* CAPACITOR LAYOUT ARRAY */ /* CAPACITOR WIRING ARRAY */ /* OP-AMP WIRING ARRAY */ /* LAYOUT SCALING FACTOR */ /* CIF BASE UNIT */ /* LAYOUT X-AXIS START */ ./* LAYOUT Y-AXIS START */ /* 2*LAMBDA WIRE WIDTH */ /* NUMBER OF CAPACITORS */ /* CAP ARRAY HEIGHT */ /* NUMBER OF FILTER STAGES */ 175 int swap ; int start ; int level[10] struct cell { /* ARRAY LAYOUT STRATEGY */ /* FILTER STARTING POINT */ /* VERTICAL LAYOUT LEVELS */ int height int width ; int xorg ; int yorg ; int level j int con[3] int vos[3] int wid[3] /* OP-AMP HEIGHT */ /* OP-AMP WIDTH */ /* X ORIGIN OF OP-AMP */ Y ORIGIN OF OP-AMP */ OP-AMP CONNECTION LEVEL */ CONNECTION DISPLACEMENTS */ POWER CONNECT LEVELS */ POWER LINE WIDTHS */ /* /* /* /* /* struct cell opamp /* OP-AMP DATA */ struct mother { int cap ; /* CAPACITOR CONTACT */ int out ; /* OP-AMP CONTACT */ int cross ; /* HORIZONTAL CROSSING */ int level ; /* WIRING LEVEL */ int base ; /* OP-AMP PLACEMENT */ int mirror ; /* MIRROR FLAG */ int gnd ; /* +INPUT CONTACT */ int gndcross ; /* HORIZONTAL CROSSING */ int gndlevel ; } ; /* WIRING LEVEL */ struct mother whip[2*MAXOP] ; /* OP-AMP CONNECTION DATA */ struct contain { float val ; float v2 ; short hor[MAXVAL] short ver[MAXVAL] int pnt ; int next ; int used ; int swtch ; int lay ; int flag ; int tipflag ; char typ ; char fst[WORD] ; char sec[WORD] ; struct contain capac[MAXCAP] ; } /* CAPACITOR VALUE */ /* CAPACITOR VALUE */ /* PLATE HORIZONTAL */ /* PLATE VERTICAL */ /* NUMBER OF PLATES */ /* EXTRA CAP GAPS */ /* SWITCH PLACEMENT */ /* CLOCKING SCHEME */ /* CAPACITOR LAYOUT */ SWITCH CONNECTION */ TIP PLACEMENT */ CAPACITOR TYPE */ FIRST CAP NODE */ SECOND CAP NODE */ /* /* /* /* /* /* CAPACITOR DATA */ /********************************************* /* */* MAIN PROGRAM — LAYOUT GENERATOR */ /*/*************************************** main(argc,argv) /* FETCH C SHELL PARAMETERS int argc ; char *argv[] /* /* NUMBER OF ARGUMENTS */ ARGUMENT POINTERS */ { char head ; /* /* /* /* /* /* /* /* /* /* INPUT SECTION STYLE */ LINE BUFFER */ char *buf ; char *fp ; char st ; FILE POINTER */ CHARACTER STORAGE */ INDEX VARIABLE */ int i ; FILE *fdcom ; FILE *fdcif ; FILE *fopen() FILE *fdct ; FILE *fdnd ; •CT FILE DESCRIPTOR */ .ND FILE DESCRIPTOR */ .COM FILE DESCRIPTOR */ .CIF FILE DESCRIPTOR */ FILE OPEN FUNCTION */ /* SAVE THE INPUT SECTION STYLE */ st = *argv[2] ; head = ((st>='a' && st<='z') ? st-'a'+'A' : st) ; /* OPEN THE .CT FILE FOR READING */ fp = argv[l] ; for (i=0; *(fp+i)!=EOW; i++) ; *(fp+i+0) = '.• ; *(fp+i+l) = 'c' ; *(fp+i+2) = 't' ; *(fp+i+3) = EOW ; fdct = fopen(fp,"r") ; /* OPEN THE .COM FILE FOR READING */ *(fp+i+l) = 'c1 ; *(fp+i+2) = 'o' ; *(fp+i+3) = 'm' ; *(fp+i+4) = EOW ; fdcom = fopen(fp,"r") ; /* OPEN THE .ND FILE FOR READING */ *(fp+i+l) = 'n' ; *(fp+i+2) = 'd' ; *(fp+i+3) = EOW ; fdnd = fopen(fp,"r") ; /* OPEN THE .CIF FILE FOR WRITING */ *(fp+i+l) = 'c' ; *(fp+i+2) = 'i' ; *(fp+i+3) = 'f ; *(fp+i+4) = EOW ; fdcif = fopen(fp,"w") ; /* INITIALIZE THE NODE AND CAPACITOR DATA */ init(fdcom,fdct,fdnd,head) ; /* GENERATE THE CAPACITOR ARRAY */ caparray(fdcif) ; /* INITIALIZE THE OP-AMP AND SWITCH DATA preop(fdcif) ; /* WIRE THE INPUT NODES */ wirel(fdcif) ; /* WIRE THE OUTPUT NODES */ wire2(fdcif) ; /* WIRE THE HIDDEN INPUT NODES */ wire3(fdcif) ; /* WIRE THE HIDDEN OUTPUT NODES */ wire4(fdcif,0) ; wire4(fdcif,1) ; /* CONNECT THE SWITCHES */ streak(fdcif) ; /* CONNECT THE INPUT AND OUTPUT NODES */ wire5(fdcif) ; /* CONNECT THE GROUND LEADS */ wire6(fdcif) ; /* PLACE AND CONNECT THE OP-AMPS */ ampson(fdcif) ; /* INSERT GLOBAL LAYOUT FEATURES */ wrapup(fdcif) ; /* HARD-WIRE THE INPUT SECTION */ if (head==«L') inputl(fdcif) ; if (head=='M') input2(fdcif) ; if (head==«S') input3(fdcif) ; if (head=='Al) input4(fdcif) ; /* FINISH THE .CIF FILE */ buf = "DF ;\n" ; writeline(fdcif,buf) ; /* CLOSE THE FILES */ fclose(fdct) ; fclose(fdcif) ; fclose(fdcom) ; fclose(fdnd) ; 178 /***********************************************************/ /* */* INIT FUNCTION — Read Input Data */*/* The init function reads the input .CT file and */ /* initializes the capac structure. It also initializes */ /* the node table. */* */***********************************************************/ init (fdcom,fdct,fdnd,head) FILE *fdcom ; /* .COM INPUT FILE */ FILE *fdct ; * .CT INPUT FILE */ FILE *fdnd ; * .ND INPUT FILE */ char head ; /* INPUT SECTION STYLE */ { int i,j,k ; * INDEX VARIABLES */ int conn[4] ; /* CLOCK PHASES */ int flip[MAXCAP] ; /* CAP CLOCK STORAGE */ char line[LENGTH] ; * LINE BUFFER */ Char Stl[WORD],st2[WORD] ; /* NODE BUFFERS */ /* INITIALIZE THE LEVEL STORAGE */ for (i=0; i<10; i++) level[i] = 0 ; /* READ THE .COM FILE DATA */ readcom(fdcom) ; /* READ INPUT AND OUTPUT NODES */ readnd(fdnd,head) ; /* INITIALIZE THE CAPACITORS */ i = 1 ; stages = 0 ; readline(fdct,line) ; while (line[0] != EOF) /* THE INPUT SWITCH IS PUT ON THE FIRST CAPACITOR */ { if (line[0]=='B' && line[l]=='S') { getnode(line,ONE,stl) ; getnode(line,TWO,st2) ; if (same(Stable[0][0][0],stl) || same(&table[0][0][0],s { if (head=='L') capac[2].swtch = !clockphase(line,ZERO) ; if (head=='M') capac[1].swtch = Iclockphase(line,ZERO) ; } } 179 /* GET THE CAP PARAMETERS FROM THE INPUT FILE */ if (line[l]==lC && line[0]!=EOL) { sscanf (line,"%*s%[A) ] %c%f11, stl, st2, &capac[i] .val) ; capac[i].v2 = capac[i].val ; getnode(line,ONE,&capac[i].fst[0]) ; getnode(line,TWO,&capac[i].sec[0]) ; capac[i]•next = 1 ; capac[i].used = 0 ; capac[i].lay = ((capac[i].val>swap) ? 0 : 1) ; /* GET THE CLOCKS FOR THE SWITCHED CAPS */ if (line[0]=='S') { capac[i].typ = •s' ; flip[i] = clockphase(line,1) ; capac[i].swtch = clockphase(line,3) ; } /* SAVE THE CAPACITOR TYPE */ if (line[0]=='I') capac[i].typ = 'I' ; if (line[0]=='C ) capac[i].typ = 'C ; i++ ; } /* INCREMENT THE STAGE COUNT */ if (line[0]=='O') stages++ ; readline(fdct,line) ; } /* SAVE THE CLOCKING FOR THE INTEGRATING CAPS */ total = i-1 ; for (i=l; i<=total; i++) if (capac[i].typ=='I') for (j=0; j<=total; j++) if (same(&capac[i].fst[0],ficapac[j].fst[0])) capac[i].swtch = flip[j] ; /* INITIALIZE THE SWITCH CONNECTION FLAGS */ for (i=l; i<=total; i++) capac[i].flag = 1 ; /* CUSTOMIZE THE INPUT STAGE PARAMETERS */ if (head=='M') ( capac[1].flag = 0 ; capac[1].used = 1 ; } if (head=='A') { capac[1].used = 1 ; capac[1].flag = 0 ; for (i=2; i<=total; i++) if (same(&capac[i].sec[0],&table[0][0][0]) && capac[i]•typ=='S1 && capac[i].swtch!=capac[l].swtch) { capac[i].flag = 0 ; 180 capac[i].used = 1 ; } } if (head=='S') { capac[1].flag = 0 capac[2].flag = 0 capac[2].used = 1 capac[3].flag = 0 capac[3].used = 1 capac[1].next = 2 capac[2].swtch = !capac[3].swtch ; /*********************************^ /* */ /* CAPARRAY FUNCTION — Generate Capacitor Array */* V /* The caparray function generates the capacitor array */ /* by laying out the capacitors and then ensuring that */ /* the op-amp widths are comparable to the capacitor base */ /* widths. If this is not the case, spaces are inserted */ /* the capacitor array. The capacitor tip is added at the */ /* end to provide proper areas and mask shift immunity. */ /* */***************************************** caparray(fdcif) FILE *fdcif ; /* .CIF FILE */ { int xcl ; * WIDTH OF THE OP-AMPS */ int XC2 ; /* WIDTH OF CAPACITORS */ float space ; /* EXTRA SPACE NEEDED */ /* LAYOUT THE CAPACITOR ARRAY */ layout(fdcif,0.0) ; /* COMPARE WIDTHS OF OP-AMPS AND CAPACITORS */ xcl = stages*opamp.width ; xc2 = capac[total].nor[0]+capac[total].next*EDGE ; space = (xcl - xc2 + 10) / (total-1) ; /* INSERT EXTRA SPACES IN THE CAP ARRAY IF NECCESSARY */ if (space > 0) layout(fdcif,space) ; /* ADD THE TIP ON THE CAPACITORS */ termonate(fdcif) ; > /***********************************************************/ 181 /* */ /* LAYOUT FUNCTION — Layout Capacitors */*/* The layout function generates the capacitor array. */ /* The layout is generated by laying out each capacitor */ /* one plate at a time and inserting spaces until all the */ /* capacitors fit. The height of the array is user set. */ /* V /*********************************************** layout(fdto,space) FILE *fdto ; float space ; { char *buf ; float fraction ; float gap2 ; float FEDGE = EDGE ; int dir[2][4][2] ; int x,y ; int i,j ; int flag ; int finish ; int horz ; int left ; int gap ; int numb ; int xdir,ydir ; int index ; /* OUTPUT FILE */ /* EXTRA GAP REQUIRED */ /* LINE BUFFER */ /* FRACTIONAL CAP SIZE * /* GAP INCREMENT */ /* PLATE EDGE */ /* PLATE DIRECTIONS */ /* PLATE CO-ORDINATES */ /* INDEX VARIABLES */ /* PLATE LAYOUT SUCCESS /* ARRAY LAYOUT SUCCESS /* HORIZ. LAYOUT CO-ORD /* LEFT PLATE BOUNDARY * /* PLATE GAP */ /* CURRENT CAPACITOR */ /* PLATE DIRECTION */ /* SEARCH INDEX */ /* INITIALIZE PLATE DIRECTION UP-DOWN PREFERENCE */ dir[0][0][0] = 0 ; dir[0][0][1] = 1 ; dir[0][l][0] = 0 ; dir[0][l][l] = -1 ; dir[0][2][0] = 1 ; dir[0][2][l] = 0 ; dir[0][3][0] = -1 ; dir[0][3][1] = 0 ; /* INITIALIZE PLATE DIRECTION RIGHT-LEFT PREFERENCE */ dir[l][0][0] = 0 ; dir[1][0][1] = -1 ; dir[l][l][0] = 1 ; dir[l][l][l] = 0 ; dir[l][2][0] = -1 ; dir[l][2][l] = 0 ; dir[l][3][0] = 0 ; dir[1][3][1] = 1 ; /* COPY OP-AMP CELL TO CIF FILE */ rewind(fdto) ; shoveon(fdto) ; /* INITIALIZE LAYOUT SYMBOL */ buf = "DS 1 ;\n" ; writeline(fdto,buf) ; 182 /* EMPTY THE ARRAY */ for (i=0; i<2000; i++) for (j=0; j<TOPMAX; j++) grid[i][j] = 0 ; /* INITIALIZE THE LAYOUT PARAMETERS */ horz = 1 ; gap = 0 ; gap2 = 0.0 ; /* PLACE THE FIRST PLATE OF EACH CAPACITOR */ for (i=l; i<=total; i++) /* INITIALIZE THE FIRST PLATE CO-ORDS */ { capac[i].pnt = 1 ; capac[i].hor[0] = horz ; capac[i].ver[0] = 1 ; /* FIND THE PLATE SIZE */ capac[i].val = capac[i].v2 ; fraction = ((capac[i].val<l.0) ? capac[i].val : 1.0) ; capac[i].tipflag = ((fraction<l.0) ? 1 : 0) ; capac[i].val = capac[i].val - 1.0 ; /* FILL THE ARRAY */ for (j=horz; j<horz+EDGE; j++) grid[j][l] = i ; /* ATTACH THE PLATE */ attachl(horz,0,0,1,fraction,fdto,0) ; /* INCREMENT TO THE NEXT PLATE */ gap2 = gap2 + space - gap ; gap = ((gap2>=EDGE) ? EDGE : 0) ; horz = horz + capac[i].next*EDGE + CAPGAP + gap ; , } /* PLACE THE BOUNDARIES OF THE ARRAY */ horz = horz - CAPGAP ; for (i=0; i<=horz; i++) for (j=0; j<TOPMAX; j++) if (i==0 || i==horz || j==0 || j==topper+2) grid[i][j] = MAXCAP - 1 ; /* PLACE THE REST OF THE CAPACITOR PLATES */ finish = 0 ; while (!finish) { finish = 1 ; /* CHECK EACH CAPACITOR IN TURN */ 183 for (numb=l; numb<=total; numb++) /* TRY EACH DIRECTION */ { flag = 0 ; for (j=0; (j<4 && Iflag); /* CHECK EACH PREVIOUS PLATE */ for (index=0; (index<capac[numb].pnt && "flag); index /* FIND THE PLATE LOCATION */ { xdir = dir[capac[numb].lay][j][0] ; ydir = dir[capac[numb].lay][j][1] ; x = capac[numb].hor[index] ; y = capac[numb].ver[index] ; /* DECIDE IF THERE IS ROOM FOR THE PLATE */ if (capac[numb].val > 0 && !flag && dope(x,xdir,y,ydir,numb,norz)) /* FIND THE PLATE SIZE */ { fraction = ((capac[numb].val>=l) ? 1.0 : capa if (fraction<l.0 && ydir==l) capac[numb].tipflag = 1 ; /* FILL THE ARRAY ONLY IF NECCESSARY */ if (fraction*FEDGE+CAPGAP+2>EDGE && !xdir | | ( left = x + xdir*EDGE ; for (i=left; i<left+EDGE; i++) grid[i][y+ydir] = numb ; } /* UPDATE THE CAPACITOR PARAMETERS */ capac[numb].hor[capac[numb].pnt] = x+xdir*EDG capac[numb].ver[capac[numb].pnt] = y+ydir; capac[numb].val = capac[numb].val - 1.0 ; capac[numb].pnt = capac[numb].pnt + 1 ; /* PLACE THE PLATE AS APPROPRIATE */ if (fraction < LIMIT) attach2(x,y,xdir,ydir,fraction,fdto,1) ; else if (fraction < 1.0) attach.3 (x,y,xdir,ydir, fraction, fdto, 1) ; else attachl(x,y,xdir,ydir,fraction,fdto,1) ; /.* SET THE FLAGS */ flag = 1 ; if (capac[numb].val > 0) finish = 0 ; } } } ) /* SEE IF THE ALL CAPACITORS WERE COMPLETED */ j = flag = 0 ; 184 > while (j <= total) { if (capac[j].val>0) /* ALLOCATE MORE SPACE */ { capac[j++].next += 1 ; /* SKIP NEXT ONE */ flag = 1 ; } j = j + 1 ; ) /* DO IT AGAIN IF NECCESSARY */ if (flag) { printf("%s\n","ITERATION FAILURE") ; layout(fdto,space) ; } /********************************^ /* V /* TERMONATE FUNCTION — Place a Tip on the Capacitor */ /* */* The termonate function places a tip on the caps not */ /* yet having one. The tip ensures proper area ratios and */ /* immunity to P1-P2 mask shifts. */*/***********************************************************/ termonate(fdto) FILE *fdto ; /* OUTPUT FILE */ { int i,j ; /* INDEX VARIABLES */ int xtop,ytop ; /* HIGHEST CO-ORDS */ int xc,yc ; /* TIP LOCATION */ /* CHECK EACH CAPACITOR FOR PREVIOUS TIP PLACEMENT */ for (i=l; i<=total; i++) if (!capac[i].tipflag) /* FIND THE HIGHEST PLATE OF THE CAPACITOR */ { ytop = -1000 ; for (j=0; j<capac[i].pnt; j++) if (capac[i],ver[j] > ytop) { ytop = capac[ i ].ver[j] ; xtop = capac[i].hor[j] ; } /* INCREMENT TO THE TOP OF THAT PLATE */ XC = (Xtop + EDGE/2.0)*U ; yc = (ytop*EDGE + 1)*U ; /* PLACE THE TIP */ BOX(fdto,P2B,2*U,2*U,xc,yc) ; } 185 /*************************************************** /* •*/ /* WIREl FUNCTION — Connect Input Nodes */* V /* The wirel function connects all the op-amp input */ /* nodes to the appropriate capacitors. */* */***********************************************************/ wirel(fdto) FILE *fdto /* OUTPUT FILE */ { int i,k ; int j ; int least[2] ; int most[2] ; int xc[3],yc[3] /* INDEX VARIABLES */ /* WIRING LEVEL */ /* LEFTMOST POINT OF WIRE */ /* RIGHTMOST POINT OF WIRE */ /* WIRING CENTER CO-ORDS */ /* INITIALIZE THE VERTICAL CO-ORDS */ yc[13 = level[33 = U ; /* EMPTY THE WIRING ARRAY */ for (i=0; i<10; i++) for (j=0; j<300; j++) path[i][J3 = 0 ; /* WIRE UP THE OP-AMP INPUT NODES */ for (i=start; table[2][i 3[0]!=EOW; i+=2) /* INITIALIZE THE WIRE END-POINTS */ { least[03 = 3*(total+l) ; most[03 = 0 ; /* CHECK ALL CAPACITORS FOR A CONNECTION */ for (j=0;j<=total; { xc[03 = (capac[j].hor[0]+EDGE/2+8)*U ; xc[2] = xc[0] - 16*U ; /* IGNORE SWITCHED CAPACITORS */ if (capac[j].typ=='S') ; /* IF THE FIRST NODE IS THE SAME... */ else if (same(&table[2][i][0],&capac[j].fst[0])) { if (3*j<least[0]) { least[0] = 3*j ; least[l] = xc[2] ; } else if (3*j>most[0]) { most[0] = 3*j ; most[l] = xc[2] ; ) ) 186 > /* IF THE SECOND NODE IS THE SAME... */ else if (same(Stable[2][i][0],&capac[j].sec[0])) { if (3*j+2<least[0]) { least[0] = 3*j+2 ; least[l] - xc[0] ; } else if (2*j+l>most[0]) { most[0] = 3*j+2 ; most[l] = xc[0] ; } } } if (most[0]>least[0]) { /* FIND WIRE LEVEL AND PLACE WIRE */ j = wireslot(least,most) ; yc[0] = (-5*j-3)*U ; WIRE(fdto,MlW,w,least[1],yc[0],most[l],yc[0]) ; } /* CHECK ALL CAPACITORS */ for (k=0; k<=total; k++) { xc[0] = (capac[k].hor[0]+EDGE/2+8)*U ; xc[2] = xc[0] - 16*U ; /* CONNECT NODES */ if (same(Stable[2][i][0],Scapac[k].fst[0]) || same(Stable[2][i][0],Scapac[k].sec[0])) /* PLACE CAPACITOR CONNECTIONS */ { if (same(Stable[2][i][0],Scapac[k].fst[0])) /* SAVE VERTICAL CO-ORD FOR SWITCH CONNECTION */ { capac[k].ver[2] = ((most[0]>least[0]) ? yc[0]/ xc[l] = xc[2] ; } else xc[l] = xc[0] ; if (capac[k].typ!='S1 SS most[0]>least[0]) { WIRE(fdto,P2W,w,xc[l],yc[l],xc[l],yc[0]) ; mp2(xc[l],yc[0],fdto) ; } } ) } /*************************************** /* */ /* WIRE2 FUNCTION — Connect Output Nodes */*/* The wire2 function connects the op-amp output */ /* nodes to switched capacitor switches. */*/************************************************** wire2(fdto) FILE *fdto ; /* OUTPUT FILE */ { int i,k ; * INDEX VARIABLES */ 187 int j ; int least[2] ; int most[2] ; int xc[4],yc[3] /* WIRING LEVEL */ /* LEFTMOST POINT OF WIRE */ /* RIGHTMOST POINT OF WIRE */ /* WIRING CENTRE CO-ORDS */ /* INITIALIZE THE WIRING LEVELS */ yc[l] = U ; /* CONNECT THE OP-AMP OUTPUT NODES */ for (i=l+start; table[2][i][0]1=EOW; i+=2) /* INITIALIZE THE WIRE BOUNDS */ { least[0] = 3*(total+l) ; most[0] = 0 ; /* CHECK EACH CAP FOR THE NODE */ for (j=0;j<=total; j++) { xc[0] = (capac[j].nor[0]+EDGE/2+8)*U ; xc[2] = xc[0] - 16*U ; xc[3] = (capacftotal].hor[0]+capac[total].next*EDGE)*U /* CHECK THE FIRST NODE */ if (capac[k].typ!='S' && same(Stable[2][i][0],Scapac[j].fst[0])) { if (3*j<least[0]) { least[0] = 3*j ; least[l] = xc[2] ; } else if (3*j>most[0]) { most[0] = 3*j ; most[l] = xc[2] ; } } /* CHECK THE SECOND NODE */ else if (same(Stable[2][i][0],&capac[j].sec[0])) ( if ((capac[j].typ=='Sf && capac[j].used==l) || capac[j].typ!=,S*) ( if (3*j+2<least[0]) { least[0] = 3*j+2 ; least[l] = xc[0] ; } else if (3*j+2>most[0]) { most[0] = 3*j+2 ; most[l] = xc[0] ; } } /* EXTEND OUTPUT NODE TO THE FAR RIGHT */ if (same(Stable[0][1][0],Stable[2][i][0])) ( most[0] = 3*total+2 ; most[l] = xc[3] ; } } /* CALCULATE WIRE LEVEL */ j = wireslot(least,most) ; yc[0] = (-5*j-3)*U ; WIRE(fdto,Mlw,w,least[1],yc[0],most[l],yc[0]) ; /* SAVE THE OUTPUT WIRING LEVEL */ if (same(Stable[0][1][0],Stable[2][i][0])) level[9] = yc[0] ; 188 > /* CONNECT THE APPROPRIATE CAPS */ for (k=0; k<=total; k++) { xc[0] = (capac[k].hor[0]+EDGE/2+8)*U ; xc[2] = xc[0] - 16*U ; /* CONNECT NODES */ if (same(Stable[2][i][0],Scapac[k].fst[0]) || same(Stable[2][i][0],Scapac[k].sec[0])) /* FIRST NODE */ ( if (same(Stable[2][i][0],Scapac[k].fst[0])) xc[l] = xc[2] ; else xc[l] = xc[0] ; /* SAVE LEVEL FOR SWITCH CONNECTION */ if (capac[k].typ=='S') capac[k].ver[l] = yc[0]/10 ; /* ELSE PLACE CONTACTS AND CONNECT THEM */ else ( mp(xc[l],yc[0],fdto) ; WIRE(fdto,PlW,w,xc[l],yc[l],xc[l],yc[0]) ; } } } /*************************************** /* */ /* WIRE4 FUNCTION — Connect Shared Output Nodes */ /* */* The wire4 function connects the op-amp output */ /* nodes to switched capacitor switches. */*/************************************** wire4(fdto,theone) FILE *fdto ; /* OUTPUT FILE */ int theone ; { int i,k ; /* INDEX VARIABLES */ int j ; * WIRING LEVEL */ int least[2] ; /* LEFTMOST POINT OF WIRE */ int most[2] ; * RIGHTMOST POINT OF WIRE */ int XC[3],yc[3] ; /* WIRING CENTRE CO-ORDS */ /* INITIALIZE THE WIRING LEVELS */ yc[l] = U ; /* CONNECT THE OP-AMP OUTPUT NODES */ for (i=l+start; table[2][i][0]!=EOW; i+=2) 189 } /* INITIALIZE THE WIRE BOUNDS */ { least[0] = 3*(total+l) ; most[0] = 0 ; /* CHECK EACH CAP FOR THE NODE */ for (j=0;j<=total; j++) { xc[0] = (capac[j].nor[0]+EDGE/2)*U ; /* CHECK THE FIRST NODE */ if (capac[j].typ==lS' && same(Stable[2][i][0],Scapac[j].sec[0])) if (capac[j].swtch==theone) { if (3*j+Kleast[0]) { least[0] = 3*j+l ; least[l] = xc[0] ; } else if (3*j+l>most[0]) { most[0] = 3*j+l ; most[l] = xc[0] ; } } if (most[0]>least[0]) { /* FIND WIRE LEVEL AND PLACE WIRE */ j = wireslot(least,most) ; yc[0] = (-5*j-3)*U ; WIRE(fdto,MlW,w,least[1],yc[0],most[l],yc[0]) ; /* CONNECT THE APPROPRIATE CAPS */ for (k=0; k<=total; k++) { xc[0] = (capac[k].hor[0]+EDGE/2)*U ; /* CONNECT NODES */ if (capac[k].typ=='S' SS same(Stable[2][i][0],Scapac[k].sec[0])) if (capac[k].swtch==theone) /* PLACE CONTACTS AND CONNECT THEM */ { mp2(xc[0],yc[0],fdto) ; capac[k].nor[2] = yc[0]/10 ; WIRE(fdto,P2W,w,xc[0],yc[l],xc[0],yc[0]) /********************************************* /* */ /* WIRE3 FUNCTION — Connect Hidden Nodes */* V /* The wire3 function connects the hidden nodes */ /* between integrating and switched capacitors. */*/********************************************************* wire3(fdto) FILE *fdto ; /* OUTPUT FILE */ 190 int i,k ; int j ; int least[2] ; int most[2] ; int xc[3],yc[3] /* INDEX VARIABLES */ /* WIRE LEVEL */ /* LEFTMOST POINT OF WIRE */ /* RIGHTMOST POINT OF WIRE */ /* WIRE CONNECTION POINTS */ /* INITIALIZE THE WIRING LEVELS */ yc[l] = U ; /* CONNECT THE HIDDEN NODES */ for (i=start; table[2][i][0]!=EOW; i+=2) /* INITIALIZE THE WIRE BOUNDS */ { least[0] = 3*(total+l) ; most[0] = o ; /* CHECK EVERY CAPACITOR */ for (j=0;j<=total; j++) { xc[l] = (capac[j].hor[0]+EDGE/2)*U ; xc[2] = xc[l] - 8*U ; /* FIRST NODE ON SWITCHED CAPS */ if (capac[j].typ==,Sl && same(Stable[2][i][0],Scapac[j].fst[0])) { if (3*j<least[0]) { least[0] = 3*j ; least[l] = xc[2] ; } else if (3*j>most[0]) { most[0] = 3*j ; most[l] = xc[2] ; } } /* FIRST NODE ON INTEGRATING CAPS */ else if (capac[j].typ==lI' && same(Stable[2][i][0],Scapac[j].fst[0])) { if (3*j+Kleast[0]) { least[0] = 3*j+l ; least[l] = xc[l] ; } else if (3*j+l>most[0]) { most[0] = 3*j+l ; most[l] = xc[l] ; } } /* FIND THE WIRE LEVEL */ j = wireslot(least,most) ; yc[0] = (-5*j-3)*U ; WIRE(fdto,MlW,w,least[1],yc[0],most[l],yc[0]) ; /* CONNECT THE CAPACITORS TO THE WIRE */ for (k=0; k<=total; k++) { xc[l] = (capac[k].hor[0]+EDGE/2)*U ; xc[2] = xc[l] - 8*U ; /* FIRST NODE CONNECTIONS ONLY */ if (same(Stable[2][i][0],Scapac[k].fst[0])) 191 /* CONNECT SWITCHED CAPS */ { if (capac[k].typ==,S') /* PLACE AND CONNECT CONTACTS */ { mp(xc[2],yc[0],fdto) ; WIRE (fdto,PlW,w,xc[2],yc[l],xc[2],yc[0]) /* PLACE CONTACTS FOR INTEGRATING CAPS */ else if (capac[k].typ=='I') capac[k].ver[l] = yc[0]/10 ; } } } } /it*********************************** /* */ /* STREAK FUNCTION — Connect the Switches */*/* The streak function places and connects the */ /* switches to the previous wiring. */*/*************************************** streak(fdto) FILE *fdto ; /* OUTPUT FILE */ ( int i ; * INDEX VARIABLE */ int xc,xm,xp ; /* HORIZ. WIRING POINTS */ int yc[8] ; * VERTICAL WIRING LEVELS */ yc[0] = level[1] ; /* TOP OF SWITCH */ yc[l] = U ; /* CONTACT FOR CAPACITOR */ yc[3] = level[1] - 16*U ; /* BOTTOM OF SWITCH */ yc[4] = level[l] - 33*U ; /* GROUND LINE */ yc[2] = level[1] + 12*U ; /* TOP CONNECTION LEVEL */ /* PLACE AND CONNECT THE SWITCHES */ for (i=0; i<=total; i++) /* INITIALIZE THE CONNECTION POINTS */ { xc = (capac[i].hor[0] + EDGE/2)*U ; xm = xc - 8*U ; xp = xc + 8*U ; yc[5] = 10*capac[i].ver[l] yc[6] = 10*capac[i].ver[2] yc[7] = 10*capac[i].hor[2] /* SWITCHED CAPACITOR */ if (capac[i].typ == 'S') ( if (capac[i].used==l) 192 > { switchplace(xc,level[1],i,fdto) ; WIRE(fdto,MlW,w,xm,yc[3],xm,yc[4]) ; if (yc[7]==level[l]+17*U) { WIRE(fdto,P2W,w,xc,yc[l],xc,yc[7]) ; WIRE(fdto,MlW,w,xc,yc[7],xc,yc[0]) ; } else ( mp2(xc,yc[2],fdto) ; WIRE(fdto,P2W,w,xc,yc[l],xc,yc[2]) ; WIRE(fdto,MlW,w,xc,yc[2],xc,yc[0]) ; ) } if (capac[i].flag && capac[i].used) { if (yc[5]!=yc[2]+5*U) ( mp(xp,yc[5],fdto) ; mp(xp,yc[2],fdto) ; WIRE(fdto,MlW,w,xp,yc[2],xp,yc[0]) ; WIRE(fdto,PlW,w,xp,yc[5],xp,yc[2]) ; ) else WIRE(fdto,MlW,w,xp,yc[5],xp,yc[0]) ; ) } /* INTEGRATING CAPACITOR */ else if (capac[i].typ=='I') { switchplace(xc,level[1],i,fdto) ; WIRE(fdto,MlW,w,xp,yc[3],xp,yc[4]) ; if (yc[5]!=yc[2]+5*U) { mp(xc,yc[5],fdto) ; mp(xc,yc[2],fdto) ; WIRE(fdto,MlW,w,xc,yc[2],xc,yc[0]) ; WIRE(fdto,Plw,w,xc,yc[5],xc,yc[2]) ; ) else WIRE(fdto,MlW,w,xc,yc[5],xc,yc[0]) ; mp2(xm,yc[2],fdto) ; WIRE(fdto,MlW,w,xm,yc[2],xm,yc[0]) ; if (yc[6]==(-10)) WIRE(fdto,P2W,w,xm,yc[l],xm,yc[2]) ; else WIRE(fdto,P2W,w,xni,yc[6] ,xm,yc[2]) ; ) ) /************************************************* /* */ /* PREOP FUNCTION — Initialize OP-AMP Data */*/* The preop function initializes the op-amp data */ /* and decides where the op-amps are to be connected to */ /* the switches. It also decides which op-amps to mirror. */ /* V /***********************************************************/ 193 preop(fdto) FILE *fdto ; /* OUTPUT FILE */ { int length ; /* LENGTH OF CAP ARRAY */ int gap ; /* GAP BETWEEN OP-AMPS */ int clock ; /* SC CLOCK */ int stox ; /* INDEX */ int flag ; /* FOUND FLAG */ int count ; /* NUMBER OF SC'S FOR CONNECTION */ int middle ; /* MIDPOINT OF OP-AMP CONNECTS */ int master ; /* CLOSEST SC CONTACT */ int store ; /* SC CONNECTION POINT */ int /* INDEX VARIABLES */ int x ; /* OP-AMP PLACEMENT POINT */ float gap2 ; /* REQUIRED GAP BETWEEN OP-AMPS */ float inc ; /* GAP INCREMENT */ /* FIND ANY EXTRA SPACING REQUIRED BETWEEN THE OP-AMPS */ length = capac[total].hor[0] + capac[total].next*EDGE + 4 ; inc = (length - stages * opamp.width) / (stages - 1) ; if (inc < 0) inc = 0 ; /* INITIALIZE THE PLACEMENT */ X = -1 ; gap = 0 ; gap2 = 0.0 ; /* INITIALIZE THE INPUT STAGE OP-AMP FOR SEDRA */ if (start==2) { whip[0].out = x + opamp.con[0] ; whip[1].out = x + opamp.con[2] ; whip[0].cap = (capac[1].hor[0]+EDGE/2)*U ; whip[l].cap= (capac[2].hor[0]+EDGE/2+8)*U ; whip[0].base = x ; whip[0].gnd = x + opamp.con[l] ; whip[0].mirror = 0 ; x = x + opamp.width + inc ; } /* PROCESS THE REST OF THE FILTER */ for (i=start; i<stages+stages; i++) { whip[i].base = x ; /* OP-AMP INPUT NODE */ if (!(i%2)) /* LOOK FOR AN INTEGRATING CAPACITOR */ { for (j=l; j<=total; j++) if (capac[j].typ=='11 && 194 same(&capac[j].fst[0],Stable[2][i][0])) { whip[i].cap = capac[j].hor[0] + EDGE/2 - 8 ; whip[i].out = x + opamp.con[0] ; whip[ i ].gnd = x + opamp.con[1] ; } } /* OP-AMP OUTPUT NODE */ else { master = 20000 ; whip[i],out = x + opamp.con[2] ; whip[i].gnd = x + opamp.con[l] ; middle = (whip[i].out + whip[i-1].out)/2 ; /* PICK CLOSEST SC CONNECTION POINT */ for (j=l; j<=total; j++) if (capac[j].typ=='S1 && same(Scapac[j].sec[0],Stable[2][i][0])) { store = abs(middle - (capac[j].hor[0]+EDGE/2+8)) if (store < master) { whip[i].cap = (capac[j].hor[0]+EDGE/2+8) ; clock = capac[j].swtch ; stox = j ; master = store ; } ) /* PICK REVERSE CLOCKING SC */ flag = 1 ; capac[stox].used = 1 ; for (j=l; j<=total && flag; j++) if (capac[j].typ=='S• && same(Scapac[j].sec[0],Stable[2][i][0])) if (capac[j].swtch!=clock) ( capac[j].used = 1 ; flag = 0 ; } /* MIRROR OP-AMP IF NECCESSARY */ if (turn(i-1)) ( whip[i-l].out = whip[i-l].out + opamp.width - 2*opa whip[i].out = whip[i].out + opamp.width - 2*opamp.c whip[i-l].gnd = whip[i-l].gnd + opamp.width - 2*opa whip[i-1].mirror = 1 ; } /* INCREMENT THE PLACEMENT */ gap2 = gap2 + inc - gap ; gap = gap2 ; x = x + opamp.width + gap ; } } > /******************************************************* /* */ /* WIRE5 FUNCTION — Connect Op-Amp Inputs/Outputs */ /*/* The wire5 function connects the -inputs and the */ 195 wire5(fdto) FILE *fdto /* OUTPUT FILE */ { int yc2,yc3,yc4,yc5 ; int xa,xb,xc,a,b ; int dir ; int adj ; int flag,f2 ; int i,j,m ; int k ; /* /* /* /* /* /* /* VERTICAL CONNECTS */ HORIZONTAL CONNECTS */ CONNECTION DIRECTION */ CAP CONTACT ADJUST */ WIRING PLACEMENT FLAGS */ INDEX VARIABLES */ WIRING LEVEL */ /* EMPTY THE WIRING GRID */ for (i=0; i<5; i++) for (j=0; j<5000; j++) path2[i][j] =0 ; /* INITIALIZE THE VERTICAL CONNECTION LEVELS */ yc2 = level[1] - 33*U ; yc3 = level[1] - 27*U ; yc4 = level[1] - 18*U ; level[6] = 0 ; /* PROCESS ONE OP-AMP CONNECTION AT A TIME */ for (i=start; i<stages+stages; i++) /* STORE THE CONNECTION POINTS */ ( xa = whip[i].out*U ; xb = whip[i].cap*U ; /* ADJUSTMENT DISTANCE FOR CAP CONTACTS */ adj = ((i%2) ? -12 : 12) ; /* FIND LEFT AND RIGHT CONNECTION POINTS */ if (whip[i].out > whip[i].cap) ( a = whip[i].cap ; b = whip[i].out ; dir = -1 ; } else ( a - whip[i].out ; b = whip[i].cap ; dir = 1 ; } /* SEE IF WIRE CAN BE DRAWN BELOW THE SWITCHES */ flag = 1 ; for (j=start; j<stages+stages; j++) { if (i!=j && whip[j].cap > a-5 && whip[j].cap < b+5) flag = 0 /* SEE IF NO OTHER WIRE IS THERE */ 196 if (flag) for (k=a-3; k<=b+3; k++) if (path2[0][k]!=0) flag = 0 ; /* PLACE WIRE BELOW THE SWITCHES */ if (flag) /* ONLY DRAW HORIZONTAL WIRE IF NECCESSARY */ { if (abs(xa-xb) > 2*U) WIRE(fdto,PlW,w,xa,yc3,xb,yc3) ; /* PLACE CONTACT ON THE SWITCH */ mp(xb,yc3,fdto) ; WIRE(fdto,MlW,w,xb,yc3,xb,yc4) ; /* FILL THE GRID */ for (k=a; k<=b; k++) path2[0][k] = 1 ; /* SAVE WIRE PARAMETERS FOR OP-AMP CONNECTION */ whip[i].cross = whip[i],out ; whip[i].level = yc3 ; } /* DRAW THE WIRE BELOW THE VSS LINE */ else { whip[i].cross = whip[i].cap ; /* DECIDE IF THE CROSSING POINT SHOULD BE MOVED */ for (k=start; k<stages+stages; k++) if (abs(whip[i].cap-whip[k].gnd) < 5 || abs(whip[i].cap-whip[k].out)<5) whip[i].cross = whip[i].cap + adj ; /* FIND LEFT AND RIGHT POINTS */ if (whip[i].cross > whip[i].out) { a = whip[i].out ; b = whip[i].cross ; } else { a = whip[i].cross ; b = whip[i].out ; } /* FIND A WIRE SLOT */ f2 = 1 ; for (k=l; f2; k++) { flag = 1 ; for (m=a-3; m<=b+3; m++) if (path2[k][m]!=0) flag = 0 ; if (flag) f2 = 0 ; } k— ; /* CALCULATE THE WIRE LEVEL */ yc5 = level[1] - (45+6*(k-1))*U ; 197 } if (k-l>level[6]) level[6] = k-1 ; /* FILL THE GRID */ for (m=a-2; m<=b+2; m++) path2[k][m] = 1 ; /* IF NO ADJUSTMENT */ if (whip[i].cross==whip[i].cap) /* PLACE SWITCH CONTACT AND CROSS BUS LINES */ { mp(xb,yc3,fdto) ; WIRE(fdto,M1W, w, xb, yc3, xb,yc4) ; WIRE^fdtOjPlW^xbjycSjX^ycS) ; xc - xa ; } /* WIRE CROSSING HAS BEEN MOVED */ else { xa = whip[i],cap*U ; xb = whip[i].cross*U ; xc = whip[i].out*U ; /* CONNECT SWITCH AND WIRE IT */ mp(xa,yc3,fdto) ; WIRE(fdto,MlW,w,xa,yc3,xa,yc4) ; WIRE(fdto,PlW,w,xb,yc5,xb,yc3) ; WIRE(fdto,PlW,w,xa,yc3,xb,yc3) ; } /* PLACE METAL WIRE WITH CONTACTS IF REQUIRED */ if (abs(xc-xb) > 6*U) { mp(xb,yc5,fdto) ; mp(xc,yc5,fdto) ; WIRE(fdto,MlW/w,xb,yc5,xc,yc5) ; } /* OR DRAW A SHORT POLY LINKING WIRE */ else WIRE(fdto,PlW,w,xb,yc5,xc,yc5) ; /* SAVE WIRING PARAMETERS FOR OP-AMP CONNECTION */ whip[i].level = yc5 ; } } /************************************ /* */* WIRE6 FUNCTION — Wire the Ground Connections */ /*/* The wire6 function connects the +input of the */ /* op-amps to the ground wire. It will curve around any */ /* obstacles. */* */************************************* wire6(fdto) 198 FILE *fdtO /* OUTPUT FILE */ { int yc[6] ; int xa,xb,xb2,a,b ; int dir ; int flag ; int j ; int i,k,m ; /* VERTICAL CONNECTS */ /* HORIZONTAL CONNECTS */ /* WIRING DIRECTION */ /* WIRING FLAG */ /* WIRING LEVEL */ /* INDEX VARIABLES */ /* INITIALIZE THE VERTICAL CONNECT LEVELS */ yc[2] = level[l] - 33*U ; yc[3] = level[l] - 27*U ; yc[4] = level[1] - 18*U ; /* SET THE SEDRA CROSSING POINTS FOR THE FIRST OP-AMP */ if (start==2) { whip[0].cross = capac[2].hor[0]+EDGE/2+8 ; whip[1].cross = capac[2],hor[0]+EDGE/2+8 ; whip[0].gndcross = opamp.con[l] - 1 ; } /* PROCESS ONE GROUND CONNECTION AT A TIME */ for (i=start/2; i<stages; i++) /* FIND WIRE DIRECTION */ { dir = ((whip[2*i].gnd < whip[2*i].out) ? -1 : 1) ; /* TRY TO WIRE THE GROUND CONNECTION */ flag = 1 ; for (k=0; flag; k=k+dir) { flag = 0 ; /* LOOK FOR ANY OBSTACLES */ for (j=start; j<stages+stages; j++) { if (whip[j].level!=yc[3]) if (abs(whip[2*i],gnd+k-whip[j].cross) < 5) /* FINAL CROSSING POINT */ xb = whip[2*i].gnd*U ; k = k - dir ; whip[2*i].gndcross = whip[2*i].gnd + k ; /* PLACE THE DISPLACED WIRE */ if (k!=0) { xb2 = xb + k*U ; /* FIND LEFT AND RIGHT POINTS */ if (k > 0) { a = whip[2*i].gnd ; b = a + k ; ) flag = 1 199 } else { b = whip[2*i].gnd ; a = b + k ; } /* CHECK FOR SPACE IN THE GRID */ flag = 1 ; for (m=a-2; m<=b+2; m++) if (path2[level[6]][m]!=0) flag = 0 ; /* MOVE TO LOWEST LEVEL IF NECCESSARY */ if (!flag) level[6] += 1 ; /* CALCULATE WIRING LEVEL */ yc[5] = level[1] - (45+6*level[6])*U ; whip[2*i].gndlevel = yc[5] ; /* CONNECT THE GROUND WIRE TO THE INPUT */ mp(xb2,yc[2],fdto) ; WIRE(fdto,PlW,w,xb2,yc[5],xb2,yc[2]) ; WIRE(fdto,PlW,w,xb,yc[5],xb2,yc[5]) ; } /* DRAW STRAIGHT WIRE AND CONTACT OTHERWISE */ else { mp(xb,yc[2],fdto) ; whip[2*i].gndlevel = yc[2] ; } } /***********************************************************/ /* */* AMPSON FUNCTION — Insert the Op-Amps */ /*/* The ampson function places and connects the op-amps */ /* to the previously placed wires. */*/************************************** ampson(fdto) FILE *fdto ; /* OUTPUT FILE */ { int i ; * INDEX VARIABLE */ int yc[2] ; /* VERTICAL CONNECTS */ int xa ; * HORIZONTAL CONNECTS */ char *norm ; /* CELL PLACEMENT COMMAND */ /* INITIALIZE THE WIRING LEVELS */ yc[0] = level[1] - (49 + 6*level[6] + opamp.level)*U ; yc[l] = yc[0] + opamp.level*U ; level[2] = yc[0] ; /* CONNECT THE -INPUTS AND OUTPUTS */ for (i=start; i<stages+stages; i++) 200 { xa = whip[i].out*U ; WIRE(fdto,P1W,w,xa,yc[1],xa,whip[i].level) ; ) /* PLACE THE OP-AMPS */ for (i=0; i<stages; i++) /* CONNECT THE +INPUTS */ { if (i>=start/2) ( xa = whip[2*i].gnd*U ; WIRE(fdto,PlW,w,xa,yc[l],xa,whip[2*i].gndlevel) ; ) /* MIRRORED OP-AMP */ if (Jwhip[2*i].mirror) ( xa = (whip[2*i].base - opamp.xorg)*U ; norm = "C2 T" ; } /* NORMAL OP-AMP */ else { xa = (whip[2*i].base + opamp.width + opamp.xorg)*U ; norm = "C2 MX T11 ; ) /* PLACE THE OP-AMP */ cellplace(fdto,norm,xa,yc[0]) ; } /***********************************************************/ /* */* WRAPUP FUNCTION — Layout Global Features */ /*/* The wrapup function places the p-wells, the clocks, */ /* the bus lines, and the substrate contacts. */*/************************************* wrapup(fdto) FILE *fdto /* OUTPUT FILE */ { int i,j ; int wl ; int xa,xb ; int ycl,yc2 ; int xc,yc ; int xedge,yedge /* INDEX VARIABLES */ /* WIRE WIDTH */ /* HORIZONTAL CONNECTS */ /* VERTICAL CONNECTS */ /* BOX CENTRE */ /* BOX EDGES */ /* SUBSTRATE CONTACT CHECKS */ /* SUBSTRATE CONTACT PLACEMENT */ /* HORIZONTAL LAYOUT BOUNDS */ int h[3] ; int flag ; int xl,xr ; /* SET THE HORIZONTAL BOUNDS OF THE LAYOUT */ Xl = -5*U ; xa = (capac[total].hor[0]+capac[total].next*EDGE)*U ; if (xa+2*U > (whip[2*stages-2].base + opamp.width)*U) xr = xa + 6*U ; else xr = (whip[2*stages-2].base + opamp.width + 4)*U /* PLACE THE OUTPUT CONTACT */ if (xa < xr-8*U) WIRE(fdto,MlW,w,xa,level[9],xr-8*U,level[9]) ; WIRE(fdto,PlW,w,xr-8*U,level[9],xr+6*U,level[9]) ; mp(xr+6*U,level[9],fdto) ; mp(xr-8*U,level[9],fdto) ; /* CONNECT CL0CK1 LINE */ yc = level[1] + 6*U ; WIRE(fdto,P1W,w,xl,yc,xr+6*U,yc) ; mp(xr+6*U,yc-U,fdto) ; mp(xl,yc-U,fdto) ; /* CONNECT CL0CK2 LINE */ yc = level[1] - 6*U ; WIRE(fdto,P1W,w,xl,yc,xr+ 6 *U,yc) ; mp(xr+6*U,yc+U,fdto) ; mp(xl,yc+U,fdto) ; /* CONNECT CLOCK 3 LINE */ yc = level[1] - 10*U ; WIRE(fdto,P1W,w,xl,yc,xr+ 6 *U,yc) ; mp(xr+6*U,yc-U,fdto) ; mp(xl,yc-U,fdto) ; /* CONNECT CL0CK4 LINE */ yc = level[1] - 22*U ; WIRE(fdto,P1W,w,xl,yc,xr+ 6 *U,yc) ; mp(xr+6*U,yc+u,fdto) ; mp(xl,yc+U,fdto) ; /* PLACE THE GROUND LINE */ yc = level[1] - 33*U ; WIRE(fdto,M1W, 2 *w, xl+6 *U, y c, xr, y c) ; /* PLACE THE VSS LINE */ yc = level[1] - 39*U ; WIRE(fdto,M1W,2 *w,xl+6 *U,yc,xr,yc) ; /* PLACE THE OP-AMP VSS LINE */ yc = level[2] + opamp.vos[0]*U ; wl = opamp.wid[0]*U ; WIRE(fdto,M1W,wl,xl+4 *U+wl/2,yc,xr-wl/2,yc) ; /* PLACE THE OP-AMP BIAS LINE */ yc = level[2] + opamp.vos[1]*U ; wl = opamp.wid[l]*U ; WIRE(fdto,M1W,wl,xl+4 *U+w1/2,yc,xr-4 *U-wl/2, yc) ; /* PLACE THE OP-AMP VDD LINE */ yc = level[2] + opamp.vos[2]*U ; wl = opamp.wid[2]*U ; WIRE(fdto,M1W,wl,xl+4 *U+wl/2,yc,xr-4 *U-wl/2,yc) ; /* PLACE THE SWITCH P-WELL */ xc = (xl + xr) / 2 ; xedge = xr - xl - 8*U ; yc = level[1] - 55*U/2 ; BOX(fdto,PWB,xedge,31*U,xc,yc) ; /* PLACE THE N+ */ yc = level[1] - 16*U ; BOX(fdto,NPB,xedge,8 *U,xc,yc) ; /* PLACE THE P+ */ yc = level[1] ; BOX(fdto,PPB,xedge,8*U,xc,yc) ; /* PLACE THE P-WELL FOR THE CAPS */ xedge = xr - xl + 6*U ; yedge = level[0] - level[1] + (EDGE/2 + 1)*U ; yc = (level[0] + (17 + EDGE/2)*U + level[1]) / 2 ; BOX(fdto,PWB,xedge,yedge,xc+U,yc) ; /* INITIALIZE THE VERTICAL LEVELS FOR THE SUB CONTACTS yc = level[3] + 6*U ; ycl = level[0] + (5 + EDGE/2)*U ; yc2 = level[2] + opamp.vos[0]*U ; /* PLACE GROUND WIRES AND SUB CONTACTS FOR CAP P-WELL WIRE(fdto,M1W,2 *w,xl+2 *U,yc,xl+2 *U,ycl) ; WIRE(fdto,MlW,2*w,xr,yc2,xr,level[l] - 39*U) ; WIRE(fdto,MlW,2*w,xr,level[l]-33*U,xr,ycl) ; for (i=0; i*40*U<=ycl-yc; i++) { mps(xl+2*U,yc+i*40*U,fdto) ; mps(xr,yc+i*40*U,fdto) ; } WIRE(fdto,M1W,2 *w,xl+2 *U,ycl,xr,ycl) ; for (i=0; xl+(15+i*40)*U<=xr-15*U; i++) mps(xl+(15+i*40)*U,ycl,fdto) ; /* PLACE THE SUB CONTACTS BELOW THE CAPS */ for (i=l; i<=total; i++) { if (capac[i].typ=='C) { xc = (capac[i].hor[0] + EDGE/2)*U ; 203 > mps(xc,level[1]+12*U,fdto) ; WIRE(fdto,MlW,w,xc,level[l]+12*U,xc,level[1]-33*U) ; } if (capac[i].typ=='Sl && !capac[i].used) { yc = 10*capac[i].hor[2] ; if (ycl=level[l]+17*U) { xc = (capac[i].hor[0] + EDGE/2)*U ; mps(xc,level[1]+12*U,fdto) ; WIRE(fdto,M1W,w,xc,level[1]+12 *U,xc,level[1]-3 3 *U) /* PLACE THE SUB CONTACTS ALONG THE VSS LINE */ xc = xl + 8*U ; yc = level[1] - 39*U ; while (xc < xr - 8*U) { flag = 1 ; for (j=0; j<stages; j++) /* GET THE CROSSING POINTS */ { h[0] = whip[2*j].cross*U ; h[l] = whip[2*j+l].cross*U ; h[2] - whip[2*j],gndcross*U ; /* LOOK FOR A CROSSING */ for (i=0; i<3; i++) if (abs(h[i] - xc) < 6*U) flag = 0 ; ) /* IF NO CROSSING, PLACE A CONTACT */ if (flag) { mps(xc,yc,fdto) ; xc = xc + 40*U ; } /* ELSE INCREMENT THE LOCATION AND TRY AGAIN */ else xc = xc + U ; } /***************************^ /* */* INPUT1 FUNCTION — Hard-Wire the Input ( LEE ) */ /*/* The input1 function connects the input switched */ /* capacitor to the filter. */*/************************************* input1(fdto) FILE *fdto ; /* OUTPUT FILE */ { int XC[3] ; /* HORIZONTAL CONNECTIONS */ 204 } int yc[8] ; /* VERTICAL CONNECTIONS */ or[0]+EDGE/2)*U ; /* FIRST CAP */ or[0]+EDGE/2)*U ; /* SECOND CAP */ /* INPUT NODE */ /* CAP CONTACT */ /* SWITCH TOP */ /* FIRST WIRING LEVEL */ /* SECOND WIRING LEVEL */ 33*U ; /* GROUND WIRE */ XC[0] = (capac[l] XC[1] = (capac[2] XC[2] — -5*U ; yc[l] = U ; yc[2] = -13*U ; yc[3] level[1] yc[4] = -3*U ; yc[5] = -8*U ; yc[6] = level[1] yc[7] = level[1] /* PLACE THE INPUT SWITCH AND CONNECT IT TO THE FILTER */ switchplace(xc[l],yc[3],capac[2].swtch,fdto) ; WIRE(fdto,MlW,w,xc[l]+8*U,yc[3],xc[l]+8*U,yc[4]) ; /* CONNECT THE SECOND CAP TO THE SWITCH */ mp2(xc[l],yc[7],fdto) ; WIRE(fdto,MlW,w,xc[l],yc[3],xc[l],yc[7]) ; WIRE(fdto,P2W,w,xc[l],yc[l],xc[l],yc[7]) ; /* CONNECT THE INPUT NODE */ mp(xc[2],yc[2],fdto) ; mp(xc[l]-8*U,yc[2],fdto) ; WIRE(fdto,PlW,w,xc[2],yc[2],xc[l]-8*U,yc[2]) ; WIRE(fdto,PlW,w,xc[0]-8*U,yc[2],xc[0]-8*U,yc[l]) ; WIRE(fdto,MlW,w,xc[l]-8*U,yc[2],xc[l]-8*U,yc[3]) ; /* GROUND THE BOTTOM PLATE OF THE SECOND CAP */ mp(xc[0],yc[5],fdto) ; WIRE(fdto,Plw,w,xc[l]-8*U,yc[5],xc[0],yc[5]) ; WIRE(fdto,PlW,w,xc[l]-8*U,yc[l],xc[l]-8*U,yc[5]) ; WIRE(fdto,MlW,w,xc[0],yc[5],xc[0],yc[6]) ; /******************************************* /* */ /* INPUT2 FUNCTION — Hard-Wire the Input ( MARTIN ) */ /* V /* The input2 function connects the input node to the */ /* first switched capacitor of the filter. */*/********************************************** input2(fdto) FILE *fdto ; /* OUTPUT FILE */ 205 int xcl,xc2 ; /* HORIZONTAL CONNECTS */ int ycl,yc2 ; /* VERTICAL CONNECTS */ xcl = -5*U ; /* INPUT CONNECTION */ xc2 = (capac[l].hor[0]+EDGE/2+8)*U ; /* FIRST CAP */ ycl = level[1] ; /* SWITCH LEVEL */ yc2 = level[1] + 17*U ; /* WIRE LEVEL */ } /* CONNECT THE INPUT NODE TO THE SWITCH */ mp(xcl,yc2,fdto) ; WIRE(fdto,M1W,w,xc2,ycl,xc2,yc2) ; WIRE(fdto,M1W,w,xcl,yc2,xc2,yc2) ; /***********************************************************/ /* */* INPUT3 FUNCTION — Hard-Wire the Input ( SEDRA ) */ /*/*************************************** input3(fdto) FILE *fdto ; ( int xc[15] int yc[15] /* OUTPUT FILE */ /* HORIZONTAL CONNECTS */ /* VERTICAL CONNECTS */ xc[0] = -5*U ; xc[l] = (capac[l] .hor[0]+EDGE/2)*U ; XC[2] = (capac[1] .hor[0]+EDGE+EDGE/2)*U • XC[3] = (capac[2] .hor[0]+EDGE/2-8)*U ; XC[4] • (capac[2] .hor[0]+EDGE/2+8)*U ; XC[5] • (capac[3] .hor[0]+EDGE/2+8)*U ; XC[6] = (capac[4] .hor[0]+EDGE/2-8)*U ; xc[10] = = (opamp.con[1] - 1)*U ; xc[ll] = • (opamp.con[0] - 1)*U ; XC[12] = = (opamp.con[2] - 1)*U ; yc[0] = U ; /* yc[l] = level[1] • /* yc[2] = level[1] - 16*U ; /* yc[3] = level[1] - 33*U ; /* yc[5] = -3*U ; /* yc[6] - -8*U ; /* yc[7] = -13*U ; /* yc[8] - level[1] + 17*U ; yc[l0] = = level[2] + opamp.level*U ; yc[ll] = = level[1] - 27*U ; yc[12] = = level[2] + (opamp.level + 4)*U • 9 /* INPUT NODE */ /* FIRST CAP */ /* EXTENSION */ /* SECOND CAP */ /* SECOND CAP */ /* THIRD CAP */ /* FOURTH CAP */ /* +INPUT */ /* -INPUT */ /* OUTPUT */ PLATE LEVEL */ TOP OF SWITCH */ BOTTOM OF SWITCH */ GROUND WIRE */ CAP CONNECT */ FIRST WIRING LEVEL * SECOND WIRING LEVEL /* TOP WIRE LEVEL */ /* OP-AMP TOP */ /* GAP BELOW SWITCH /* CONNECT LEVEL */ 206 /* PLACE EXTRA SWITCH GROUP AND CONNECT IT */ switchplace(xc[2],yc[l],capac[2].swtch,fdto) ; WIRE(fdto,MlW,w,xc[2]+8*U,yc[2],xc[2]+8*U,yc[3]) ; WIRE(fdto,MlW,w,xc[2]-8*U,yc[5],xc[6],yc[5]) ; WIRE(fdto,MlW,w,xc[2]-8*U,yc[5],xc[2]-8*U,yc[l]) ; /* GROUND BOTTOM PLATE OF INPUT CAPACITOR */ mp(xc[l]+6*U,yc[5],fdto) ; WIRE(fdto,PlW,w,xc[l]+6*U,yc[0],xc[l]+6*U,yc[5]) ; WIRE(fdto,MlW,w,xc[l]+6*U,yc[5],xc[l]+6*U,yc[3]) ; /* CONNECT SECOND CAP TO EXTRA SWITCH GROUP */ mp(xc[3],yc[7],fdto) ; WIRE(fdto,PlW,w,xc[3],yc[0],xc[3],yc[7]) ; WIRE(fdto,MlW,w,xc[2],yc[7],xc[3],yc[7]) j WIRE(fdto,MlW,w,xc[2],yc[7],xc[2],yc[l]) ; /* CONNECT SWITCH GROUPS */ wlRE(fdto,Mlw,w,xc[5],yc[8],xc[5],yc[l]) ; WIRE(fdto,MlW,w,xc[4],yc[8],xc[4],yc[l]) ; WIRE(fdto,MlW,w,xc[4],yc[8],xc[5],yc[8]) ; /* CONNECT SECOND CAP TO ITS SWITCH GROUP */ mp2(xc[l],yc[5],fdto) ; WIRE(fdto,P2W,w,xc[l],yc[5],xc[l],yc[0]) ; WIRE(fdto,MlW,w,xc[l],yc[5],xc[l],yc[l]) ; /* CONNECT INPUT NODE TO INPUT SWITCH */ mp(xc[0],yc[6],fdto) ; WIRE(fdto,MlW,w,xc[0],yc[6],xc[l]-8*U,yc[6]) ; WIRE(fdto,Mlw,w,xc[l]-8*U,yc[6],xc[l]-8*u,yc[l]) ; /* PLACE METAL-ACTIVE CONTACTS */ ma(xc[l]-8*U,yc[l],fdto) ; ma(xc[l],yc[l],fdto) ; ma(xc[l]-8*U,yc[l]-16*U,fdto) ; ma(xc[l],yc[l]-16*U,fdto) ; /* PLACE METAL AND ACTIVE AREAS */ BOX(fdto,MlB,2*U,12*U,xc[l]-8*U,yc[l]-8*U) ; BOX(fdto,MlB,2*U,12*U,xc[l],yc[l]-8*U) ; WIRE(fdto,ACW,w,xc[l],yc[l],xc[l]-8*U,yc[l]) ; WIRE(fdto,ACW,w,xc[l],yc[l]-16*U,xc[l]-8*U,yc[l]-16*U) ; /* DECIDE ON THE CLOCKING SCHEME */ if (capac[1],swtch==l) { yc[13] = level[l] + U ; yc[14] = level[l] - 17*U ; ) else { yc[13] = level[l] - U ; yc[14] = level[l] - 15*U ; ) /* INSERT CLOCKS */ 207 BOX(fdto,PlB,2*U,8*U,XC[l]-4*U,yc[13]) ; BOX(fdto,PlB,2*U,8*U,XC[l]-4*U,yc[14]) ; /* CONNECT +INPUT TO INPUT SWITCH */ mp(xc[l],yc[ll],fdto) ; WIRE(fdto,MlW,w,xc[l],yc[ll],xc[l],yc[2]) ; WIRE(fdto,PlW,w,xc[l],yc[ll],xc[10],yc[ll]) ; wiRE(fdto,Plw,w,xc[l0],yc[ll],xc[l0],yc[l0]) ; /* CONNECT OP-AMP OUTPUT FROM SWITCH */ mp(xc[4],yc[ll],fdto) ; WIRE(fdto,MlW,w,xc[4],yc[ll],xc[4],yc[2]) ; WIRE(fdto,PlW,w,xc[4],yc[12],xc[4],yc[ll]) ; /* CONNECT OUTPUT TO -INPUT */ mp(xc[ll],yc[12],fdto) ; mp(xc[12],yc[12],fdto) ; mp(xc[4],yc[12],fdto) ; WIRE(fdto,PlW,w,xc[ll],yc[10],xc[ll],yc[12]) ; WIRE(fdto,PlW,w,xc[12],yc[10],xc[12],yc[12]) ; WIRE(fdto,MlW,w,xc[ll],yc[12],xc[12],yc[12]) ; } /****************************************************** /* V /* INPUT4 FUNCTION — Hard-Wire the Input ( AROMA ) */ /* */* The input2 function connects the input node to the */ /* first switched capacitor of the filter, and to a */ /* second one with complementary clocks if it exists. A */ /* connected to the first one if it exists. */ /* */************************************^ input4(fdto) FILE *fdto ; /* OUTPUT FILE */ ( int xc[5],yc[5] ; /* CONNECTS */ int i ; * INDEX VARIABLE */ int scone,sctwo ; * CAP LOCATIONS */ int least[2],most[2] ; /* WIRE BOUNDS */ xc[l] = -5*U ; /* INPUT CONNECTION xc[2] = (capac[1].hor[0]+EDGE/2)*U ; /* FIRST CAP */ yc[l] = -3*U ; /* FIRST WIRING LEVEL yc[2] = level[1] ; /* TOP OF SWITCH */ yc[3] = level[1] + 12*U ; /* CONTACT LEVEL */ 208 yc[4] = level[1] + 17*U ; /* TOP WIRE LEVEL */ scone = sctwo = 0 ; for (i=2; i<=total; i++) if (same(&capac[i].sec[0],Stable[0][0][0]) SS capac[i].typ==1S•) ( if (capac[i].swtch!=capac[l].swtch) scone = i ; else sctwo = i ; } xc[3] = (capac[scone].hor[0]+EDGE/2)*U ; xc[4] = (capac[sctwo].hor[0]+EDGE/2)*U ; if (scone!=0 SS sctwo!=0) { mp(xc[l],yc[4],fdto) ; WIRE(fdto,MlW,w,xc[l],yc[4],xc[3]+8*U,yc[4]) ; WIRE(fdto,Mlw,w,xc[3]+8*U,yc[2],xc[3]+8*U,yc[4]) ; WIRE(fdto,MlW,w,xc[2]+8*U,yc[2],xc[2]+8*U,yc[4]) ; least[0] = 4 ; most[0] = 3*sctwo + 1 ; yc[0] = (-5*wireslot(least,most)-3)*U ; WIRE(fdto,Miw,w,xc[4],yc[0],xc[2],yc[0]) ; WIRE(fdto,P2W,w,xc[4],yc[0],XC[4],U) ; mp2(xc[4],yc[0],fdto) ; mp2(xc[2],yc[0],fdto) ; } else ( WIRE(fdto,MlW,w,xc[l],yc[4],xc[2]+8*U,yc[4]) ; WIRE(fdto,P2W,w,xc[2]+8*U,yc[2],xc[2]+8*U,yc[4]) ; mp(xc[l],yc[4],fdto) ; } ) /************************************************* /* */ /* ATTACH1 FUNCTION ~ Attach Capacitor Plate */*/* The attachl function places a plate with a base */ /* width of EDGE. The height is smaller if a fraction of */ /* less than one is given. */* */*************************************************** attachl(a,b,xdir,ydir,fraction,fdto,flag) int a,b ; /* BASE CO-ORDS */ int xdir,ydir ; /* PLATE DIRECTION */ int flag ; /* LINKING BOX FLAG */ float fraction ; /* PLATE SIZE */ FILE *fdto ; /* OUTPUT FILE */ 209 } int xc,yc ; /* CENTER OF PLATE */ int xp,yp ; * CENTER OF LINKING BOX */ int temp ; /* STORAGE VARIABLE */ int xedl,yedl ; /* PLATE EDGES */. float tret = EDGE ; temp = 2 + tret + fraction*(tret-2) ; /* IF THE DIRECTION IS LEFT OR RIGHT... */ if (ydir == 0) { xc = (2*a + EDGE + xdir*temp)*U/2 ; yc = (2*b-l)*EDGE*U/2 + U ; yedl = (EDGE-2)*U ; xedl = fraction*(EDGE-2)*U ; xp = (2*a + EDGE*(1+xdir))*U/2 ; yp = yc ; } /* IF THE DIRECTION IS UP OR DOWN... */ else ( yc = (2*EDGE*b - EDGE + ydir*temp)*U/2 + U xc - (2*a+EDGE)*U/2 ; xedl = (EDGE-2)*U ; yedl = fraction*(EDGE-2)*U ; yp = (2*b-l+ydir)*EDGE*U/2 + U ; xp = xc ; } /* SAVE THE HIGHEST PLATE LEVEL */ if (yc > level[0]) level[0] = yc ; /* PLACE THE PLATE */ BOX(fdto,P2B,xedl,yedl,xc,yc) ; BOX(fdto,P1B,xedl+2 *U,yedl+2 *U,xc,yc) ; /* PLACE A LINK IF NECCESSARY */ if (flag) BOX(fdto,P2B,2*U,2*U,xp,yp) ; /* PLACE THE TIP IF POSSIBLE */ if (fraction<l.0 && ydir==l) BOX(fdto,P2B,2*U,2*U,xc,yc+U+yedl/2) ; /************************************** /* */ /* ATTACH2 FUNCTION — Attach Capacitor Plate */*/* The attach2 function places a plate if its size is */ /* less than LIMIT. A rectangle is placed on top of the */ /* previous plate to maintain the perimeter to area */ /* ratio. *210 /* */ /****************************************** attach2 (a,b,xdir,ydir, fraction, fdto, flag) int a,b ; /* STARTING CO-ORDS */ int xdir,ydir ; /* PLATE DIRECTION */ int flag ; * !! NOT USED !! */ float fraction ; /* PLATE SIZE */ FILE *fdto ; /* OUTPUT FILE */ { int xc,yc ; /* CENTER OF PLATE */ int xedl,yedl ; /* PLATE EDGES */ float aa ; /* RECTANGLE HEIGHT */ float bb ; * RECTANGLE WIDTH */ float tret = EDGE ; /* FIND THE RECTANGLE SIDES */ aa = 2.0*U*fraction*tret ; bb = tret*U/2.0 + 2.0*U/tret ; /* IF THE PLATE DIRECTION IS LEFT OR RIGHT... */ if (ydir==0) { xedl = aa ; yedl = bb ; xc = (2*a + EDGE + xdir*(EDGE-2))*U/2 + xdir*aa/2 ; yc = (2*b-l)*EDGE*U/2 + U ; } /* IF THE PLATE DIRECTION IS UP OR DOWN... */ else { xedl = bb ; yedl = aa ; yc - ((2*b-l)*EDGE + ydir*(EDGE-2))*U/2 + ydir*aa/2 + U ; xc = (2*a+EDGE)*U/2 ; } /* SAVE THE HIGHEST PLATE CO-ORD */ if (yc > level[0]) level[0] = yc ; /* PLACE THE RECTANGLE */ BOX(fdto,P2B,xedl,yedl,xc,yc) ; BOX(fdto,P1B,xedl+2 *U,yedl+2 *U,xc,yc) ; /* ADD THE TIP IF POSSIBLE */ if (ydir==l) BOX(fdto,P2 B,2 *U,2 *U,xc,yc+U+yedl/2) ; } /********************************************* /* */ /* ATTACH3 FUNCTION — Attach Capacitor Plate */* /* The attach3 function places a plate that is less /* than the full size buf larger than LIMIT. It spreads /* the link width to maintain the perimeter/area ratio. /* /*************************************** attach3(a,b,xdir,ydir,fraction,fdto,flag) int a,b ; /* STARTING CO-ORDS */ int xdir,ydir ; /* PLATE DIRECTION */ int flag ; /* !! NOT USED !! */ float fraction ; /* PLATE SIZE */ FILE *fdto ; /* OUTPUT FILE */ { int xc,yc ; /* PLATE CENTER */ int xp,yp ; /* LINK CENTER */ int xl,yl ; /* LINK SIDES */ int xedl,yedl ; /* PLATE SIDES */ float aa,bb ; /* PLATE VARIABLES */ float tret = EDGE ; /* CALCULATE THE PLATE SIZE */ aa = fraction*(tret + 2.0) - 2. 0 ; bb = tret - fraction*(tret - 2. o) ; /* IF THE PLATE DIRECTION IS LEFT OR RIGHT... */ if (ydir==0) ( xc - (2*a + EDGE + xdir*(2+EDGE+aa))*U/2 ; yc = (2*b-l)*EDGE*U/2 + U ; yedl « (EDGE-2)*U ; xedl = aa*U ; xp = (2*a + EDGE*(1+xdir))*U/2 ; yp = yc ; yl = bb*U ; xl = 2*U ; } /* IF THE PLATE DIRECTION IS UP OR DOWN */ else { yc = ((2*b-l)*EDGE + ydir*(2+EDGE+aa))*U/2 + U xc = (2*a+EDGE)*U/2 ; xedl = (EDGE-2)*U ; yedl = aa*U ; yp = (2*b-l+ydir)*EDGE*U/2 + U ; xp = xc ; xl = bb*U ; yl = 2*U ; } /* SAVE THE HIGHEST PLATE LEVEL */ 212 } if (yc > level[0]) level[0] = yc ; /* PLACE THE PLATE AND LINK */ BOX(fdto,P2B,xedl,yedl,xc,yc) ; BOX(fdto,P2B,xl,yl,xp,yp) ; BOX(fdto,P1B,xedl+2 *U,yedl+2 *U,xc,yc) ; /* PLACE THE TIP IF NECCESSARY */ if (ydir==l) BOX(fdto,P2B,2*U,2*U,xc,yc+U+yedl/2) ; /***********************************************************/ /* */* BOX FUNCTION ~ Write a Box to the CIF File */ /*/* The box function writes a box command to the output */ /* file. The center and edges of the box are used. */ /*/******************************^ BOX(fdto,st,xed,yed,xc,yc) FILE *fdto ; /* OUTPUT FILE */ char *st ; * BOX LAYER */ int xed,yed ; * BOX EDGES */ int xc,yc ; /* BOX CENTER */ { char *BOXCOM = "%s %d %d %d %d %s" ; /* BOX FORMAT */ Char buf[LENGTH] ; /* LINE BUFFER */ /* WRITE THE BOX */ sprintf(buf,BOXCOM,st,xed,yed,XBASE+xc,YBASE+yc,";\n") ; writeline(fdto,buf) ; } /****************************^ /* */ /* CELLPLACE FUNCTION — Place a Cell */*/* The cellplace function places a cell at the given */ /* location. */*/**************************************** cellplace(fdto,st,xc,yc) FILE *fdto ; /* OUTPUT FILE */ char *st ; * CELL CALL */ 213 int xc,yc ; /* CELL POSITION */ { int x,y ; * ACTUAL CELL PLACEMENT */ char buf[LENGTH] ; /* LINE BUFFER */ char *CELL = "%s %d %d %s" ; /* FORMAT */ /* COMPUTE ACTUAL PLACEMENT */ X = XBASE + XC 7 y = YBASE + yc - opamp.yorg*U ; /* PLACE THE CELL */ sprintf(buf,CELL,st,x,y,";\n") ; writeline(fdto,buf) ; } /***********************************************************/ /* */* CLOCKPHASE FUNCTION — Check Phase of a Clock */ /*/* The clockphase function checks the phase of the */ /* specified clock. This is only valid for SC and BS */ /* elements and the clocks must be C or #C. */* */*************************^ clockphase(buf,spot) Char buf[LENGTH] ; /* LINE BUFFER */ int spot ,* /* CLOCK POSITION */ { int i,j ; * INDEX VARAIBLES */ /* MOVE TO THE BEGINNING OF THE FIRST CLOCK */ j = 0 ; while (buf[j++]!=')•) ; while (buf[j]==' ') j++ ; /* ADVANCE TO THE DESIRED CLOCK */ for (i=l; i<=spot; i++) { while (buf[j]!=« ') j++ ; while (buf[j]==' ') j++ ; } /* RETURN 0 IF #C IS FOUND */ return((buf[j]=='#') ? 0 : 1) ; } /******************************************** /* */ /* COPY FUNCTION — String Copy */*214 /* The copy function copies stringl to string2. The */ /* first string must be terminated by an EOW. */* */*************************************** copy(str1,str2) char *strl ; /* INPUT STRING */ char *str2 ; * OUTPUT STRING */ { int i = 0 ; /* INDEX VARIABLE */ /* COPY STRING1 TO STRING2 */ do { *(str2+i) = *(strl+i) ; } while (*(strl+i++)!=EOW && *(strl+i-1)!=EOL) ; /* ALWAYS TERMINATE WITH EOW */ if (*(Strl+i-l)==EOL) *(str2+i-l)=E0W ; /********************************^ /* */ /* DOPE FUNCTION — Check For Array Space */*/* The dope function decides if there is enough space */ /* to insert a plate into the grid. */*/***************************^ dope(x,xdir,y,ydir,count,max) int x,y ; /* STARTING CO-ORDS */ int xdir,ydir ; /* PLATE DIRECTION */ int count ; * CURRENT CAPACITOR */ int max ; /* RIGHT EDGE OF THE GRID */ { int X2,y2 ; /* PLATE CENTER */ int i,j ; * INDEX VARIABLES */ int right ; /* RIGHT BOUNDARY OF CHECK */ int left ; * LEFT BOUNDARY OF CHECK */ int a,b ; * ARRAY CHECK CO-ORDS */ /* FIND THE BOTTOM CORNER OF THE PLATE */ x2 = x + xdir * EDGE ; y2 = y + ydir ; /* FIND THE LIMITS OF THE PLATE */ right = x2 + EDGE + CAPGAP ; 215 } left = x2 - CAPGAP ; /* SEARCH FOR ROOM FOR THE PLATE */ for (i=x2; i<x2+EDGE; i++) if (grid[i][y2]!=0) return(0) ; /* SEARCH FOR ENOUGH GAP AROUND THE PLATE */ for (j=y2-l; j<=y2+l; j++) for (i=left; i<right; i++) /* ONLY CHECK WITHIN THE GRID */ { a = i ; b = j ; if (i<l) a = 1 ; if (i>max-l) a = max-1 ; if (j<l) b = 1 ; if (j>TOPMAX) b = TOPMAX ; if (grid[a][b]!=0 && grid[a][b]!=count) return(0) ; } return(1) ; /*********************************** /* V /* EMPTY FUNCTION — Clears a Column of TABLE */ /* */* The empty function initializes one column of TABLE */ /* to EOW. */*/*************************************** empty(col) int COl ; /* TABLE COLUMN */ { int b ; /* INDEX VARIABLE */ /* INITIALIZE THE COLUMN */ for (b=0; b<50; b++) table[col][b][0] = EOW ; } /****************************************** /* V /* GETNODE FUNCTION — Get One Node of a Line */ /*/* The getnode function returns the requested node */ /* from the given line. */* *216 /***********************************************************/ getnode(buf,pos,vertx) Char buf[LENGTH] ; /* LINE BUFFER */ int pos ; /* NODE POSITION */ char vertx[WORD] ; /* NODE BUFFER */ { int q,i,k ; /* INDEX VARIABLES */ q = i = 0 ; while (buf[i++] !='(•) /* STORE THE REQUESTED NODE */ for (k=l; k<=pos; k++) { while (buf[i] == • •) i++ ; while (buf[i] !='•&& buf[i] != ')') { if (k == pos) vertx[q++] = buf[i++] ; else i++ ; } } vertx[q] = EOW ; } /********************************************* /* V /* MA FUNCTION — Metal-Active Contact */ /* */* The ma function places a metal-active contact at */ /* the given location. */*/***********************************************************/ ma(xc,yc,fdto) int xc,yc ; /* LOCATION */ FILE *fdto ; * OUTPUT FILE */ { /* PLACE THE CONTACT */ BOX(fdto,MlB,4*U,4*U,xc,yc) ; BOX(fdto,ClBf2*U,2*Ufxcfyc) ; BOX(fdto,ACB,4*U,4*U,xc,yc) ; } /************************************** /* */ /* MP FUNCTION — Metal-Polyl Contact */*217 /* The mp function places a metal-polyl contact at the */ /* given location. */* */************************************** mp(xc,yc,fdto) int xc,yc ; /* LOCATION */ FILE *fdto ; * OUTPUT FILE */ { /* PLACE THE CONTACT */ BOX(fdto,MlB,4*U,4*U,xc,yc) ; BOX(fdto,ClB,2*U,2*U,xc,yc) ; BOX(fdto,PlB,4*U,4*U,xc,yc) ; > /***********************************************************/ /* */* MP2 FUNCTION — Metal-Poly2 Contact */ /*/* The mp2 function places a metal-poly2 contact at */ /* the given location. */*mp2(xc,yc,fdto) int xc,yc ; /* LOCATION */ FILE *fdto ; * OUTPUT FILE */ { /* PLACE THE CONTACT */ BOX(fdto,MlB,4*U,4*U,XC,yc) ; BOX(fdto,ClB,2*U,2*U,xc,yc) ; BOX(fdtO,P2B,5*U,5*U,XC,yc) ; } /*********************************** /* */ /* MPS FUNCTION — Substrate Contact to P-well */*/* The mps function places a p-well substrate contact */ /* at the given location. */*/********************************** mps(xc,yc,fdto) int xc,yc ; /* LOCATION */ FILE *fdto ; * OUTPUT FILE */ 218 { /* PLACE THE CONTACT */ BOX(fdto,MlB,4*U,4*U,xc,yc) ; BOX(fdto,ClB,2*U,2*U,xc,yc) ; BOX(fdtO,ACB,4*U,4*U,XC,yc) BOX(fdtofPPBf8*Uf8*Ufxcfyc) ; } /****************************************** /* V /* READCOM FUNCTION — Read Input Data */ /* */* The readcom function reads the input parameters */ /* from the .com file. */*/**********************************^ readcom(fdcom) FILE *fdcom ; /* .COM FILE */ { /* INITIALIZE THE NODE TABLE */ empty(O) ; empty(l) ; empty(2) ; /* READ THE INPUT PARAMETERS */ fscanf(fdcom,"%f %d %d",&LAMBDA,Stopper,&swap) ; fscanf(fdcom,"%d %d",&opamp.xorg,Sopamp.yorg) ; fscanf (fdcom,11 %d %d %d", & opamp. width, & opamp. he ight, &opamp. level) fscanf(fdcom,"%d %d %d",&opamp.con[0],&opamp.con[l],&opamp.con[2 fscanf(fdcom,"%d %d %d",&opamp.vos[0],&opamp.vos[1],&opamp.vos[2 fscanf(fdcom,"%d %d %d",&opamp.wid[0],&opamp.wid[l],&opamp.wid[2 /* INITIALIZE THE CIF UNITS */ U = 100*LAMBDA ; W = 200*LAMBDA 7 /* */ /* READND FUNCTION — Read Nodal Data */*/* The readnd function reads the input parameters from */ /* the .nd file. */*/*************************************** readnd(fdnd,head) FILE *fdnd ; /* .ND FILE */ char head ; * INPUT SECTION STYLE */ 219 { Char line[LENGTH] ; /* LINE BUFFER */ int i ; /* INDEX VARIABLE */ /* INITIALIZE THE NODE TABLE */ readline(fdnd,line) ; copy(&1ine[0],Stable[0][0][0]) ; readline(fdnd,line) ; copy(&line[0],&table[0][1][0]) ; readline(fdnd,line) ; readline(fdnd,line) ; /* READ THE INPUT SECTION NODES */ if (head=='L' || head=='Ml) { copy(&line[0],&table[l][0][0]) ; start = 0 ; } if (head=='S') { copy(&line[0],&table[l][0][0]) ; readline(fdnd,line) ; copy(&line[0],Stable[l][1][0]) ; copy(Stable[1][0][0],&table[2][0][0]) ; copy(Stable[1][1][0],Stable[2][1][0]) ; start = 2 ; } /* READ THE INTEGRATOR NODES */ readline(fdnd,line) ; readline(fdnd,line) ; for(i=start; line[0]!=EOF; i++) { copy(Sline[0],Stable[2][i][0]) ; readline(fdnd,line) ; } /*****************************^ /* */ /* READLINE FUNCTION — Read a Line From File */*/* The readline function reads a line terminated by an */ /* EOL or an EOF from the given input file. */*/*************************************** readline(fdfrom,buf) FILE *fdfrom ; /* INPUT FILE */ Char buf[LENGTH] ; /* LINE BUFFER */ { int q = 0 ; /* INDEX VARIABLE */ Uoa =i ((uioajpj)o^e6 = up)) aixu* A sna Adoo A ana indNI SHJi N3d0 */ A NoiiONna N3do ana */ • ()uadoj¥ ana A ana indNi */ uiojjpj* ana A naaana H3IDYHVHO */ wo w } A ana indino */ •' O4PJ* ana (oq.pj)uosAoxis /¥¥*¥¥¥**¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥/ A *A *9TT3 ^rioABi sujq. oq.ux */ A 9TT? aiO dure-do eirq. sexdoo uox^ounj UOSAOUJS em */ A * ' *A ®TTa aio dutv-do Adoo — NoiiiONna NO3AOHS */ AA¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥/ { .' (T)uari4ea .' (M03=I [T-Xlljnq 95 M03=i [T-X]2Jnq) aTTUA { • (0) uin^aa ([++X]2?nq=| [*.]Tjnq) jx } op /¥ H3I0YHYH0 A9 H310VHYH0 S9NIHIS 3Hi 3HYdW0D */ A siaivaYA xaaNi */ i 0 = X 4UX } A ONIHIS aNooas */ '. zim* «qo /¥ ONIHI.S OLSHia ¥/ Tjnq* JBUO (Zjnq'ijnqJeuiBS A¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥/ A *A *Moa 4SBI */ A au.q. oq. dn sBuxaqs OM4 seaeduioo uoxqounj eui.es em ¥/ A ' */¥ A+XTenbs 6uxa4s syp9u;D — NOIIONfia 3WYS ¥/ A/¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥¥/ { (303 =i [T-b]jnq 55 103 =i [T-bljnq) 9TXUM { .' (uioajpj) o4a6 = [++b]jnq } op /¥ ana indNi am, wona SHSIIOYHYHO QYSH */ QZZ 221 putc(ch,fdto) /* CLOSE INPUT FILE */ fclose(fdfrom) ; ***/ /* The switchplace function places the switch group /* with the appropriate clocking scheme. /* /******************************************** */ */ */ */ */ */ ***/ switchplace(x,y,index,fdto) int x,y ; int index FILE *fdto /* SWITCH CO-ORDS */ /* CLOCKING SCHEME */ /* OUTPUT FILE */ { int i,j ; int xc,yc ; int ycl,yc2,yc3,yc4 /* INDEX VARIABLES */ /* SWITCH PLACEMENT POINTS */ /* WIRING LEVELS */ /* PLACE THE METAL-ACTIVE CONTACTS */ for (i=0-l; i<2; i++) for (j=0; j<2; j++) ma(x+i*8*U,y-j*16*U,fdto) ; /* DRAW THE METAL LINES */ for (i=0-l; i<2; i++) { xc = x + i*8*U ; yc = y - 8*U ; BOX(fdto,MlB,2*U,12*U,xc,yc) ; } /* PUT IN THE ACTIVE LINES */ BOX(fdto,ACB,12*U,2*U,x,y) ; BOX(fdto,ACB,12 *U,2 *U,x,y-16 *U) ; /* CLOCKING SCHEME */ if (capac[index].swtch==l) { ycl = level[1] - U ; yc2 = level[1] - 15*U ; yc3 = level[1] + U ; yc4 = level[1] - 17*U ; } else { ycl = level[1] + U ; yc2 = level[1] - 17*U ; yc3 = level[1] - U ; yc4 = level[1] - 15*U ; } /* INSERT THE Pl TIPS ON THE CLOCK LINES */ BOX(fdtO,PlB,2*U,8*U,X+4*U,ycl) ; 222 BOX(fdto,P1B,2 *U,8 *U,X+4 *U,yc2) ; BOX(fdto,P1B,2 *U,8 *U,X-4 *U,yc3) ; BOX(fdto,P1B, 2 *U, 8 *U, x-4 *U,yc4) ; } /*********************************** /* */ /* TURN FUNCTION — Checks for Op-Amp Mirroring */ /*/* The turn function decides if an opamp should be */ /* imaged. It checks for an intersection of two lines */ /* connecting the opamp nodes to their switch */* connections. */* V /*************************^ turn(i) int i ; /* OP-AMP INDEX */ { int delx,dela ; /* HORIZONTAL BOUNDS */ int xin ; /* INTERCEPT CO-ORD */ int xmin/xminl,xmin2 ; /* LINE MINIMA */ int xmax,xmaxl,xmax2 ; * LINE MAXIMA */ /* FIND HORIZONTAL LENGTHS OF CONNECTIONS */ delx = whip[i].cap - whip[i].out ; dela = whip[i+l].cap - whip[i+l].out ; /* FAULTY CROSSING CHECK */ if (whip[i+1].cap>whip[i+1].out && whip[i].out>whip[i].cap) return(0) ; /* FAULTY CROSSING CHECK */ if (whip[i+1].out>whip[i+1].cap && whip[i+1].cap>whip[i].cap) if (whip[i].cap>whip[i].out) return(0) ; /* FIND MAX AND MIN OF FIRST LINE */ if (delx > 0) { xmaxl = whip[i].cap ; xminl = whip[i].out ; } else { xmaxl = whip[i].out ; xminl = whip[i].cap ; } /* FIND MAX AND MIN OF SECOND LINE */ if (dela > 0) { xmax2 = whip[i+l].cap ; xmin2 = whip[i+l].out ; } else { xmax2 = whip[i+l].out ; xmin2 = whip[i+l].cap ; } /* FIND OVERALL MIN */ if (xminl < xmin2) 223 } xmin = xminl ; else xmin = xmin2 ; /* FIND OVERALL MAX */ if (xmaxl > xmax2) xmax = xmaxl ; else xmax = xmax2 ; /* COMPUTE INTERSECTION POINT */ if (delx!=dela) { xin = (whip[i].cap*dela - whip[i+l].cap*delx)/(dela-delx) if (xin > xmin && xin < xmax) return(1) ; } return(0) ; /************************************** /* */ /* WIRE FUNCTION — Write a Wire to the CIF File */*/* The wire function writes a wire command to the */ /* output file. The width and end-points of the wire are */ /* used./* */********************************^ WIRE(fdto,st,width,xl,y1,x2,y2) FILE *fdto ; /* OUTPUT FILE */ char *st ; * BOX LAYER */ int width ; * WIRE WIDTH */ int xl,yl ; /* WIRE START */ int x2,y2 ; * WIRE FINISH */ { char *WC = "%s %d %d %d %d %d %s" ; /* WIRE FORMAT */ Char buf[LENGTH] ; /* LINE BUFFER */ /* WRITE THE WIRE */ sprintf(buf,WC,st,width,XBASE+Xl,YBASE+y1,XBASE+X2,YBASE+y2 , " writeline(fdto,buf) ; } /******************************************* /* V /* WIRESLOT FUNCTION — Find Wire Level */ /* */* The wireslot function finds the first available */ /* level for a wire to inserted into the grid. The */ 224 wireslot(least,most) int least[2] int most[2] /* LEFT END-POINT */ /* RIGHT END-POINT */ { int i,k ; int flag,f2 int j ; /* INDEX VARIABLES */ /* SEARCH FLAGS */ /* WIRE LEVEL */ /* FIND A HOLE IN THE ARRAY LONG ENOUGH FOR THE WIRE */ f2 = 1 ; for (j=0; f2; { flag = 1 ; for (k=least[0]; k<=most[0]; k++) if (path[j][k]!=0) flag = 0 ; if (flag) f2 = 0 ; } /* FILL THE HOLE */ for (k=least[0]; k<=most[0]; k++) path[j][k] = 1 ; /* UPDATE THE HIGHEST WIRING LEVEL */ if (level[l] > (-5*j-20)*U) level[1] = (-5*j-20)*U ; return(j) ; } /************************************** /* */ /* WRITELINE FUNCTION — Write a Line To File */*/* The writeline function writes a line terminated by */ /* an EOL or an EOF to the output file. *j-writeline(fdto,buf) FILE *fdto ; char buf[LENGTH] /* OUTPUT FILE */ /* LINE BUFFER */ { int q = 0 /* INDEX VARIABLE */ 225 /* WRITE THE LINE TO THE OUTPUT FILE */ do { putc(buf[q++],fdto) ; } while (buf[q-l] != EOL && buf[q-l] ! = EOF && buf[q-l] != EOW) ; 

Cite

Citation Scheme:

    

Usage Statistics

Country Views Downloads
United States 8 0
China 4 6
Japan 2 0
Venezuela 2 0
Thailand 2 0
Poland 1 0
Russia 1 0
City Views Downloads
Ashburn 7 0
Unknown 4 3
Shenzhen 2 6
Tokyo 2 0
Caracas 2 0
Mountain View 1 0
Beijing 1 0
Saint Petersburg 1 0

{[{ mDataHeader[type] }]} {[{ month[type] }]} {[{ tData[type] }]}
Download Stats

Share

Embed

Customize your widget with the following options, then copy and paste the code below into the HTML of your page to embed this item in your website.
                        
                            <div id="ubcOpenCollectionsWidgetDisplay">
                            <script id="ubcOpenCollectionsWidget"
                            src="{[{embed.src}]}"
                            data-item="{[{embed.item}]}"
                            data-collection="{[{embed.collection}]}"
                            data-metadata="{[{embed.showMetadata}]}"
                            data-width="{[{embed.width}]}"
                            async >
                            </script>
                            </div>
                        
                    
IIIF logo Our image viewer uses the IIIF 2.0 standard. To load this item in other compatible viewers, use this url:
http://iiif.library.ubc.ca/presentation/dsp.831.1-0096921/manifest

Comment

Related Items