%const %string (31) VERSION = "Imp LAP Version 4.7A 9-Jul-85" {*************************************************************************} {*************************************************************************} {*** ***} {*** This is ILAP or Imp LAP ***} {*** ***} {*************************************************************************} {*************************************************************************} {#########################################################################} {# #} {# This program is part of the ILAP library, and was written in #} {# The Department of Computer Science at the University of Edinburgh #} {# (James Clerk Maxwell Building, Kings Buildings, Edinburgh) #} {# #} {# This software is available free to other educational establisments #} {# but the University of Edinburgh, retains all commercial rights. #} {# It is a condition of having this software is that the sources are #} {# not passed on to any other site, and that Edinburgh University is #} {# given credit in any re-implementations of any of the algorithms #} {# used, or articles published which refer to the software. #} {# #} {# There is no formal support for this software, but any bugs should #} {# be reported to Gordon Hughes or David Rees at the above address, #} {# are likely to be fixed in a future release. #} {# #} {#########################################################################} ! ! INTRODUCTION: ! ! ILAP is a series of external Imp procedures which allow the ! creation of syntactically correct CIF2.0 representations of integrated ! circuit layouts. By embedding a graphics capability into a high level ! language, the use of control structures and parameterised symbols is ! made available to the designer. ! ! ! DESCRIPTION: ! ! ILAP contains procedures to draw shapes on different mask layers and ! define symbols made of such shapes. The actual individual procedures ! are described below. However, it is important to note here that ILAP is ! very close to CIF 2.0, and that almost all procedure calls translate ! directly into CIF 2.0. Consequently, where the results of certain ! constructions are not described the reader is referred to the definition ! of CIF2.0 given in Mead and Conway's "Introduction to VLSI Systems" ! (chapter 4, section 4.5). ! ! ! DIFFERENCES FROM CIF2.0: ! ! The major differences and restrictions of ILAP from CIF2.0 are summarised below. ! ! All primitive shapes and symbol calls should be in symbols. ! Boxes cannot be specified other than parallel to the axes. ! Symbols can only be rotated parallel to the axes. ! Symbol calls which specify rotation or mirroring are rotated or ! mirrored before translation. ! No symbol definition delete statement. ! ! ! ACCURACY: ! ! All units (i.e. widths, heights, lengths and displacements), are ! specified in terms of lambda. Lambda is the distance by which a ! geometrical feature on one layer may stray from another geometrical ! feature on the same layer or on another layer with all processing ! factors considered and an appropriate safety factor added. The design ! rules given in Mead and Conway are given in terms of lambda. Accuracy ! of all units is preserved to one tenth lambda. ! ! ! The next 20 lines are operating system dependent possibly !%external %integer %fn %spec REM (%integer A, B) %const %string (4) output extension = ".CIF" !%const %string (1) snl = " !" %own %integer cif stream = 3 %own %integer error stream = 0 !%external %integer %fn %spec out stream !%external %routine %spec open output (%integer s, %string (127) file) !%external %routine %spec close output !%external %routine %spec prompt (%string (63) s) !%external %routine %spec set default (%string (5) s) %external %string (63) %fn %spec itos (%integer n, s) %external %string (15) %fn %spec date %external %string (15) %fn %spec time %external %routine %spec check %alias "ILAP__CHECK" (%string (31) s, %byte %array (2) %name data, %short %array (2) %name tran ids, %integer xmax, ymax, xorigin, yorigin) %external %string (127) %fn %spec out file name !%system %routine %spec exit (%integer code) %const %integer true = 1, false = 0 %const %integer smallest = -16_7FFF { maximum bounding box size in lambda %const %integer largest = 16_7FFF { ditto %const %integer max symbols = 127 { Must be a power of 2 minus 1 for 'lookup' to work %const %integer Polygon Type = 1, Line Type = 2 %const %integer ETPX type = 3, ETPY type = 4 %const %integer ETDX type = 5, ETDY type = 6 %const %integer DTPX type = 7, DTPY type = 8 %const %integer DTDX type = 9, DTDY type = 10 %const %integer DTDBX type = 11, DTDBY type = 12 %const %integer Wire type = 13 %const %integer Max type = 13 %const %integer up = 0, down = 1, left = 2, right = 3, none = 4 %const %integer Tr bit = 128 { Indicates that the layer number is part of a transistor %const %integer Tr layer = 7 %const %integer no tr bit = \ Tr bit %const %integer violations = 64 %const %integer max layer = 15 %own %integer last layer = 9 %own %integer last merged layer = 7 %const %integer diff layer = 0 %const %integer poly layer = 1 %const %string (4) %array NMOS codes (0:max layer) = "ND", "NP", "NM", "NI", "NB", "NC", "NV", "NT", "NG", "?" (*) %const %string (4) %array CMOS codes (0:max layer) = "CD", "CP", "CM", "CWP", "CWN", "CC", "CV", "CT", "CG", "CS", "CW", "CA", "?"(*) %own %string (4) %array %name layer codes(0:max layer) %own %string (15) %array NMOS names (0:max layer) = "diffusion", "polysilicon", "metal", "implant", "buried", "contact", "violations", "transistors", "glass", "undefined" (*) %own %string (15) %array CMOS names (0:max layer) = "diffusion", "polysilicon", "metal", "P-well", "N-well", "contact", "violations", "transistors", "glass", "substrate", "well", "active", "undefined" (*) %own %string (15) %array %name layer names(0:max layer) %own %integer %array NMOS widths (0:max layer) = 2, 2, 3, 6, 4, 2, 0, 2, 40, 0 (*) %own %integer %array CMOS widths (0:max layer) = 2, 2, 3, 4, 4, 2, 0, 2, 40, 4, 4, 2, 0 (*) %own %integer %array %name default widths(0:max layer) %own %integer %array widths (0:max layer) = 0 (*) %const %string (35) after init = " must be called before INITIALISE" %record %format symdef(%string(31) name, %integer number, geometry, calls, xl, yl, xu, yu, trans);! Symbol Table Entry format %own %record (symdef) %array symbol table(-1:max symbols) = 0(*) { Symbol Table %own %byte symbols speced = false %own %record (symdef) %name current symbol { current symbol %own %record (symdef) %name call symbol { symbol currently being called %record %format boxf (%short lx, ly, ux, uy, %byte layer, %record (boxf) %name next) %own %record (boxf) %name first box, next box { set to NIL in INILIALISE } %own %string(31) current transistor name = "" { name of transistor %own %string (3) layer before transistor="" { restored after each transistor %own %byte technology = 'N' { Type of MOS. %own %integer current point { index for path %own %integer current type { path type %own %integer current width { for Wires %own %integer init = false { Set TRUE after initialise called %own %integer statements { CIF statement count %own %integer warnings { Error report counter %own %integer current stream { Holds current stream selected by caller %own %integer initial symbol = 100 { Set to first CIF symbol number required can be set by users %own %integer seqno { Number of current symbol %own %integer wlx, wly, wux, wuy, wdir { Wire box bounds (also used for transistor gates)} %own %integer olx, oly, oux, ouy { Transistor overlap boxes } %own %integer ppx, ppy { Position in Path } %own %string (3) gate layer, overlap layer %own %byte depletion transistor = false { type of tran being defined } %own %byte first transistor box = false %const %integer NMOS Lambda = 300, CMOS Lambda = 250, Default Lambda = 250 %own %integer lambda = Default Lambda { Number of 100s of microns in each unit distance %own %integer cifscale = 2 - (Default Lambda&1) { All values are multiplied by this ! If lambda is EVEN => CIFSCALE = 2 => DS n lambda//2 1; ! If lambda is ODD => CIFSCALE = 1 => DS n lambda 1; and polygons used if box is odd sized. %routine %spec dump comment (%string (255) s) %routine %spec dump statement (%string (255) s) %routine %spec end symbol %integer %fn %spec c width %include "ILAPUTIL" ! Which defines MONITOR, NODE NAME, and DUMP LAMBDA %external %integer %fn ILAP warnings %alias "ILAP_WARNINGS" %result = WARNINGS %end %own %integer control = 0 %external %integer %map ILAP control %alias "ILAP_CONTROL" %result == control %end %const %integer no warnings = 1 { Suppress warning messages %const %integer monitor endsym = 2 { Gives a message on ENDSYM %const %integer give times = 4 { Monitor CPU use %const %integer merge = 8 { Produce merged CIF %const %integer design rule check = 16 { Turns on DRC %const %integer circuit analysis = 32 { Let Natalie loose on the design! %const %integer give node list = 64 { Ask for a list of nodes %const %integer give tran list = 128 { Ask for a list of transistors %const %integer give node plot = 256 { Ask for a plot of the extracted circuit. %own %integer current layer = -1, previous layer = -1 ! The significance of the layer integer is - ! <0 => no layer defined ! 0<= layer&noTRbit <=max layer => a known layer (from array) %string(63)%fn layer name(%integer cif name) cif name = cif name & no tr bit %result = layer names(cif name) %if 0<=cif name<=max layer %result = "undefined" %end %external %routine warn %alias "ILAP_WARNING" (%string(255) s) !Outputs a warning message plus some additional information on an error !Also keeps a count of number of warnings %integer i %return %if control & no warnings # 0 i = out stream select output (error stream) print string ("Warning: ") print string (s) print string (" on layer ".layer name(current layer)) %if current layer>=0 print string (" in symbol ".current symbol_name) %if current symbol##nil newline select output (i) warnings = warnings + 1 %end %external %routine die %alias "ILAP_DISASTER" (%string (255) s) ! Abort the program, after a disasterous error. select output (error stream) print string ("Disaster: ") print string (s) print string (" in symbol ".current symbol_name) %if current symbol##nil newline %signal 0, 42 ! exit (16_10000000 + 42) %end %string (63) %fn W P or Tran (%integer current type) ! Returns a string with 'Transistor Polygon or Wire' ! Current point<1 is none or all %const %string (7) %array type(1:max type) = "Polygon", "Line", "ETPX", "ETPY", "ETDX", "ETDY", "DTPX", "DTPY", "DTDX", "DTDY", "DTDBX", "DTDBY", "Wire" %result = "Transistor, Polygon, or Wire" %if current type<1 %result = type(current type) %end %string (31) %fn at point (%integer x, y) %result = " at (X=".itos(x,0)." Y=".itos(y,0).")" %end %routine track error (%string (3) which) ! Check that we are doing a polygon, wire, line, or transistor warn (which." called with no Polygon, Wire, or Transistor being started") %end %routine layer check ! check that user has specified a layer to output on warn ("Layer not defined") %if current layer<0 %end %routine warn outside symbol (%string (255) s, %integer x, y) ! warn a user that geometry of a call is outside a symbol warn (s." outside a symbol".at point(x,y)) %end %routine out num (%integer n) ! Outputs a number in the minimum digits space; write (n, 0) %end %routine initialise (%string (255) ofile) %integer i, char %return %if init=true; !already initialised current stream = out stream select output (error stream) %if ofile="" %start print string (version); newline prompt ("CIF output file name: ") read symbol (char) %until char > ' ' %cycle ofile = ofile.tostring(char) %if char#' ' read symbol (char) %repeat %until char < ' ' %finish ! set default (output extension) ofile = ofile.".CIF" %unless ofile -> (".") %or charno(ofile,1)=':' open output (cif stream, ofile) %if technology = 'N' %start Lambda = nmos lambda layer codes == nmos codes layer names == nmos names default widths == nmos widths last layer = 9 %finish %else %if technology = 'C' %start Lambda = cmos lambda layer codes == cmos codes layer names == cmos names default widths == cmos widths last layer = 11 %finish init = true cifscale = 2 - (lambda&1) first box == nil; next box == nil symbol table (i) = 0 %for i = -1, 1, max symbols current point = -1 current symbol == nil statements = 0 warnings = 0 %if initial symbol<0 %start warn("Initial symbol ".itos(initial symbol,0)." invalid") initial symbol = 100 %finish seqno = initial symbol - 1 widths(i) = default widths(i) %for i = 0, 1, max layer current layer = -1 select output (cif stream) dump comment ("CIF 2.0") dump comment ("File ".outfilename) dump comment ("Produced by ".version." on ".date." at ".time) dump lambda (lambda) select output (current stream) %end %routine new layer (%string (4) colour) %integer new layer, i, current stream warn outside symbol("Set layer",0,0) %if current symbol==nil colour = to string (technology).colour %if length(colour) = 1 current layer = -1 %and %return %if colour = ""; ! Forget current layer new layer = -1 %for I = 0, 1, last layer %cycle new layer = i %if layer codes(i)=colour %repeat %if new layer = -1 %start ! Try to add it : DIE ("Too many layers used") %if last layer = max layer last layer = last layer + 1 layer codes (last layer ) = colour layer names (last layer) = colour widths (last layer) = 2 { as a default } new layer = last layer %finish new layer = new layer ! Tr bit %if new layer >=0 %and current transistor name # "" %return %if current layer=new layer current layer=new layer %if control < merge %or new layer & no tr bit > last merged layer %start current stream = out stream select output (cif stream) print symbol ('L'); space; print string (colour); print symbol (';') newline select output (current stream) statements = statements + 1 %finish %end %string (4) %fn CUR LAYER ! returns the current layer %integer layer layer = current layer & no tr bit %result = layer codes (layer) %if 0<=layer<=last layer %result = "" %end %external %routine fix mbb %alias "ILAP_FIX_MBB" (%integer xl, yl, xu, yu) ! Fixes the size of the symbols bounding box (used by the annotation procedures) warn ("FIX MBB used when no symbol was defined") %and %return %if current symbol==nil current symbol_xl = xl; current symbol_yl = yl current symbol_xu = xu; current symbol_yu = yu %end %external %routine update mbb %alias "ILAP_UPDATE_MBB" (%integer xl, yl, xu, yu) ! Updates if necessary the minimum bounding box of the current symbol %return %if current symbol==nil current symbol_xl=xl %if xlcurrent symbol_xu current symbol_yu=yu %if yu>current symbol_yu %end %integerfn lookup(%string(31)name) !Finds the specified name in the Symbol Table or allocates a new entry !Names are converted to a canonical form (see fn CANONICAL below) !Returns entry -1 if the Symbol Table is full %integer val, i %string(31) %fn canonical(%string(31) name) !Returns parameter in a canonical form i.e. only upper case and spaces removed %string(31) canon name %integer i,char canon name = "" %for i = 1,1,length(name) %cycle char = charno(name,i) char = char-('a'-'A') %if 'a'<=char<'z'; !Lower case to Upper case canon name = canon name.tostring(char) %if char#' ';!Remove spaces %repeat %result = canon name %end name = canonical(name) val = 0 val = val+charno(name,i)<<(i-1) %for i=1,1,length(name) i = val&max symbols i = (i+1)&max symbols %until canonical(symbol table(i)_name)=name %orc symbol table(i)_number=0 %or i=val&max symbols %result = i %unless i=val&max symbols %result = -1 %end %const %integer choose sx = 0, choose sy = 1, choose lx = 2, choose ly = 3 %integer %fn get mbb (%string (31) cell, %integer which) %const %string (2) %array proc (0:3) = "SX", "SY", "LX", "LY" %record (symdef) %name entry %switch sw (0:3) initialise ("") %if init=false entry == symbol table (lookup(cell)) %if entry_number#0 %start %if entry_xu<=entry_xl %or entry_yu<=entry_yl %start warn (proc(which)." is undefined") %result = 0 %finish warn (proc(which)." is of the current symbol") %if entry==current symbol -> sw(which) sw (choose sx): %result = entry_xu - entry_xl sw (choose sy): %result = entry_yu - entry_yl sw (choose lx): %result = entry_xl sw (choose ly): %result = entry_yl %finish warn ("Symbol """.cell.""" not defined for ".proc(which)) %result = 0 %end %routine dump statement (%string (255) s) %integer current stream current stream = out stream select output (cif stream) print string (s); print symbol (';'); newline statements = statements + 1 select output (current stream) %end %routine dump comment (%string (255) s) dump statement ("(".s.")") warn ("Cif Comment contains brackets") %if s -> ("(") warn ("Cif Comment extends across a line") %if s -> (snl) %end %routine dump (%string (15) start, %integer x, y) ! Start dumping the code for either a polygon or a line current stream = out stream select output (cif stream) print string (start) wlx = x; wly = y olx = wlx; oly = wly out num (x*cifscale) out num (y*cifscale) current point = 1 select output (current stream) %end %routine dump point (%integer x, y) current stream = out stream select output (cif stream) out num (x*cifscale) out num (y*cifscale) wlx = x; wly = y update mbb (olx, oly, wlx, wly) current point = current point + 1 newline %if rem (current point, 5) = 0 select output (current stream) %end %routine dump box (%integer xl, yl, xu, yu) current stream = out stream select output (cif stream) %if cifscale=2 %start print symbol ('B') outnum ((xu-xl)*2) outnum ((yu-yl)*2) outnum (xu+xl) outnum (yu+yl) %finish %else %if (xu+xl)&1=0 %and (yu+yl)&1=0 %start print symbol ('B') outnum (xu-xl) outnum (yu-yl) outnum ((xu+xl)//2) outnum ((yu+yl)//2) %else print symbol ('P') outnum (xl); outnum (yl); outnum (xu); outnum (yl) outnum (xu); outnum (yu); outnum (xl); outnum (yu) outnum (xl); outnum (yl) %finish print symbol (';') newline statements = statements+1 select output (current stream) %end %routine output box(%integer xl, yl, xu, yu) ! Saves a box given any diagonally opposite corners ! or outputs it if the layer is not to be saved. %record(boxf)%name box %integer i, l %if xu= merge %and 0<=l<=last merged layer %start box == nil box == new (box) box_next == nil %if first box == nil %start first box == box next box == box box == first box %finish %else %start next box_next == box next box == next box_next %finish box_ly <- yl; box_lx <- xl; box_uy <- yu; box_ux <- xu; box_layer<-current layer %finish %else dump box (xl, yl, xu, yu) %end %routine do transistor implant %if first transistor box = true %start ! Extend the Implant %if wdir=up %start oly = oly - 2 %finish %else %if wdir=down %start ouy = ouy + 2 %finish %else %if wdir=right %start olx = olx - 2 %finish %else %if wdir=left %start oux = oux + 2 %finish first transistor box = false %finish new layer ("NI") output box (olx, oly, oux, ouy) %end %routine bit map to boxes (%byte %array (2) %name bit map, %integer xlim, ylim, originx, originy, layers) %integer p,i,j,x,y,xx,yy,xxlim,mask %byte %name pixel %routine put box (%integer xl, yl, xu, yu,la) !* Outputs a CIF2.0 box %integer st %own %integer l = -1 l = la %and %return %if la<0 st = out stream %if l#la %start l = la select output (cif stream) print symbol ('L') space print string (layer codes(l)) print symbol (';') newline statements = statements+1 %finish dump box (xl, yl, xu, yu) select output (st) %end put box (0, 0, 0, 0, -1) ! The above makes the put box routine forget the layer last used in the ! last cell, as layers are only local to a symbol call. %for p=0,1,last merged layer-1 %cycle mask=1<

=yy-y %start xxlim=xx-1 %exit %finish %else %start yy=yy-1 ->boxout %finish %finish %repeat %repeat boxout: put box(x+originx,y+originy,xxlim+originx+1,yy+originy+1,p) %for j=y,1,yy %cycle %for i=x,1,xxlim %cycle pixel == bit map(i, j) pixel = pixel&(\mask) %repeat %repeat %finish %repeat %repeat %repeat %end %routine Transistor Polygon or Wire check ! Checks if a path of points is being produced if so outputs a set of boxes ! Minimum points for a line is 2 ! Minimum points for a polygon is 3 %switch type (1:max type) %integer i initialise("") %if init=false; !User has not called initialise do it for him %return %if current point<0; !Nothing happening %if current type=Polygon Type %and current point>2 %and (olx#wlx %or oly#wly) %start warn("Polygon not closed".at point(wlx, wly)) %finish i = current point current point = -1 %if (current type=Line type %and i=1) %or (current type=Polygon type %and i=2) %start warn("Incomplete ".W P or Tran(current type).at point(wlx, wly)) %return %finish -> type (current type) type (polygon type): type (line type): current stream = out stream select output (cif stream) Print symbol (';'); newline select output (current stream) statements = statements + 1 %return type (wire type): output box (wlx, wly, wux, wuy) %return type (ETPX type): type (ETPY type): type (ETDX type): type (ETDY type): type (DTPX type): type (DTPY type): type (DTDX type): type (DTDY type): type (DTDBX type): type (DTDBY type): new layer (overlap layer) output box (olx, oly, oux, ouy) ! Extend the gate in the direction that we last went in. %if wdir=up %start wuy = wuy + 2; ouy = ouy + 2 %finish %else %if wdir=down %start wly = wly - 2; oly = oly - 2 %finish %else %if wdir=right %start wux = wux + 2; oux = oux + 2 %finish %else %start { left } wlx = wlx - 2; olx = olx - 2 %finish do transistor implant %if depletion transistor = true new layer (gate layer) output box (wlx, wly, wux, wuy) current transistor name = "" depletion transistor = false new layer (layer before transistor) %end %integer %fn draw first (%string (31) name, %integer x, y) ! Checks if a symbol is defined if it is output first part of call ! Used in conjunction with drawlast %record (symdef)%name entry %own %byte called out side symbol = false Transistor Polygon or Wire check entry == symbol table (lookup (name)) %if entry_number = 0 %start warn ("Call on undefined symbol ".name.at point(x,y)) %result = false %finish %else %start %if entry==current symbol %start warn ("Recursive call on symbol ".name.at point(x,y)) %result = false %finish %else %start %if current symbol##nil %start current symbol_calls = current symbol_calls + 1 current symbol_trans = current symbol_trans + entry_trans %finish %else %start ! ILAP allows 1 call outside a symbol, but warns if more occur. warn outside symbol ("Call of ".name, x, y) %if called out side symbol = true called out side symbol = true %finish current stream = out stream select output(cif stream) print symbol ('C') outnum (|entry_number|) call symbol == entry %result = true %finish %finish %end %string (7) %fn rotation (%integer %name ROT) ! return the rotation component and also normalise ROT to the range 0 to 3 %const %string (4) %array rotations (0:3) = "1 0", "0 1", "-1 0", "0 -1" rot = rem(rem(rot,4)+4,4); !normalise rotation %result = " R ".rotations(rot) %end %routine draw last (%string (15) transform, %integer x, y) ! Outputs final part of symbol call. ! first the transformation information, and then the translation to new x,y print string (transform) print string (" T") outnum (x*cifscale); outnum (y*cifscale); print symbol (';'); newline statements = statements + 1 select output (current stream) %end %routine shape check (%string (15) shape, %integer X, Y) Transistor Polygon or Wire check layer check %if current symbol##nil %start current symbol_geometry = current symbol_geometry+1 %finish %else warn outside symbol (shape, x, y) %end %routine check current symbol %integer cxl, cxu, cyl, cyu, cxd, cyd cxl = current symbol_xl cyl = current symbol_yl cxu = current symbol_xu cyu = current symbol_yu cxd = cxu-cxl-1 cxd = 3 %if cxd<3; ! 0:3 is minimum size that can be DRCed cyd = cyu-cyl-1 cyd = 3 %if cyd<3 %begin %integer i,j,x,y,bit,checks, yl, yu %record(boxf) %name box %byte %array bit map (0 : cxd, 0 : cyd) %short %array tran names (0 : cxd, 0 : cyd) %byte %name pixel !! For EMAS only ! %integer %fn extend (%half I) ! I = I ! 16_FFFF0000 %if I&16_8000#0 ! %result = I ! %end !! End of EMAS only section, (+ delete following set of {} ) %for i = 0, 1, cxd %cycle bit map(i,j) = 0 %for j = 0, 1, cyd %repeat checks = 0 box == first box %while box ## nil %cycle bit = 1<<(box_layer¬rbit) ! (box_layer&trbit) checks = checks ! bit yl = {extend} (box_ly) - cyl { <<< Change on EMAS } yu = {extend} (box_uy) - cyl - 1 { <<< Change on EMAS } %for x = {extend} (box_lx)-cxl, 1, {extend} (box_ux)-cxl-1 %cycle %for y = yl, 1, yu %cycle pixel == bit map(x,y) pixel = pixel ! bit %repeat %repeat first box == box box == box_next dispose (first box) %repeat first box == nil; next box == nil %if control >= design rule check %start monitor ("Starting DRC") %if control & give times # 0 check (current symbol_name, bit map, tran names, cxd, cyd, cxl, cyl) %finish checks = checks ! violations; ! To ensure that they are drawn. monitor ("Start of Bit map to boxes") %if control & give times #0 bit map to boxes (bit map, cxd, cyd, cxl, cyl, checks) monitor ("End of Bit map to boxes ") %if control & give times # 0 %end %end !*** !*** !*** Everything before this point is internal to ILAP !*** Everything after this point is available externally !*** !*** %external %routine symbol %alias "ILAP_SYMBOL" (%string (31) name) %record (symdef) %name entry Transistor Polygon or Wire check %if current symbol##nil %start warn("Nested symbol definition ".name) endsymbol %finish entry == symbol table(lookup(name)) %if entry##symbol table (-1) %start %if entry_number>0 %then warn ("Multiply defined symbol ".name) seqno = seqno+1 %if entry_number = 0 { if it has not been spec'd } previous layer = current layer current layer = -1 current symbol == entry %if current symbol_number=0 %start ! Note that all fields have value 0 if not assigned. current symbol_number = seqno current symbol_name = name current symbol_xl = largest; current symbol_yl = largest current symbol_xu = smallest; current symbol_yu = smallest %finish %else current symbol_number = |current symbol_number| current stream = out stream select output (cif stream) newline; print string ("DS") outnum (current symbol_number) %if cifscale=1 %then outnum(lambda) %else outnum(lambda//2) print string (" 1;") select output (current stream) statements = statements + 1 warn ("Symbol name contains a ';', (trumcated before it)") %if name->name.(";") dump statement ("9 ".name) %finish %else die ("Symbol Table Full adding ".name) monitor ("Start of symbol """.name."""") %if control & give times # 0 %end %external %routine external symbol %alias "ILAP_EXTERNAL_SYMBOL" (%string (31) name, %integer number) %record (symdef) %name entry Transistor Polygon or Wire check %if current symbol##nil %start warn("Nested symbol definition ".name) endsymbol %finish entry == symbol table(lookup(name)) %if entry##symbol table (-1) %start %if entry_number>0 %then warn ("Multiply defined symbol ".name) previous layer = current layer current layer = -1 current symbol == entry %if current symbol_number=0 %start ! Note that all fields have value 0 if not assigned. current symbol_number = number { NB. This should be checked of validity ! } current symbol_name = name current symbol_xl = largest; current symbol_yl = largest current symbol_xu = smallest; current symbol_yu = smallest %finish %else current symbol_number = |current symbol_number| current stream = out stream select output (cif stream) newline; print string ("DS") outnum (current symbol_number) %if cifscale=1 %then outnum(lambda) %else outnum(lambda//2) print string (" 1;") statements = statements + 1 select output (current stream) warn ("Symbol name contains a ';', (trumcated before it)") %if name->name.(";") dump statement ("9 ".name) %finish %else die ("Symbol Table Full adding ".name) monitor ("Start of symbol """.name."""") %if control & give times # 0 %end %external %routine symbol spec %alias "ILAP_SYMBOL_SPEC" %c (%string (31) name, %integer xl, yl, xu, yu) %record (symdef) %name entry Transistor Polygon or Wire check entry == symbol table(lookup(name)) %if entry##symbol table (-1) %start %if entry_number#0 %then warn ("Symbol ".name." conflicts with previous definition") seqno = seqno+1 previous layer = current layer current layer = - 1 entry_number = - seqno entry_name = name entry_xl = xl; entry_yl = yl entry_xu = xu; entry_yu = yu %finish %else die ("Symbol Table Full adding ".name) symbols speced = true %end %external %routine external symbol spec %alias "ILAP_EXTERNAL_SYMBOL_SPEC" %c (%string (31) name, %integer num, xl, yl, xu, yu) %string (255) line %record (symdef) %name entry Transistor Polygon or Wire check %if 0<=numinitial symbol+max symbols %start entry==symbol table(lookup(name)) %if entry##symbol table(-1) %start %if entry_number#0 %then warn ("External symbol ".name." conflicts with internal definition") entry_number=-num; entry_name=name entry_xl=xl; entry_yl=yl entry_xu=xu; entry_yu=yu warn ("Invalid MBB for external symbol ".name) %if xl>xu %or yl>yu line = name line = itos (yu * lambda,0).",".line line = itos (xu * lambda,0).",".line line = itos (yl * lambda,0).",".line line = itos (xl * lambda,0).",".line line = itos (num, 0).",".line dump statement ("8 ".line) %finish %else die ("Symbol Table Full adding external symbol ".name) %finish %else warn ("External symbol ".name." number ".itos(num,0)." conflicts with internal numbers") %end %external %routine end symbol %alias "ILAP_END_SYMBOL" %integer i %string (255) diags Transistor Polygon or Wire check %if current symbol##nil %start %if control # 0 %start diags = "End of symbol """.current symbol_name."""" %if control & monitor end sym # 0 %start diags = diags.itos(current symbol_xl,1).itos(current symbol_yl,1) diags = diags.itos(current symbol_xu,1).itos(current symbol_yu,1) %finish monitor (diags) %if control & (monitor end sym ! give times) # 0 %finish current layer = previous layer widths(i) = default widths(i) %for i=0,1,max layer %if current symbol_geometry>0 %start check current symbol %if control >= merge %finish %else %start %if control >= design rule check %start current stream = out stream select output (0) newline print string ("No check of symbol ".current symbol_name) newline select output (current stream) %finish %finish dump statement ("DF") %if current symbol_xl=largest %and current symbol_yl=largest %and %c current symbol_xu=smallest %and current symbol_yu=smallest %start warn ("No geometry") current symbol_xl=0; current symbol_yl=0 current symbol_xu=0; current symbol_yu=0 %finish current symbol == nil %finish %else warn ("Unmatched endsymbol") %end %external %routine dx %alias "ILAP_DX" (%integer u) track error ("DX") %and %return %if current point < 0 %if polygon type # current type # line type %start %if u#0 %start ppx = ppx + u %if current type # wire type %start ! Transistor %if wdir=up %start ouy = ouy + 2 %finish %else %if wdir=down %start oly = oly - 2 %finish new layer (overlap layer) output box (olx, oly, oux, ouy) do transistor implant %if depletion transistor = true new layer (gate layer) %finish output box (wlx, wly, wux, wuy) %if left#wdir#right %start %if wdir=up %then wly=wuy-current width %else wuy=wly+current width %finish %if u>0 %start wlx = wux; wux = wux + u; wdir = right %finish %else %start wux = wlx; wlx = wlx + u; wdir = left %finish olx = wlx; oux = wux; oly = wly - 2; ouy = wuy + 2 %finish %else warn ("DX of ".W P or Tran (current type)." is zero".at point (ppx,ppy)) %finish %else dump point (wlx+u, wly) %end %external %routine dy %alias "ILAP_DY" (%integer v) track error ("DY") %and %return %if current point < 0 %if polygon type # current type # line type %start %if v#0 %start PPY = PPY + v %if current type # wire type %start ! Transistor %if wdir=right %start oux = oux + 2 %finish %else %if wdir=left %start olx = olx - 2 %finish new layer (overlap layer) output box (olx, oly, oux, ouy) do transistor implant %if depletion transistor = true new layer (gate layer) %finish output box (wlx, wly, wux, wuy) %if up#wdir#down %start %if wdir=right %then wlx=wux-current width %else wux=wlx+current width %finish %if v>0 %start wly = wuy; wuy = wuy + v; wdir = up %finish %else %start wuy = wly; wly = wly + v; wdir = down %finish olx = wlx - 2; oux = wux + 2; oly = wly; ouy = wuy %finish %else warn ("DY of ".W P or Tran (current type)." is zero".at point (ppx,ppy)) %finish %else dump point (wlx, wly+v) %end %external %routine dxy %alias "ILAP_DXY" (%integer dx, dy) track error ("DXY") %and %return %if current point < 0 %unless polygon type # current type # line type %start dump point (wlx+dx, wly+dy) %finish %else warn ("Only polygons and lines may use the DXY construct") %end %external %routine ax %alias "ILAP_AX" (%integer u) track error ("AX") %and %return %if current point < 0 %if polygon type # current type # line type %start %if uwux %then dx (u-wux) %else %start %if wlx#u#wuy %start warn ("AX of ".ITOS(u,0)." is inside the ". %c W P or Tran(current type).at point (ppx, ppy)) %finish %finish %else ppx = u dump point (u, wly) %finish %end %external %routine ay %alias "ILAP_AY" (%integer v) track error ("AY") %and %return %if current point < 0 %if polygon type # current type # line type %start %if vwuy %then dy (v-wuy) %else %start %if wly#v#wuy %start warn ("AY of ".ITOS(v,0)." is inside the ". %c W P or Tran(current type).at point (ppx, ppy)) %finish %finish %else ppy = v dump point (wlx, v) %finish %end %external %routine axy %alias "ILAP_AXY" (%integer x, y) track error ("AXY") %and %return %if current point < 0 %unless polygon type # current type # Line type %start dump point (x, y) %finish %else warn ("Only polygons and lines may use the AXY construct") %end %external %routine wirex %alias "ILAP_WIREX" (%integer x, y, l) shape check ("Wirex", x, y) %return %if CWIDTH<=0 current type = wire type current width = cwidth current point = 0 ppx = x; ppy = y { Position in path for diagnostics } %if l < 0 %start wlx = x + l; wux = x; wdir = left %finish %else %if l > 0 %start wlx = x; wux = x + l; wdir = right %finish %else %start warn ("Zero length Wirex".at point (x, y)) %finish wly = y; wuy = y + current width { Note the box is buffered and is output when a new one is to be buffered } %end %external %routine wirey %alias "ILAP_WIREY" (%integer x, y, l) shape check ("Wirey", x, y) %return %if CWIDTH<=0 current type = wire type current width = cwidth current point = 0 ppx = x; ppy = y { Position in path for diagnostics } %if l < 0 %start wly = y + l; wuy = y; wdir = down %finish %else %if l > 0 %start wly = y; wuy = y + l; wdir = up %finish %else %start warn ("Zero length Wirey".at point(x,y)) %finish wlx = x; wux = x + current width { Note the box is buffered and is output when a new one is to be buffered } %end %external %routine gndwirex %alias "ILAP_GNDWIREX" (%integer x, y, l) shape check ("GNDwirex", x, y) %return %if CWIDTH<=0 warn ("GND wire X not on metal layer") %if layer names (current layer)#"metal" current type = wire type current width = cwidth current point = 0 ppx = x; ppy = y { Position in path for diagnostics } %if l < 0 %start wlx = x + l; wux = x; wdir = left %finish %else %if l > 0 %start wlx = x; wux = x + l; wdir = right %finish %else %start warn ("Zero length Wirex".at point (x, y)) %finish wly = y; wuy = y + current width { Note the box is buffered and is output when a new one is to be buffered } %end %external %routine gndwirey %alias "ILAP_GNDWIREY" (%integer x, y, l) shape check ("GNDwirey", x, y) %return %if CWIDTH<=0 warn ("GND wire Y not on metal layer") %if layer names (current layer)#"metal" current type = wire type current width = cwidth current point = 0 ppx = x; ppy = y { Position in path for diagnostics } %if l < 0 %start wly = y + l; wuy = y; wdir = down %finish %else %if l > 0 %start wly = y; wuy = y + l; wdir = up %finish %else %start warn ("Zero length Wirey".at point(x,y)) %finish wlx = x; wux = x + current width { Note the box is buffered and is output when a new one is to be buffered } %end %external %routine vddwirex %alias "ILAP_VDDWIREX" (%integer x, y, l) shape check ("VDDwirex", x, y) %return %if CWIDTH<=0 warn ("VDD wire X not on metal layer") %if layer names (current layer)#"metal" current type = wire type current width = cwidth current point = 0 ppx = x; ppy = y { Position in path for diagnostics } %if l < 0 %start wlx = x + l; wux = x; wdir = left %finish %else %if l > 0 %start wlx = x; wux = x + l; wdir = right %finish %else %start warn ("Zero length Wirex".at point (x, y)) %finish wly = y; wuy = y + current width { Note the box is buffered and is output when a new one is to be buffered } %end %external %routine vddwirey %alias "ILAP_VDDWIREY" (%integer x, y, l) shape check ("VDDwirey", x, y) %return %if CWIDTH<=0 warn ("VDD wire Y not on metal layer") %if layer names (current layer)#"metal" current type = wire type current width = cwidth current point = 0 ppx = x; ppy = y { Position in path for diagnostics } %if l < 0 %start wly = y + l; wuy = y; wdir = down %finish %else %if l > 0 %start wly = y; wuy = y + l; wdir = up %finish %else %start warn ("Zero length Wirey".at point(x,y)) %finish wlx = x; wux = x + current width { Note the box is buffered and is output when a new one is to be buffered } %end %external %routine box %alias "ILAP_BOX" (%integer xl, yl, xu, yu) shape check ("Box", xl, yl) %if xl=2 %start %if l#0 %start layer before transistor = cur layer current transistor name = name current type = Type current width = w current point = 0 ppx = x; ppy = y { Path position, for error messages } gate layer = gate overlap layer = overlap depletion transistor = true %if DTPX type <= type <= DTDBY type first transistor box = true %if dir='X' %start %if l>0 %start wlx = x; wux = x + l; wdir = right %finish %else %start wlx = x + l; wux = x; wdir = left %finish wly = y; wuy = y + w olx = wlx; oux = wux; oly = wly - 2; ouy = wuy + 2 %if l>0 %then wlx=wlx-2 %else wux=wux+2 %finish %else %start %if l>0 %start wly = y; wuy = y + l; wdir = up %finish %else %start wly = y + l; wuy = y; wdir = down %finish wlx = x; wux = x + w olx = wlx - 2; oux = wux + 2; oly = wly; ouy = wuy %if l>0 %then wly=wly-2 %else wuy=wuy+2 %finish %if current symbol ## nil %then current symbol_trans = current symbol_trans + 1 %finish %else warn ("Zero length ".W P or Tran(type).at point(x,y)) %finish %else warn("Invalid ".W P or Tran(type)." width <2".at point(x,y)) %end %external %routine ETPX %alias "ILAP_ETPX" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(poly layer), 'X', ETPX type, "P", "D") %end %external %routine ETPY %alias "ILAP_ETPY" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(poly layer), 'Y', ETPY type, "P", "D") %end %external %routine ETDX %alias "ILAP_ETDX" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(diff layer), 'X', ETDX type, "D", "P") %end %external %routine ETDY %alias "ILAP_ETDY" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(diff layer), 'Y', ETDY type, "D", "P") %end %external %routine DTPX %alias "ILAP_DTPX" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(poly layer), 'X', DTPX type, "P", "D") %end %external %routine DTPY %alias "ILAP_DTPY" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(poly layer), 'Y', DTPY type, "P", "D") %end %external %routine DTDX %alias "ILAP_DTDX" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(diff layer), 'X', DTDX type, "D", "P") %end %external %routine DTDY %alias "ILAP_DTDY" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(diff layer), 'Y', DTDY type, "D", "P") %end %external %routine DTDBX %alias "ILAP_DTDBX" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(diff layer), 'X', DTDBX type, "D", "P") new layer ("NB"); output box (x-2, y-1, x+2, y+widths(diff layer)+1) %end %external %routine DTDBY %alias "ILAP_DTDBY" (%string (31) name, %integer x, y, l) start tran (name, x, y, l, widths(diff layer), 'Y', DTDBY type, "D", "P") new layer ("NB"); output box (x-1, y-2, x+widths(diff layer)+1, y+2) %end %external %routine layer %alias "ILAP_LAYER" (%string (4) colour) Transistor Polygon or Wire check new layer (colour) %end %external %string (4) %fn clayer %alias "ILAP_CLAYER" ! returns the current layer Transistor Polygon or Wire check %result = CUR LAYER %end %external %routine width %alias "ILAP_WIDTH" (%integer W) ! sets the width of Wires and transistors in the current layer Transistor Polygon or Wire check %if w > 0 %start %if current layer >= 0 %start widths (current layer&(trbit-1)) = W %finish %else warn ("No layer is set") %finish %else warn ("Invalid setting for WIDTH (".itos(W,0).")") %end %external %integer %fn cwidth %alias "ILAP_CWIDTH" ! returns the current width %integer layer Transistor Polygon or Wire check layer = current layer & no tr bit %result = widths (layer) %if 0 <= layer <= last layer %result = 2 %end %external %routine draw %alias "ILAP_DRAW" (%string (31) name, %integer x, y) %if drawfirst(name,x,y)=true %start draw last ("", x, y) update mbb (call symbol_xl+x, call symbol_yl+y, call symbol_xu+x, call symbol_yu+y) %finish %end %external %routine draw mx %alias "ILAP_DRAW_MX" (%string (31) name, %integer x, y) %if drawfirst(name,x,y)=true %start draw last (" MX", x, y) update mbb (-call symbol_xu+x, call symbol_yl+y, -call symbol_xl+x, call symbol_yu+y) %finish %end %external %routine draw my %alias "ILAP_DRAW_MY" (%string (31) name, %integer x, y) %if drawfirst(name,x,y)=true %start draw last (" MY", x, y) update mbb (call symbol_xl+x, -call symbol_yu+y, call symbol_xu+x, -call symbol_yl+y) %finish %end %external %routine draw rot %alias "ILAP_DRAW_ROT" (%string (31) name, %integer x, y, rot) %if drawfirst(name,x,y)=true %start draw last (rotation (rot), x, y) %if rot=0 %start; ! In first quadrant update mbb(call symbol_xl+x, call symbol_yl+y, call symbol_xu+x, call symbol_yu+y) %finish %else %if rot=2 %start; ! In third quadrant update mbb(-call symbol_xu+x,-call symbol_yu+y, -call symbol_xl+x,-call symbol_yl+y) %finish %else %if rot=1 %start; ! In Second quadrant update mbb(-call symbol_yu+x, call symbol_xl+y, -call symbol_yl+x, call symbol_xu+y) %finish %else %start; ! In Fourth quadrant update mbb(call symbol_yl+x,-call symbol_xu+y, call symbol_yu+x,-call symbol_xl+y) %finish %finish %end %external %routine draw mx rot %alias "ILAP_DRAW_MX_ROT" (%string (31) name, %integer x, y, rot) %if drawfirst(name,x,y)=true %start draw last (" MX".rotation (rot), x, y) %if rot=0 %start update mbb(call symbol_xu+x, call symbol_yl+y, call symbol_xl+x, call symbol_yu+y) %finish %else %if rot=2 %start update mbb(-call symbol_yu+x,-call symbol_xu+y, -call symbol_yl+x,-call symbol_xl+y) %finish %else %if rot=1 %start update mbb(call symbol_xl+x, -call symbol_yl+y, call symbol_xu+x, -call symbol_yu+y) %finish %else %start update mbb(call symbol_yl+x,call symbol_xl+y, call symbol_yu+x,call symbol_xu+y) %finish %finish %end %external %routine draw my rot %alias "ILAP_DRAW_MY_ROT" (%string (31) name, %integer x, y, rot) %if drawfirst(name,x,y)=true %start draw last (" MY".rotation (rot), x, y) %if rot=0 %start update mbb(call symbol_xl+x, -call symbol_yu+y, call symbol_xu+x, -call symbol_yl+y) %finish %else %if rot=2 %start update mbb (-call symbol_xu+x, call symbol_yl+y, -call symbol_xl+x, call symbol_yu+y) %finish %else %if rot=1 %start update mbb(call symbol_yl+x,call symbol_xl+y, call symbol_yu+x,call symbol_xu+y) %finish %else %start update mbb(-call symbol_yu+x, -call symbol_xu+y, -call symbol_yl+x, -call symbol_xl+y) %finish %finish %end %external %routine cif comment %alias "ILAP_CIF_COMMENT" (%string (255) s) Transistor Polygon or Wire check dump comment (s) %end %external %routine cif statement %alias "ILAP_CIF_STATEMENT" (%string (255) s) Transistor Polygon or Wire check warn ("CIF statement contains a ';', (trumcated before it)") %if s->s.(";") dump statement (s) %end %external %routine user extension %alias "ILAP_USER_EXTENSION" (%integer no, %string (255) s) warn ("User extension contains a ';', (trumcated before it)") %if s->s.(";") Cif statement (Itos(no,0)." ".s) %end %external %integer %fn sx %alias "ILAP_SX" (%string (31) cell) %result = get mbb (cell, choose sx) %end %external %integer %fn sy %alias "ILAP_SY" (%string (31) cell) %result = get mbb (cell, choose sy) %end %external %integer %fn lx %alias "ILAP_LX" (%string (31) cell) %result = get mbb (cell, choose lx) %end %external %integer %fn ly %alias "ILAP_LY" (%string (31) cell) %result = get mbb (cell, choose ly) %end %external %integer %fn symbol exists %alias "ILAP_SYMBOL_EXISTS" (%string (31) name) %record (symdef) %name entry initialise ("") %if init=false entry == symbol table (lookup(name)) %if entry_number=0 %then %result=false %else %result=true %end %external %routine set lambda %alias "ILAP_SET_LAMBDA" (%integer L) warn ("Set Lambda called inside a symbol call") %if current symbol ## nil lambda = l dump lambda (l) cifscale = 2 - (L&1) %end %external %routine get lambda %alias "ILAP_GET_LAMBDA" (%integer %name L) l = lambda %end %external %routine first cell number %alias "ILAP_FIRST_CELL_NUMBER" (%integer I) warn ("First cell number must be positive") %and %return %if i<0 %if init=true %start %if i<= seqno %then warn ("Call to FIRST CELL NUMBER had number less than the current number") %c %else seqno = i-1 %finish initial symbol = i { Slightly unsafe, but CIFSYS will sort it out if faulty } %end %external %routine MERGE ON %alias "ILAP_MERGE_ON" control = control ! merge %end %external %routine MERGE OFF %alias "ILAP_MERGE_OFF" Warn ("Call to MERGE OFF while within a symbol") %if first box ## nil control = control & (\merge) %end %external %routine DRC ON %alias "ILAP_DRC_ON" control = control ! design rule check %end %external %routine DRC OFF %alias "ILAP_DRC_OFF" CONTROL = control & (\ design rule check) %end %external %routine SET ERROR STREAM %alias "ILAP_SET_ERROR_STREAM" (%integer I) warn ("Set error stream".after init) %if init=true ERROR stream = I %end %external %routine SET CIF STREAM %alias "ILAP_SET_CIF_STREAM" (%integer I) warn ("Set CIF stream".after init) %if init=true CIF stream = I %end %external %routine INITIALISE NMOS %alias "ILAP_INIT_NMOS" (%string (255) ofile) technology = 'N' %if lambda#nmos lambda %start Warn ("LAMBDA being re-set by a call to INITIALISE") %if lambda#default lambda lambda = nmos lambda %finish initialise (ofile) %end %external %routine INITIALISE CMOS %alias "ILAP_INIT_CMOS" (%string (255) ofile) technology = 'C' %if lambda#cmos lambda %start Warn ("LAMBDA being re-set by a call to INITIALISE") %if lambda#default lambda lambda = cmos lambda %finish initialise (ofile) %end %external %routine finish %alias "ILAP_FINISH" %record (symdef) %name entry %integer i Transistor Polygon or Wire check end symbol %and warn ("Endsymbol missing at FINISH") %if current symbol##nil ! Check for any un-satisfied symbol specs %if symbols speced = true %start %for i = 0, 1, max symbols %cycle entry == symbol table (i) warn ("Body of symbol """.entry_name.""" missing at FINISH") %if entry_number < 0 %repeat %finish current stream = out stream select output (cif stream) print symbol ('E'); newline close output select output (error stream) statements = statements+1 %if warnings>0 %start write (warnings, 0); print string (" Warning") print symbol ('s') %if warnings#1 print string (" issued."); newline %finish write(statements, 0); printstring(" CIF statements output"); newline init = false select output (current stream) %end %external %routine give statistics %alias "ILAP_GIVE_STATISTICS" %record (sym def) %name symbol %integer i print string (" Symbol Statistics"); newline newline print string (" ".version." run at ".time." on ".date); newline newline print string (" Type Name symbol LLX LLY URX URY TR Count"); newline %for i=0,1,max symbols %cycle symbol == symbol table(i) %if symbol_number#0 %start %if symbol_geometry=0 %and symbol_calls=0 %start %if symbol_xu>symbol_xl %start print string (" External") %finish %else %start print string (" Empty") %finish %finish %else %if symbol_geometry=0 %and symbol_calls#0 %start print string ("Composition") %finish %else %if symbol_geometry#0 %and symbol_calls=0 %start print string (" Leaf Cell") %finish %else %if symbol_geometry#0 %and symbol_calls#0 %start print string (" Mixed Cell") %finish spaces (31-8-length (symbol_name)) print string (symbol_name) write (|symbol_number|, 6) write (symbol_xl, 6) write (symbol_yl, 6) write (symbol_xu, 6) write (symbol_yu, 6) write (symbol_trans, 7) newline %finish %repeat %end %end %of %file