1
/* -*- tab-width: 4 -*-
3
* Electric(tm) VLSI Design System
5
* File: Applicon860.java
6
* Input tool: Applicon\860 input
8
* Copyright (c) 2008 Sun Microsystems and Static Free Software
10
* Electric(tm) is free software; you can redistribute it and/or modify
11
* it under the terms of the GNU General Public License as published by
12
* the Free Software Foundation; either version 3 of the License, or
13
* (at your option) any later version.
15
* Electric(tm) is distributed in the hope that it will be useful,
16
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18
* GNU General Public License for more details.
20
* You should have received a copy of the GNU General Public License
21
* along with Electric(tm); see the file COPYING. If not, write to
22
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
23
* Boston, Mass 02111-1307, USA.
25
* This code only reads Apple/860 format, and it does not handle many of the
26
* features. It is built from Applicon document A-20482-002, November 1983.
27
* The features that are not included are:
28
* > Only polygons are read, not paths, areas, or CWHA rectangles
29
* > Cell instances cannot scale or stretch and must be manhattan
30
* > Groups are ignored
31
* > Auxiliary records are ignored
32
* > Multilevel polygons are not handled (must be on only one level)
33
* > Polygon records must use default layer and not have their own color
34
* > Text is handled poorly and should be commented out (see below)
35
* The code can accomodate tape or disk format files with optional byte swapping.
37
package com.sun.electric.tool.io.input;
39
import com.sun.electric.database.geometry.Orientation;
40
import com.sun.electric.database.geometry.Poly;
41
import com.sun.electric.database.hierarchy.Cell;
42
import com.sun.electric.database.hierarchy.Library;
43
import com.sun.electric.database.text.TextUtils;
44
import com.sun.electric.database.text.TextUtils.UnitScale;
45
import com.sun.electric.database.topology.NodeInst;
46
import com.sun.electric.database.variable.TextDescriptor;
47
import com.sun.electric.technology.Layer;
48
import com.sun.electric.technology.PrimitiveNode;
49
import com.sun.electric.technology.Technology;
50
import com.sun.electric.technology.Technology.NodeLayer;
51
import com.sun.electric.technology.technologies.Artwork;
53
import java.awt.geom.AffineTransform;
54
import java.awt.geom.Point2D;
55
import java.awt.geom.Rectangle2D;
56
import java.io.IOException;
57
import java.util.HashMap;
58
import java.util.HashSet;
59
import java.util.Iterator;
63
public class Applicon860 extends Input
65
private static final int POLYSPLIT = 999; /* maximum polygon record size (was 62) */
66
private static final int BYTESSWAPPED = 1; /* bit set if bytes are swapped */
67
private static final int TAPEFORMAT = 2; /* bit set if file is tape-blocked */
68
private static final int INITIALIZED = 4; /* bit set if file status is known */
70
private Map<Integer,PrimitiveNode> appleNodeMap = new HashMap<Integer,PrimitiveNode>();
71
private int appleState;
73
private int [] polylist;
74
private int polylistcount = 0;
75
private int [] px, py;
76
private Point2D [] ptrace;
79
* Method to import a library from disk.
80
* @param lib the library to fill
81
* @return the created library (null on error).
83
protected Library importALibrary(Library lib)
87
if (!readAppleLibrary(lib)) return null; // error reading the file
88
} catch (IOException e) {}
93
* Method to read the Applicon file.
94
* @param lib the Library to fill.
97
* Method to read the Applicon file.
98
* @param lib the Library to fill.
99
* @return True if no error was found
100
* @throws IOException
102
private boolean readAppleLibrary(Library lib)
106
int chain, length, type, i, eitype, offset, lvlgrp, layer, polyptr, nfl, nfh, nfe, tcount,
107
st, levels, a1, a2, a3, a4, lx, hx, ly, hy;
108
int [] cidata = new int[32];
109
String name, units, cellname;
110
int x1, y1, xoff = 0, yoff = 0;
111
Cell curfacet, subnp = null;
112
PrimitiveNode layernp = null;
116
// establish linkage between Apple numbers and primitives
120
Set<Integer> notFound = new HashSet<Integer>();
124
chain = appleGetChain();
125
if (chain != 3 && chain != 1)
127
System.out.println("CHAIN=" + chain + " at byte " + byteCount);
130
length = appleGetWord();
131
type = appleGetWord();
134
case 2: // top global parameter record
135
case 254: // cell global parameter record
139
System.out.println("Top global parameter length=" + length); else
140
System.out.println("Cell global parameter length=" + length);
144
for(int k=0; k<30; k++) name += dataInputStream.readByte();
145
st = name.indexOf(']') + 1;
146
i = name.indexOf('.', st);
147
if (i >= 0) name = name.substring(0, i);
150
for(int k=0; k<4; k++) units += dataInputStream.readByte();
151
nfl = appleGetWord();
152
nfh = appleGetWord();
153
nfe = appleGetWord();
154
scale = appleFloat(nfl, nfh, nfe) / 2147483648.0;
155
if (units.equals("MIL "))
157
// 25.4 microns to the mil
158
scale = TextUtils.convertFromDistance(scale*25.4, Technology.getCurrent(), UnitScale.MICRO);
159
} else if (units.equals("INCH"))
161
// 25400 microns to the inch
162
TextUtils.convertFromDistance(scale*25400.0, Technology.getCurrent(), UnitScale.MICRO);
166
scale = TextUtils.convertFromDistance(scale, Technology.getCurrent(), UnitScale.MICRO);
168
xoff = appleGetWord() & 0xFFFF;
169
xoff |= (appleGetWord() & 0xFFFF) << 16;
170
yoff = appleGetWord() & 0xFFFF;
171
yoff |= (appleGetWord() & 0xFFFF) << 16;
172
curfacet = Cell.makeInstance(lib, name.substring(st));
173
if (curfacet == null)
175
System.out.println("Cannot create facet '" + name.substring(st) + "'");
180
case 3: // element instance record
183
System.out.println("Element instance length=" + length);
186
lvlgrp = appleGetWord();
187
levels = appleGetWord() & 0xFFFF;
188
levels |= (appleGetWord() & 0xFFFF) << 16;
189
for(i=0; i<32; i++) if (levels == (1 << i)) break;
192
System.out.println("Unknown layer code " + levels);
195
layer = lvlgrp * 32 + i + 1;
197
eitype = appleGetWord();
198
appleGetWord(); // numeir
199
appleGetWord(); // textflg
202
case 0: break; // polygon
203
case 1: break; // area
204
case 2: break; // path
205
case 3: break; // rectangle
208
Integer layerInt = new Integer(layer);
209
layernp = appleNodeMap.get(layerInt);
210
if (layernp == null && !notFound.contains(layerInt))
212
System.out.println("Warning: Apple layer " + layer + " not found");
213
notFound.add(layerInt);
217
case 101: // polygon record
218
appleGetWord(); // color
219
appleGetWord(); // draw
221
if (length-offset > polylistcount)
224
polylist = new int[length-offset];
225
px = new int[((length-offset)+4)/5];
226
py = new int[((length-offset)+4)/5];
227
ptrace = new Point2D[((length-offset)+4)/5];
228
polylistcount = length - offset;
231
while (length > POLYSPLIT)
233
for(i=0; i<POLYSPLIT-offset; i++)
234
polylist[polyptr++] = appleGetWord();
235
chain = appleGetChain();
236
if (chain != 2 && chain != 0)
238
System.out.println("END CHAIN=" + chain + " at byte " + byteCount);
244
for(i=0; i<length-offset; i++)
245
polylist[polyptr++] = appleGetWord();
246
if (polyptr > polylistcount)
247
System.out.println("Just overflowed " + polylistcount + " long array with " + polyptr + " points");
248
if ((chain&2) == 0) appleGetWord();
250
// process data into a set of points
252
for(i=0; i<polyptr; i++)
254
px[i] = polylist[i*5] & 0xFFFF;
255
px[i] |= (polylist[i*5+1] & 0xFFFF) << 16;
256
py[i] = polylist[i*5+2] & 0xFFFF;
257
py[i] |= (polylist[i*5+3] & 0xFFFF) << 16;
258
px[i] = appleScale(px[i], xoff, scale);
259
py[i] = appleScale(py[i], yoff, scale);
260
if ((polylist[i*5+4]&2) != 0 && i != 0)
261
System.out.println("Warning: point " + i + " of polygon has s=" + polylist[i*5+4]);
262
if ((polylist[i*5+4]&1) != 0 && i != polyptr-1)
263
System.out.println("Warning: point " + i + " of polygon has s=" + polylist[i*5+4]);
265
if (px[polyptr-1] == px[0] && py[polyptr-1] == py[0]) polyptr--;
268
for(i=1; i<polyptr; i++)
270
if (px[i] < lx) lx = px[i];
271
if (px[i] > hx) hx = px[i];
272
if (py[i] < ly) ly = py[i];
273
if (py[i] > hy) hy = py[i];
275
for(i=0; i<polyptr; i++)
276
ptrace[i] = new Point2D.Double(px[i] - (lx+hx) / 2, py[i] - (ly+hy) / 2);
278
// now create the polygon
279
if (layernp != null && curfacet != null)
281
Point2D center = new Point2D.Double((lx+hx)/2, (ly+hy)/2);
282
ni = NodeInst.newInstance(layernp, center, hx-lx, hy-ly, curfacet);
283
if (ni == null) return false;
284
ni.newVar(NodeInst.TRACE, ptrace);
288
case 107: // flag record
291
System.out.println("Flag length=" + length);
294
appleGetWord(); // flag
297
case 117: // text record
298
appleGetWord(); // vnumb
299
appleGetWord(); // color
300
appleGetWord(); // lvlgrp
301
appleGetWord(); // levels1
302
appleGetWord(); // levels2
303
appleGetWord(); // txtdx low
304
appleGetWord(); // txtdx high
305
appleGetWord(); // txtdy low
306
appleGetWord(); // txtdy high
307
appleGetWord(); // txtsiz low
308
appleGetWord(); // txtsiz high
309
appleGetWord(); // tfield
310
appleGetWord(); // torien
311
tcount = appleGetWord();
312
if ((tcount&1) != 0) tcount++;
314
// allocate and read the string
316
for(int k=0; k<tcount; k++) str += dataInputStream.readByte();
318
// remove line-feeds, count carriage-returns
320
StringBuffer sb = new StringBuffer();
321
for(int k=0; k<str.length(); k++)
323
char ch = str.charAt(k);
328
} else if (ch != '\n') sb.append(ch);
336
// one carriage return: simple message
337
int crPos = str.indexOf('\n');
338
if (crPos >= 0) str = str.substring(0, crPos);
339
TextDescriptor td = TextDescriptor.getNodeTextDescriptor().withDisplay(true);
340
ni.newVar(Artwork.ART_MESSAGE, str, td);
343
// multi-line message
344
String [] message = str.split("\n");
345
TextDescriptor td = TextDescriptor.getNodeTextDescriptor().withDisplay(true);
346
ni.newVar(Artwork.ART_MESSAGE, message, td);
351
case 4: // cell name record
354
System.out.println("Cell name length=" + length);
358
for(int k=0; k<30; k++) cellname += dataInputStream.readByte();
359
st = cellname.indexOf(']') + 1;
360
i = cellname.indexOf('.', st);
361
if (i >= 0) cellname = cellname.substring(0, i);
362
subnp = lib.findNodeProto(cellname);
365
System.out.println("Instance of cell '" + cellname.substring(st) + "' not found");
370
case 5: // cell instance header record
373
System.out.println("Cell instance header length=" + length);
378
appleGetWord(); // numcir
379
appleGetWord(); // textflg
382
case 105: // cell instance record
384
for(i=0; i<length; i++) cidata[i] = appleGetWord();
387
x1 = cidata[0] & 0xFFFF;
388
x1 |= (cidata[1] & 0xFFFF) << 16;
389
y1 = cidata[2] & 0xFFFF;
390
y1 |= (cidata[3] & 0xFFFF) << 16;
391
x1 = appleScale(x1, xoff, scale);
392
y1 = appleScale(y1, yoff, scale);
395
// ignore stretch point
396
if ((cidata[length-1]&2) != 0) i += 5;
398
// get transformation matrix
399
int rot = 0, trans = 0;
400
if ((cidata[length-1]&4) != 0)
402
a1 = cidata[i] & 0xFFFF;
403
a1 |= (cidata[i+1] & 0xFFFF) << 16;
404
if (a1 == -2147483647) a1 = -1; else
405
if (a1 == 2147483647) a1 = 1; else a1 = 0;
406
a2 = cidata[i+2] & 0xFFFF;
407
a2 |= (cidata[i+3] & 0xFFFF) << 16;
408
if (a2 == -2147483647) a2 = -1; else
409
if (a2 == 2147483647) a2 = 1; else a2 = 0;
410
a3 = cidata[i+4] & 0xFFFF;
411
a3 |= (cidata[i+5] & 0xFFFF) << 16;
412
if (a3 == -2147483647) a3 = -1; else
413
if (a3 == 2147483647) a3 = 1; else a3 = 0;
414
a4 = cidata[i+6] & 0xFFFF;
415
a4 |= (cidata[i+7] & 0xFFFF) << 16;
416
if (a4 == -2147483647) a4 = -1; else
417
if (a4 == 2147483647) a4 = 1; else a4 = 0;
419
// convert to rotation/transpose
420
if (a1 == 0 && a2 == -1 && a3 == 1 && a4 == 0) rot = 900;
421
if (a1 == -1 && a2 == 0 && a3 == 0 && a4 == -1) rot = 1800;
422
if (a1 == 0 && a2 == 1 && a3 == -1 && a4 == 0) rot = 2700;
423
if (a1 == 0 && a2 == -1 && a3 == -1 && a4 == 0)
427
if (a1 == -1 && a2 == 0 && a3 == 0 && a4 == 1)
432
if (a1 == 0 && a2 == 1 && a3 == 1 && a4 == 0)
437
if (a1 == 1 && a2 == 0 && a3 == 0 && a4 == -1)
444
if (subnp != null && curfacet != null)
446
// determine center of instance
447
Orientation orient = Orientation.fromC(rot, trans != 0);
448
AffineTransform mat = orient.pureRotate();
449
Rectangle2D subBounds = subnp.getBounds();
450
Point2D dest = new Point2D.Double(0, 0);
451
mat.transform(new Point2D.Double(subBounds.getCenterX(), subBounds.getCenterY()), dest);
452
double vx = dest.getX() + x1;
453
double vy = dest.getY() + y1;
454
Point2D center = new Point2D.Double(subBounds.getWidth(), subBounds.getHeight());
455
ni = NodeInst.newInstance(subnp, center, vx*2, vy*2, curfacet, orient, null, 0);
456
if (ni == null) return false;
460
case 255: // end definition record
463
System.out.println("End definition length=" + length);
466
if (curfacet == null)
468
System.out.println("End definition has no associated begin");
475
case 0: // format record
476
for(i=0; i<length-2; i++) appleGetWord();
478
case 1: // title record
479
for(i=0; i<length-2; i++) appleGetWord();
481
case 100: // group record
482
for(i=0; i<length-2; i++) appleGetWord();
484
case 104: // auxiliary record
485
for(i=0; i<length-2; i++) appleGetWord();
488
System.out.println("Unknown record type: " + type);
496
* Method to get the chain value from disk.
497
* Automatically senses byte swapping and tape/disk format.
499
private int appleGetChain()
504
if ((appleState&INITIALIZED) == 0)
506
// on first call, evaluate nature of file
507
appleState |= INITIALIZED;
508
chain = appleGetWord();
509
if (chain == 3 || chain == 1) return(chain);
511
// tape header may be present
512
if (Character.isDigit(chain&0377) && Character.isDigit((chain>>8)&0377))
515
appleState |= TAPEFORMAT;
516
chain = appleGetWord();
519
// bytes may be swapped
520
if (chain == 0x300 || chain == 0x100)
522
appleState |= BYTESSWAPPED;
528
// normal chain request
529
if ((appleState&TAPEFORMAT) != 0)
531
// get 4-digit code, skip to end of block
532
for(int i=0; i<4; i++)
534
int val = dataInputStream.readByte();
535
updateProgressDialog(2);
536
if (Character.isDigit(val)) continue;
540
chain = appleGetWord();
544
private int appleGetWord()
547
byte low = dataInputStream.readByte();
548
byte high = dataInputStream.readByte();
549
updateProgressDialog(2);
550
if ((appleState&BYTESSWAPPED) == 0) return (low&0377) | ((high&0377)<<8);
551
return (high&0377) | ((low&0377)<<8);
555
* Method to convert the Apple floating point representation in "lo", "hi"
556
* and "exp" into a true floating point number
558
private double appleFloat(int lo, int hi, int exp)
563
i = (lo & 0xFFFF) | ((hi & 0xFFFF) << 16);
567
if ((i & 0x80000000) != 0) fl = -fl;
571
static Poly poly = null;
573
private void setupAppleLayers()
575
Technology tech = Technology.getCurrent();
576
for(Iterator<PrimitiveNode> it = tech.getNodes(); it.hasNext(); )
578
PrimitiveNode pn = it.next();
579
if (pn.getFunction() == PrimitiveNode.Function.NODE)
581
NodeLayer [] nls = pn.getLayers();
582
for(int i=0; i<nls.length; i++)
584
NodeLayer nl = nls[i];
585
Layer lay = nl.getLayer();
586
int appleLayer = lay.getIndex(); // TODO: should get the user-specified apple/860 layer
587
appleNodeMap.put(new Integer(appleLayer), pn);
594
* Method to convert from Apple units, through offset "offset" and scale
595
* "scale" and return the proper value
597
private int appleScale(int value, int offset, double scale)
601
temp = value - offset;
605
// round to the nearest quarter micron
606
if ((value % 25) != 0)
608
if (value > 0) value = (value+12) / 25 * 25; else
609
value = (value-12) / 25 * 25;