]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/libs/polygon/doc/gtl_tutorial.htm
bump version to 12.2.2-pve1
[ceph.git] / ceph / src / boost / libs / polygon / doc / gtl_tutorial.htm
CommitLineData
7c673cae
FG
1<html>
2
3<head>
4<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">
5<title>Polygon Usage</title>
6</head>
7
8<body>
9
10<h1>Layout Versus Schematic Tutorial</h1>
11<p>In this tutorial we will implement a toy VLSI layout verification
12application.&nbsp; In VLSI CAD an important step of design is the sign off check
13that verifies that the physical layout as drawn by mask designers and automated
14tools implements the logical schematic specified by design engineers.&nbsp;
15Physical layout is modeled as polygons on layers that are used to print the
16layout to the silicon wafer during manufacture.&nbsp; It is much better to find
17physical design mistakes before spending millions of dollars to prepare
18lithography masks and run a test lot of wafers.</p>
19<p>Real layout file formats are binary and often compressed and represent a
20folded hierarchical model of layout where a group of polygons can be grouped
21into a cell and instantiated as a group into other cells.&nbsp; For this
22tutorial we assume a simplified ascii layout file format with no design
23hierarchy, which we would call &quot;flat&quot; in VLSI jargon.&nbsp; Similarly we assume
24a flat, ascii logical schematic net list file format.&nbsp; A net is a named
25electrical connection in a circuit design.&nbsp; The goal of the layout
26verification tutorial is to parse these two file formats, apply geometry
27operations provided by Boost.Polygon on the layout data to generate a logical
28schematic that represents what is implemented in the physical layout and then
29compare the input schematic with the generated schematic to determine whether
30they are the same.</p>
31<p>First let us define some objects that we will need in the design of our toy
32layout verification application:</p>
33<p>Layout Rectangle: An axis-parallel rectangle with a layer associated<br>
34Layout Pin: An axis-parallel rectangle with a layer and net (electrical signal)
35name associated<br>
36Layout Database: An associative container of layer name to polygon set<br>
37Connectivity Database: An associative container of net name to layout database<br>
38Physical Device: A specific geometric arrangement on several layers with one or
39more input net and one output net<br>
40Logical Net: A named graph node<br>
41Logical Device: An un-named graph node with a device type<br>
42Logical Pin: A special net that defines an input or output for the circuit<br>
43Schematic Database: A graph consisting of nets and logical
44devices</p>
45<p>Next let's define the sequence of operations performed by our toy
46layout versus schematic application:</p>
47<p>Parse Layout: Stream layout rectangles and polygons into a layout database
48and stream layout pins into a connectivity database<br>
49Extract Connectivity: Add polygons from layout database to connectivity database
50by physical touch or overlap relationship<br>
51Extract Devices: Populate a schematic database with logical devices based on
52physical devices identified within the layout geometry and extract their
53terminals from the
54connectivity database<br>
55Extract Net List: Complete graph represented in schematic database derived from
56layout<br>
57Parse Schematic: Stream logical nets, devices and pins into a schematic
58database<br>
59Compare Schematics: Evaluate whether extracted schematic database is equivalent
60to input schematic database and output result</p>
61<p>To test our application we will extract single logic gates.&nbsp; A logic
62gate is several transistors that work together to perform a specific logic
63function.&nbsp; Logic functions include the commonly understood Boolean logic
64operations such as Boolean AND, OR, XOR and INVERT.&nbsp; Also frequently used
65are NAND and NOR, which are respectively AND and OR operations followed by an
66INVERT operation.&nbsp; A NAND gate can be implemented in the CMOS circuit
67family with four transistors.&nbsp; The NAND gate has two inputs and one output.&nbsp;
68Each input goes to two transistors, one p-type transistor and one n-type
69transistor.&nbsp; The &quot;p&quot; stands for positive and the &quot;n&quot; stands for negative.&nbsp;
70When the p-type transistor is on
71it pulls the output up to the same voltage as the voltage source.&nbsp; When the
72n-type transistor is on it pulls the output down to the same voltage as the
73ground.&nbsp; The process of creating a p-type transistor begins by &quot;doping&quot; the silicon
74substrate to create n-type material.&nbsp; This area of n-type material will be
75called the NWELL layer in our test data.&nbsp; Within the area of NWELL a
76p-diffusion area is created by further doping the silicon to create p-type
77material.&nbsp; This area of p-type material will be called PDIFF in our test
78data.&nbsp; Through the middle of a PDIFF area bars of poly-silicon are grown
79that create conductive lines over the diffusion area.&nbsp; The area of
80poly-silicon material will be called POLY in our test data.&nbsp; Under some of these
81poly-silicon lines a thin layer of silicon-oxide provides insulation but allows
82the voltage field of the poly-silicon to interact with the diffusion.&nbsp; Each
83of these insulated poly-silicon lines is the &quot;gate&quot; of a transistor.&nbsp;
84The gate area will be called GATE in our test data.&nbsp; When the
85voltage at the gate is the same as the ground voltage the p-type transistor is
86&quot;on&quot; and can pass current from the voltage source to the output .&nbsp; The
87poly-silicon lines that are not insulated create electrical connections to the
88transistor for output signals and source voltage.&nbsp; The n-type transistor
89differs from the p-type in that its diffusion is n-type material outside of NWELL area.&nbsp; Current can pass from the output to the ground when the
90voltage at the gate of the n-type transistor is at the source voltage level.&nbsp;
91Above the poly-silicon layer is a layer of silicon-oxide insulator with holes
92cut out of it that get filled in with metal.&nbsp; These metal filled holes are
93called vias and we will refer to this layer as VIA0 in our test data.&nbsp; On
94top of VIA0 is a layer of metal polygons with silicon oxide insulator between
95them.&nbsp; These metal polygons are wires and we will call them METAL1 in our
96test data.&nbsp; The Layout Pins in our test data will be on METAL1.&nbsp; In a
97NAND gate the two n-type transistors are configured in series, meaning that the
98output of one is the input voltage source of the other.&nbsp; Only if both
99n-type transistors of a NAND gate are &quot;on&quot; will the output be connected to
100ground, signifying a logical &quot;false&quot;.&nbsp; The two p-type transistors in a NAND
101gate are configured in parallel.&nbsp; If either input to the NAND gate is a
102logical &quot;false&quot; the p-type transistor it is connected to will be &quot;on&quot; and the
103output of the gate will be a logical &quot;true&quot; because the transistor will connect
104it to the voltage supply.&nbsp; The diagram below is an example of how a NAND
105gate might be laid out and is not drawn to scale for any real process
106technology.&nbsp; The diffusion material is intended to be cut away under the
107gate material by a Boolean NOT operation and is represented as solid bars under
108the gates of transistors only for convenience of drawing.</p>
109<p>
110<img border="0" src="images/NAND.PNG" width="602" height="387"></p>
111<p>The following is the input layout file for the above NAND gate layout,
112rectangle format is XL XH YL YH:</p>
113<p><font face="Courier New" size="2">Rectangle 0 60 24 48 NWELL<br>
114Rectangle 3 57 32 43 PDIFF<br>
115Rectangle 3 57 5 16 NDIFF<br>
116Rectangle 5 7 0 17 POLY<br>
117Rectangle 5 7 22 45 POLY<br>
118Rectangle 17 19 3 45 POLY<br>
119Rectangle 29 31 31 48 POLY<br>
120Rectangle 41 43 3 45 POLY<br>
121Rectangle 53 55 3 45 POLY<br>
122Rectangle 17 19 4 17 GATE<br>
123Rectangle 17 19 31 44 GATE<br>
124Rectangle 41 43 4 17 GATE<br>
125Rectangle 41 43 31 44 GATE<br>
126Rectangle 5 7 0 2 VIA0<br>
127Rectangle 5 7 23 25 VIA0<br>
128Rectangle 17 19 28 30 VIA0<br>
129Rectangle 29 31 46 48 VIA0<br>
130Rectangle 41 43 18 20 VIA0<br>
131Rectangle 53 55 23 25 VIA0<br>
132Rectangle 0 60 0 2 METAL1<br>
133Rectangle 3 57 28 30 METAL1<br>
134Rectangle 0 60 46 48 METAL1<br>
135Rectangle 3 57 18 20 METAL1<br>
136Rectangle 3 57 23 25 METAL1<br>
137Pin 29 31 0 2 METAL1 GND<br>
138Pin 29 31 23 25 METAL1 OUTPUT</font><font face="Courier New" size="2"><br>
139Pin 29 31 28 30 METAL1 INPUT1</font><font face="Courier New" size="2"><br>
140Pin 29 31 46 48 METAL1 VDD<br>
141Pin 29 31 18 20 METAL1 INPUT2</font></p>
142<p>
143<img border="0" src="images/nands.PNG" width="421" height="402"></p>
144<p>The following is the logic schematic net list file for the above NAND gate
145schematic:</p>
146<p><font face="Courier New" size="2">Pin OUTPUT<br>Pin INPUT1<br>Pin INPUT2<br>
147Pin VDD<br>Pin GND<br>Device PTRANS VDD INPUT1 OUTPUT<br>Device PTRANS VDD
148INPUT2 OUTPUT<br>Device NTRANS GND INPUT1 NET1<br>Device NTRANS NET1 INPUT2
149OUTPUT</font></p>
150<p>A human can look at this schematic and compare it to the drawn layout of the
151NAND gate above to verify that the drawn layout matches what the schematic says
152in a few seconds.&nbsp; If you do that now you will probably find the p and
153n-type transistors and trace the connectivity of the inputs and power to the
154terminals of the transistors and then to the output.&nbsp; Since there are on
155the order of one billion transistors on a single chip these days we need to go a
156lot faster than humans can inspect layout and make fewer mistakes.&nbsp; Using polygon set operations
157and polygon connectivity extraction provided by Boost.Polygon we will automate
158the identification of transistors and the tracing of connectivity.&nbsp; Based
159on this
160<a href="analysis.htm">analysis</a> of Boost.Polygon performance we can expect
161this methodology to easily scale up to million gate blocks on standard
162workstations and arbitrarily large designs given sufficient system memory.&nbsp;
163let's start
164by implementing some data structures for our application.</p>
165<p><font face="Courier New" size="2">struct layout_rectangle {<br>
166&nbsp; int xl, yl, xh, yh;<br>
167&nbsp; std::string layer;<br>
168};</font></p>
169<p>Our layout rectangle is nice and minimal, just enough to store its data.&nbsp;
170It is defined in <a href="tutorial/layout_rectangle.hpp">layout_rectangle.hpp</a>. Next
171let's implement the layout
172pin in a similar way.</p>
173<p><font face="Courier New" size="2">struct layout_pin {<br>
174&nbsp; int xl, yl, xh, yh;<br>
175&nbsp; std::string layer;<br>
176&nbsp; std::string net;<br>
177};</font></p>
178<p>Our layout pin is defined in <a href="tutorial/layout_pin.hpp">layout_pin.hpp</a>.&nbsp; Now
179let's define a layout database object and populate it from our parsed
180layout data in in <a href="tutorial/layout_database.hpp">layout_database.hpp</a>.</p>
181<p><font face="Courier New" size="2">typedef std::map&lt;std::string,
182boost::polygon::polygon_90_set_data&lt;int&gt; &gt; layout_database;<br>
183<br>
184//map the layout rectangle data type to the boost::polygon::rectangle_concept<br>
185namespace boost { namespace polygon{<br>
186&nbsp; template &lt;&gt;<br>
187&nbsp; struct rectangle_traits&lt;layout_rectangle&gt; {<br>
188&nbsp;&nbsp;&nbsp; typedef int coordinate_type;<br>
189&nbsp;&nbsp;&nbsp; typedef interval_data&lt;int&gt; interval_type;<br>
190&nbsp;&nbsp;&nbsp; static inline interval_type get(const layout_rectangle&amp;
191rectangle, orientation_2d orient) {<br>
192&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(orient == HORIZONTAL)<br>
193&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return interval_type(rectangle.xl,
194rectangle.xh);<br>
195&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return interval_type(rectangle.yl, rectangle.yh);<br>
196&nbsp;&nbsp;&nbsp; }<br>
197&nbsp; };<br>
198<br>
199&nbsp; template &lt;&gt;<br>
200&nbsp; struct geometry_concept&lt;layout_rectangle&gt; { typedef rectangle_concept
201type; };<br>
202}}<br>
203<br>
204//insert layout rectangles into a layout database<br>
205inline void populate_layout_database(layout_database&amp; layout, std::vector&lt;layout_rectangle&gt;&amp;
206rects) {<br>
207&nbsp; for(std::size_t i = 0; i &lt; rects.size(); ++i) {<br>
208&nbsp;&nbsp;&nbsp; layout[rects[i].layer].insert(rects[i]);<br>
209&nbsp; }<br>
210}</font></p>
211<p>We don't need to insert pins into the layout database because it doesn't know
212anything about connectivity, just geometry.&nbsp; However, we do need to know
213something about connectivity to compare a schematic to a layout, so we need to
214define our connectivity database and some logical objects.&nbsp; First we define
215an object for a logical device in <a href="tutorial/device.hpp">device.hpp</a>.&nbsp;
216Since we are lazy this object does double duty as a pin and both types of
217transistor.&nbsp; A traditional object oriented design might declare a base
218class with virtual destructor and derive every device from that.&nbsp; Since we
219aren't paid by the line of code let's just keep things simple.</p>
220<p><font face="Courier New" size="2">struct device {<br>
221&nbsp; std::string type;<br>
222&nbsp; std::vector&lt;std::string&gt; terminals;<br>
223};</font></p>
224<p>Now let's define a schematic database object in
225<a href="tutorial/schematic_database.hpp">schematic_database.hpp</a> and populate it from our parsed
226schematic data.</p>
227<p><font face="Courier New"><font size="2">struct schematic_database{<br>
228&nbsp; std::vector&lt;device&gt; devices;<br>
229&nbsp; std::map&lt;std::string, std::set&lt;std::size_t&gt; &gt; nets;<br>
230};<br>
231<br>
232//given a vector of devices populate the map of net name to set of device index<br>
233inline void extract_netlist(std::map&lt;std::string, std::set&lt;std::size_t&gt; &gt;&amp; nets,<br>
234&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
235std::vector&lt;device&gt;&amp; devices) {<br>
236&nbsp; for(std::size_t i = 0; i &lt; devices.size(); ++i) {<br>
237&nbsp;&nbsp;&nbsp; for(std::size_t j = 0; j &lt; devices[i].terminals.size(); ++j)
238{<br>
239&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //create association between net name and device
240id<br>
241&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
242nets[devices[i].terminals[j]].insert(nets[devices[i].terminals[j]].end(), i);<br>
243&nbsp;&nbsp;&nbsp; }<br>
244&nbsp; }<br>
245}</font></font></p>
246<p>Our schematic database is just a vector of devices, which are associated to
247nets by name through their terminals and a map of net name to set of device
248index into the vector, which completes the graph by associating nets with their
249devices.&nbsp; Given the devices and their terminal nets we easily build the
250mapping from nets to devices with the extract_netlist operation.&nbsp; Now we
251are ready to start working on extracting our layout to a derived schematic
252database.&nbsp; However, first we need to build a physical connectivity database
253with geometry in it before we can build a logical connectivity database from the
254layout.&nbsp; We define a simple connectivity database in
255<a href="tutorial/connectivity_database.hpp">connectivity_database.hpp</a> as a
256map of net name to layout database of geometry connected to that net and
257populate it with the layout database and pin data.</p>
258<p><font size="2" face="Courier New">typedef std::map&lt;std::string,
259layout_database &gt; connectivity_database;<br>
260<br>
261//map layout pin data type to boost::polygon::rectangle_concept<br>
262namespace boost { namespace polygon{<br>
263&nbsp; template &lt;&gt;<br>
264&nbsp; struct rectangle_traits&lt;layout_pin&gt; {<br>
265&nbsp;&nbsp;&nbsp; typedef int coordinate_type;<br>
266&nbsp;&nbsp;&nbsp; typedef interval_data&lt;int&gt; interval_type;<br>
267&nbsp;&nbsp;&nbsp; static inline interval_type get(const layout_pin&amp; pin,
268orientation_2d orient) {<br>
269&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(orient == HORIZONTAL)<br>
270&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return interval_type(pin.xl, pin.xh);<br>
271&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return interval_type(pin.yl, pin.yh);<br>
272&nbsp;&nbsp;&nbsp; }<br>
273&nbsp; };<br>
274<br>
275&nbsp; template &lt;&gt;<br>
276&nbsp; struct geometry_concept&lt;layout_pin&gt; { typedef rectangle_concept type; };<br>
277}}</font></p>
278<p><font size="2" face="Courier New">//given a layout_database we populate a
279connectivity database<br>
280inline void populate_connectivity_database(connectivity_database&amp; connectivity,<br>
281&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
282std::vector&lt;layout_pin&gt;&amp; pins, layout_database&amp; layout) {<br>
283&nbsp; using namespace boost::polygon;<br>
284&nbsp; using namespace boost::polygon::operators;<br>
285&nbsp; for(std::size_t i = 0; i &lt; pins.size(); ++i) {<br>
286&nbsp;&nbsp;&nbsp; connectivity[pins[i].net][pins[i].layer].insert(pins[i]);<br>
287&nbsp; }<br>
288&nbsp; int internal_net_suffix = 0;<br>
289&nbsp; //connect metal1 layout to pins which were on metal1<br>
290&nbsp; connect_layout_to_layer(connectivity, layout[&quot;METAL1&quot;], &quot;METAL1&quot;, <br>
291&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
292&quot;METAL1&quot;, &quot;__internal_net_&quot;, internal_net_suffix);<br>
293&nbsp; //connect via0 layout to metal1<br>
294&nbsp; connect_layout_to_layer(connectivity, layout[&quot;VIA0&quot;], &quot;VIA0&quot;, <br>
295&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
296&quot;METAL1&quot;, &quot;__internal_net_&quot;, internal_net_suffix);<br>
297&nbsp; //poly needs to have gates subtracted from it to prevent shorting through
298transistors<br>
299&nbsp; polygon_set poly_not_gate = layout[&quot;POLY&quot;] - layout[&quot;GATE&quot;];<br>
300&nbsp; //connect poly minus gate to via0<br>
301&nbsp; connect_layout_to_layer(connectivity, poly_not_gate, &quot;POLY&quot;, <br>
302&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
303&quot;VIA0&quot;, &quot;__internal_net_&quot;, internal_net_suffix);<br>
304&nbsp; //we don't want to short signals through transistors so we subtract the
305gate regions<br>
306&nbsp; //from the diffusions<br>
307&nbsp; polygon_set diff_not_gate = (layout[&quot;PDIFF&quot;] + layout[&quot;NDIFF&quot;]) -
308layout[&quot;GATE&quot;];<br>
309&nbsp; //connect diffusion minus gate to poly<br>
310&nbsp; //Note that I made up the DIFF layer name for combined P and NDIFF<br>
311&nbsp; connect_layout_to_layer(connectivity, diff_not_gate, &quot;DIFF&quot;, <br>
312&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
313&quot;POLY&quot;, &quot;__internal_net_&quot;, internal_net_suffix);<br>
314&nbsp; //connect gate to poly to make connections through gates on poly<br>
315&nbsp; connect_layout_to_layer(connectivity, layout[&quot;GATE&quot;], &quot;GATE&quot;, <br>
316&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
317&quot;POLY&quot;, &quot;__internal_net_&quot;, internal_net_suffix);<br>
318&nbsp; //now we have traced connectivity of the layout down to the transistor
319level<br>
320&nbsp; //any polygons not connected to pins have been assigned internal net
321names<br>
322}</font></p>
323<p>This populate connectivity database function is our first real use of
324Boost.Polygon in our application.&nbsp; Here we are doing Boolean (polygon set)
325operations on layout layers to merge together the PDIFF and NDIFF layers and cut
326away the GATE layer from the result, for example.&nbsp; We connect up the layout
327starting from the pins and working our way down the layer stack to the
328transistor level.&nbsp; It would work equally well to work our way up the layer
329stack, or connect things up in any order, really, but this way produces fewer
330internal temporary nets that need to be merged when connections between them are
331discovered later.&nbsp; The connect layout to layer function used above needs to
332be implemented before we can populate our connectivity database.</p>
333<p><font size="2" face="Courier New">inline void
334connect_layout_to_layer(connectivity_database&amp; connectivity, polygon_set&amp;
335layout, <br>
336&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
337std::string layout_layer, std::string layer,<br>
338&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
339std::string net_prefix, int&amp; net_suffix) {<br>
340&nbsp; if(layout_layer.empty())<br>
341&nbsp;&nbsp;&nbsp; return;<br>
342&nbsp; boost::polygon::connectivity_extraction_90&lt;int&gt; ce;<br>
343&nbsp; std::vector&lt;std::string&gt; net_ids;<br>
344&nbsp; for(connectivity_database::iterator itr = connectivity.begin(); itr !=
345connectivity.end(); ++itr) {<br>
346&nbsp;&nbsp;&nbsp; net_ids.push_back((*itr).first);<br>
347&nbsp;&nbsp;&nbsp; ce.insert((*itr).second[layer]);<br>
348&nbsp; }<br>
349&nbsp; std::vector&lt;polygon&gt; polygons;<br>
350&nbsp; layout.get_polygons(polygons);<br>
351&nbsp; std::size_t polygon_id_offset = net_ids.size();<br>
352&nbsp; for(std::size_t i = 0; i &lt; polygons.size(); ++i) {<br>
353&nbsp;&nbsp;&nbsp; ce.insert(polygons[i]);<br>
354&nbsp; }<br>
355&nbsp; std::vector&lt;std::set&lt;int&gt; &gt; graph(polygons.size() + net_ids.size(),
356std::set&lt;int&gt;());<br>
357&nbsp; ce.extract(graph);<br>
358&nbsp; std::vector&lt;int&gt; polygon_color(polygons.size() + net_ids.size(), 0);<br>
359&nbsp; //for each net in net_ids populate connected component with net<br>
360&nbsp; for(std::size_t node_id = 0; node_id &lt; net_ids.size(); ++node_id) {<br>
361&nbsp;&nbsp;&nbsp; populate_connected_component(connectivity, polygons,
362polygon_color, graph, node_id, <br>
363&nbsp;&nbsp;&nbsp; polygon_id_offset, net_ids[node_id], net_ids, <br>
364&nbsp;&nbsp;&nbsp; net_prefix, layout_layer);<br>
365&nbsp; }<br>
366&nbsp; //for each polygon_color that is zero populate connected component with
367net_prefix + net_suffix++<br>
368&nbsp; for(std::size_t i = 0; i &lt; polygons.size(); ++i) {<br>
369&nbsp;&nbsp;&nbsp; if(polygon_color[i + polygon_id_offset] == 0) {<br>
370&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::stringstream ss(std::stringstream::in |
371std::stringstream::out);<br>
372&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ss &lt;&lt; net_prefix &lt;&lt; net_suffix++;<br>
373&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::string internal_net; <br>
374&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ss &gt;&gt; internal_net;<br>
375&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; populate_connected_component(connectivity,
376polygons, polygon_color, graph, <br>
377&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i + polygon_id_offset, <br>
378&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; polygon_id_offset, internal_net, net_ids, <br>
379&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net_prefix, layout_layer);<br>
380&nbsp;&nbsp;&nbsp; }<br>
381&nbsp; }<br>
382}</font></p>
383<p>The connect layout to layer function uses the connectivity extraction feature
384of Boost.Polyon to build a connectivity graph for polygons on the input polygon
385set and in the connectivity database on the specified layer.&nbsp; It then finds
386polygons associated with existing nets in the connectivity database through
387graph traversal and inserts them into the connectivity database.&nbsp; Finally,
388polygons that weren't connected to existing nets are inserted into the
389connectivity database on auto-generated internal net names.&nbsp; The insertion
390of a connected component into the connectivity database is handled by the
391recursive traversal of the connectivity graph that we implement next.</p>
392<p><font size="2" face="Courier New">inline void populate_connected_component<br>
393(connectivity_database&amp; connectivity, std::vector&lt;polygon&gt;&amp; polygons, <br>
394&nbsp;std::vector&lt;int&gt; polygon_color, std::vector&lt;std::set&lt;int&gt; &gt;&amp; graph, <br>
395&nbsp;std::size_t node_id, std::size_t polygon_id_offset, std::string&amp; net, <br>
396&nbsp;std::vector&lt;std::string&gt;&amp; net_ids, std::string net_prefix,<br>
397&nbsp;std::string&amp; layout_layer) {<br>
398&nbsp; if(polygon_color[node_id] == 1)<br>
399&nbsp;&nbsp;&nbsp; return;<br>
400&nbsp; polygon_color[node_id] = 1;<br>
401&nbsp; if(node_id &lt; polygon_id_offset &amp;&amp; net_ids[node_id] != net) {<br>
402&nbsp;&nbsp;&nbsp; //merge nets in connectivity database<br>
403&nbsp;&nbsp;&nbsp; //if one of the nets is internal net merge it into the other<br>
404&nbsp;&nbsp;&nbsp; std::string net1 = net_ids[node_id];<br>
405&nbsp;&nbsp;&nbsp; std::string net2 = net;<br>
406&nbsp;&nbsp;&nbsp; if(net.compare(0, net_prefix.length(), net_prefix) == 0) {<br>
407&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net = net1;<br>
408&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; std::swap(net1, net2);<br>
409&nbsp;&nbsp;&nbsp; } else {<br>
410&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; net_ids[node_id] = net;<br>
411&nbsp;&nbsp;&nbsp; }<br>
412&nbsp;&nbsp;&nbsp; connectivity_database::iterator itr =
413connectivity.find(net1);<br>
414&nbsp;&nbsp;&nbsp; if(itr != connectivity.end()) {<br>
415&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(layout_database::iterator itr2 = (*itr).second.begin();<br>
416&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itr2 != (*itr).second.end();
417++itr2) {<br>
418&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connectivity[net2][(*itr2).first].insert((*itr2).second);<br>
419&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
420&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; connectivity.erase(itr);<br>
421&nbsp;&nbsp;&nbsp; }<br>
422&nbsp; }<br>
423&nbsp; if(node_id &gt;= polygon_id_offset)<br>
424&nbsp; connectivity[net][layout_layer].insert(polygons[node_id -
425polygon_id_offset]);<br>
426&nbsp; for(std::set&lt;int&gt;::iterator itr = graph[node_id].begin();<br>
427&nbsp; itr != graph[node_id].end(); ++itr) {<br>
428&nbsp;&nbsp;&nbsp; populate_connected_component(connectivity, polygons,
429polygon_color, graph, <br>
430&nbsp;&nbsp;&nbsp; *itr, polygon_id_offset, net, net_ids, net_prefix,
431layout_layer);<br>
432&nbsp; }<br>
433}<br>
434<br>
435</font>We want to merge internally generated nets into pin nets, which is the
436most complicated part of this simple procedure.&nbsp; Now that we have our
437connectivity database extracted from pins down to transistors we need to extract
438our transistors and establish the relationship between transistor terminals and
439nets in our connectivity database.&nbsp; First let's extract transistors with
440the functions defined in defined in <a href="tutorial/extract_devices.hpp">
441extract_devices.hpp</a>.</p>
442<p><font size="2" face="Courier New">typedef boost::polygon::connectivity_extraction_90&lt;int&gt;
443connectivity_extraction;<br>
444inline std::vector&lt;std::set&lt;int&gt; &gt;<br>
445extract_layer(connectivity_extraction&amp; ce, std::vector&lt;std::string&gt;&amp; net_ids,<br>
446&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
447connectivity_database&amp; connectivity, polygon_set&amp; layout,<br>
448&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
449std::string layer) {<br>
450&nbsp; for(connectivity_database::iterator itr = connectivity.begin(); itr !=
451connectivity.end(); ++itr) {<br>
452&nbsp;&nbsp;&nbsp; net_ids.push_back((*itr).first);<br>
453&nbsp;&nbsp;&nbsp; ce.insert((*itr).second[layer]);<br>
454&nbsp; }<br>
455&nbsp; std::vector&lt;polygon&gt; polygons;<br>
456&nbsp; layout.get_polygons(polygons);<br>
457&nbsp; for(std::size_t i = 0; i &lt; polygons.size(); ++i) {<br>
458&nbsp;&nbsp;&nbsp; ce.insert(polygons[i]);<br>
459&nbsp; }<br>
460&nbsp; std::vector&lt;std::set&lt;int&gt; &gt; graph(polygons.size() + net_ids.size(),
461std::set&lt;int&gt;());<br>
462&nbsp; ce.extract(graph);<br>
463&nbsp; return graph;<br>
464}</font></p>
465<p>This extract layer algorithm constructs a connectivity graph between polygons
466in the input polygon set and polygons in the given layer of the connectivity
467database.&nbsp; It is used to form the association between transistors and their
468terminal nets in the function for extracting a specific transistor type.</p>
469<p><font size="2" face="Courier New">inline void extract_device_type(std::vector&lt;device&gt;&amp;
470devices, connectivity_database&amp; connectivity,<br>
471&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
472polygon_set&amp; layout, std::string type) {<br>
473&nbsp; //recall that P and NDIFF were merged into one DIFF layer in the
474connectivity database<br>
475&nbsp; //find the two nets on the DIFF layer that interact with each transistor<br>
476&nbsp; //and then find the net on the poly layer that interacts with each
477transistor<br>
478&nbsp; boost::polygon::connectivity_extraction_90&lt;int&gt; cediff;<br>
479&nbsp; std::vector&lt;std::string&gt; net_ids_diff;<br>
480&nbsp; std::vector&lt;std::set&lt;int&gt; &gt; graph_diff =<br>
481&nbsp;&nbsp;&nbsp; extract_layer(cediff, net_ids_diff, connectivity, layout,
482&quot;DIFF&quot;);<br>
483&nbsp; boost::polygon::connectivity_extraction_90&lt;int&gt; cepoly;<br>
484&nbsp; std::vector&lt;std::string&gt; net_ids_poly;<br>
485&nbsp; std::vector&lt;std::set&lt;int&gt; &gt; graph_poly =<br>
486&nbsp;&nbsp;&nbsp; extract_layer(cepoly, net_ids_poly, connectivity, layout,
487&quot;POLY&quot;);<br>
488&nbsp; std::vector&lt;device&gt; tmp_devices(graph_diff.size() - net_ids_poly.size());<br>
489&nbsp; for(std::size_t i = net_ids_poly.size(); i &lt; graph_diff.size(); ++i) {<br>
490&nbsp;&nbsp;&nbsp; tmp_devices[i - net_ids_diff.size()].type = type;<br>
491&nbsp;&nbsp;&nbsp; tmp_devices[i - net_ids_diff.size()].terminals = std::vector&lt;std::string&gt;(3,
492std::string());<br>
493&nbsp;&nbsp;&nbsp; std::size_t j = 0;<br>
494&nbsp;&nbsp;&nbsp; for(std::set&lt;int&gt;::iterator itr = graph_diff[i].begin();<br>
495&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itr != graph_diff[i].end(); ++itr,
496++j) {<br>
497&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(j == 0) {<br>
498&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_devices[i - net_ids_diff.size()].terminals[0]
499= net_ids_diff[*itr];<br>
500&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if(j == 1) {<br>
501&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_devices[i - net_ids_diff.size()].terminals[2]
502= net_ids_diff[*itr];<br>
503&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>
504&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //error, too many diff connections<br>
505&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_devices[i - net_ids_diff.size()].terminals
506= std::vector&lt;std::string&gt;(3, std::string());<br>
507&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
508&nbsp;&nbsp;&nbsp; }<br>
509&nbsp;&nbsp;&nbsp; j = 0;<br>
510&nbsp;&nbsp;&nbsp; for(std::set&lt;int&gt;::iterator itr = graph_poly[i].begin();<br>
511&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; itr != graph_poly[i].end(); ++itr,
512++j) {<br>
513&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(j == 0) {<br>
514&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_devices[i - net_ids_diff.size()].terminals[1]
515= net_ids_poly[*itr];<br>
516&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else {<br>
517&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //error, too many poly connections<br>
518&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; tmp_devices[i - net_ids_poly.size()].terminals
519= std::vector&lt;std::string&gt;(3, std::string());<br>
520&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>
521&nbsp;&nbsp;&nbsp; }<br>
522&nbsp; }<br>
523<br>
524&nbsp; devices.insert(devices.end(), tmp_devices.begin(), tmp_devices.end());<br>
525}</font></p>
526<p>We append transistors onto the vector of devices with their terminals
527populated with net names extracted from the connectivity database.&nbsp;
528Transistors' terminals are connected through the POLY and DIFF layers where DIFF
529contains both PDIFF and NDIFF.&nbsp; The connection to POLY layer is the gate of
530the transistor while the connections to DIFF on either side of the channel of
531the transistor are the source and drain.&nbsp; We can use this to extract are p
532and n-type transistors. <font size="2" face="Courier New"><br>
533<br>
534//populates vector of devices based on connectivity and layout data<br>
535inline void extract_devices(std::vector&lt;device&gt;&amp; devices, connectivity_database&amp;
536connectivity,<br>
537&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
538layout_database&amp; layout) {<br>
539&nbsp; using namespace boost::polygon::operators;<br>
540&nbsp; //p-type transistors are gate that interact with p diffusion and nwell<br>
541&nbsp; polygon_set ptransistors = layout[&quot;GATE&quot;];<br>
542&nbsp; ptransistors.interact(layout[&quot;PDIFF&quot;]);<br>
543&nbsp; ptransistors.interact(layout[&quot;NWELL&quot;]);<br>
544&nbsp; //n-type transistors are gate that interact with n diffusion and not
545nwell<br>
546&nbsp; polygon_set ntransistors = layout[&quot;GATE&quot;];<br>
547&nbsp; ntransistors.interact(layout[&quot;NDIFF&quot;]);<br>
548&nbsp; polygon_set not_ntransistors = ntransistors;<br>
549&nbsp; not_ntransistors.interact(layout[&quot;NWELL&quot;]);<br>
550&nbsp; ntransistors -= not_ntransistors;<br>
551&nbsp; extract_device_type(devices, connectivity, ptransistors, &quot;PTRANS&quot;);<br>
552&nbsp; extract_device_type(devices, connectivity, ntransistors, &quot;NTRANS&quot;);<br>
553}</font></p>
554<p>The extract devices procedure makes some more use of Boost.Polygon Boolean
555operations on the layout data when we exclude GATE material over NDIFF that
556isn't also over NWELL to extract our n-type transistors.&nbsp; We also are using
557the &quot;interact&quot; operation on polygon gets, which is implemented in terms of
558connectivity extraction and retains all polygons of a polygon set that touch or
559overlap polygons from another polygon set.&nbsp; Now that we have a vector of
560devices we can build a schematic database by calling the extract_netlist
561function.&nbsp; We can then compare the extracted schematic from the schematic
562read in from file with the functions defined in
563<a href="tutorial/compare_schematics.hpp">compare_schematics.hpp</a>.&nbsp;
564Since comparing two schematics has no geometric aspect we won't go into that
565procedure here in the tutorial and will skip to the integration of all these
566procedures in defined in <a href="tutorial/extract.cpp">extract.cpp</a> to build
567the layout to schematic comparison algorithm.</p>
568<p><font size="2" face="Courier New">bool compare_files(std::string layout_file,
569std::string schematic_file) {<br>
570&nbsp; std::ifstream sin(schematic_file.c_str());<br>
571&nbsp; std::ifstream lin(layout_file.c_str());<br>
572<br>
573&nbsp; std::vector&lt;layout_rectangle&gt; rects;<br>
574&nbsp; std::vector&lt;layout_pin&gt; pins;<br>
575&nbsp; parse_layout(rects, pins, lin);<br>
576<br>
577&nbsp; schematic_database reference_schematic;<br>
578&nbsp; parse_schematic_database(reference_schematic, sin);<br>
579<br>
580&nbsp; layout_database layout;<br>
581&nbsp; populate_layout_database(layout, rects);<br>
582<br>
583&nbsp; connectivity_database connectivity;<br>
584&nbsp; populate_connectivity_database(connectivity, pins, layout);<br>
585<br>
586&nbsp; schematic_database schematic;<br>
587&nbsp; std::vector&lt;device&gt;&amp; devices = schematic.devices;<br>
588&nbsp; for(std::size_t i = 0; i &lt; pins.size(); ++i) {<br>
589&nbsp;&nbsp;&nbsp; devices.push_back(device());<br>
590&nbsp;&nbsp;&nbsp; devices.back().type = &quot;PIN&quot;;<br>
591&nbsp;&nbsp;&nbsp; devices.back().terminals.push_back(pins[i].net);<br>
592&nbsp; }<br>
593&nbsp; extract_devices(devices, connectivity, layout);<br>
594&nbsp; extract_netlist(schematic.nets, devices);<br>
595&nbsp; return compare_schematics(reference_schematic, schematic);<br>
596}</font></p>
597<p><font face="Courier New" size="2">int main(int argc, char **argv) {<br>
598&nbsp; if(argc &lt; 3) {<br>
599&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; &quot;usage: &quot; &lt;&lt; argv[0] &lt;&lt; &quot; &lt;layout_file&gt; &lt;schematic_file&gt;&quot;
600&lt;&lt; std::endl;<br>
601&nbsp;&nbsp;&nbsp; return -1;<br>
602&nbsp; }<br>
603&nbsp; bool result = compare_files(argv[1], argv[2]);<br>
604&nbsp; if(result == false) {<br>
605&nbsp;&nbsp;&nbsp; std::cout &lt;&lt; &quot;Layout does not match schematic.&quot; &lt;&lt; std::endl;<br>
606&nbsp;&nbsp;&nbsp; return 1;<br>
607&nbsp; } <br>
608&nbsp; std::cout &lt;&lt; &quot;Layout does match schematic.&quot; &lt;&lt; std::endl;<br>
609&nbsp; return 0;<br>
610}<br>
611<br>
612</font>We test the program with two schematics and three layouts.&nbsp; These
613include a nand and a nor gate layout and schematic as well as an incorrect nand
614gate layout.&nbsp; The nand layout and schematic are the same as shown above.<font face="Courier New" size="2">
615</font></p>
616<p><font face="Courier New" size="2">&gt; lvs<br>
617usage: lvs &lt;layout_file&gt; &lt;schematic_file&gt;<br>
618&gt; lvs nand.layout nand.schematic <br>
619Layout does match schematic.<br>
620&gt; lvs nand_short.layout nand.schematic <br>
621Layout does not match schematic.<br>
622&gt; lvs nand.layout nor.schematic <br>
623Layout does not match schematic.<br>
624&gt; lvs nor.layout nor.schematic <br>
625Layout does match schematic.<br>
626&gt; lvs nor.layout nand.schematic <br>
627Layout does not match schematic.</font></p>
628<p>This concludes our tutorial on how to build a simple layout to schematic
629verification application based on Boost.Polygon library capabilities.&nbsp; The
630implementation of this application made many simplifying assumptions that are
631not valid in the real world and hard coded a lot of things that need to be
632configurable in a real layout verification application.&nbsp; However, it does
633give an idea of how to use Boost.Polygon to solve real problems and points in
634the direction of how a real application might use Boost.Polygon.</p>
635
636
637<table class="docinfo" rules="none" frame="void" id="table1">
638 <colgroup>
639 <col class="docinfo-name"><col class="docinfo-content">
640 </colgroup>
641 <tbody vAlign="top">
642 <tr>
643 <th class="docinfo-name">Copyright:</th>
644