(defMathConstants 'mconst) mfgGrid = 100.0 debug = nil ; SNAPS STUFF TO GRID ; uses global mfgGrid to do so, which gets redefined in generator ; to the tech mfg grid using the techFile (defun snap (p) floor(p*mfgGrid)/mfgGrid ) ; DEBUG output function, uncomment to get all output (procedure output( @rest args) (when debug (apply 'printf args)) ;() ) ; VECTOR HELPER FUNCTIONS ; add a vector vect to a point p (defun addVect (p vect) (car(p)+car(vect)):(cadr(p)+cadr(vect)) ) ; multiplies a vector vect with a scalar (defun multVect (vect scalar) (car(vect)*scalar):(cadr(vect)*scalar) ) ; multiplies a vector vect with -1 (inverse) (defun invVect (vect) (multVect vect -1) ) ; subtracts two vectors from one another ; (does vect2 - vect1) (defun subVect (vect1 vect2) (car(vect2)-car(vect1)):(cadr(vect2)-cadr(vect1)) ) ; returns length of a vector (defun lenVect (vect) sqrt((1.0*car(vect)**2)+(1.0*cadr(vect)**2)) ) ; rotates a vector vect by 90 CCW (defun rotVect (vect) cadr(vect):-car(vect) ) ; normalizes a vector vect by its length (defun normalizeVect (vect) (multVect vect 1.0/(lenVect vect)) ) ; DRAWING HELPER FUNCTIONS ; creates a pin using database functions ; and a corresponding net with name name ; does so on the layer layer (defun ind_createPin (id name points layer) (leCreatePin id layer "polygon" points name "inputOutput" '("none") ) /* net = dbCreateNet(id name) fig = dbCreatePolygon(id layer points) trm = dbCreateTerm(net name "inputOutput") pin = dbCreatePin(net fig name trm) pin~>accessDir = '( "none" ) */ lab = dbCreateLabel(id '("TEXT") cadr(points) name "centerLeft" "R0" "roman" 3) ;output("created pin %s\n", name) ) ; Creates the end connection for the inductor and ; places a pin there ; TODO: create underpass here (defun ind_createEnd (id start w dir) (output "[createEnd] start=%P dir=%P\n", start, dir) (let (center points left right up) center = (addVect start (multVect dir (snap -w/2))) left = (addVect center (multVect dir (snap -w/2))) right = (addVect center (multVect dir (snap w/2))) up = (multVect (rotVect dir) (snap w/2)) points = list( (addVect left up) (addVect right up) (addVect right (invVect up)) (addVect left (invVect up)) ) (ind_createPin id "inner" points list("TopMetal2" "drawing") ) ) ) ; Creates the start of the inductor ; and places a pin there (defun ind_createStart (id start width dir) center = start; (addVect start multVect((invVect dir) width/2)) points = list( (addVect center (-width):width) (addVect center width:width) (addVect center width:(-width)) (addVect center (-width):(-width)) ) (ind_createPin id "outer" points list("TopMetal2" "drawing") ) ) ; creates one segment of the inductor and calls itself recursively to complete ; one inductor (defun ind_drawSegment (id n seg start r) dx = snap(r*talpha) (case mod(seg, 8) (0 end = dx:r ) (1 end = r:dx ) (2 end = r:-dx ) (3 end = dx:-r ) (4 end = -dx:-r ) (5 end = -r:-dx ) (6 end = -r:dx ) (7 r -= pitch end = (addVect start (r-dx):(r-dx)) ) ) dir = (subVect start end) ndir = (normalizeVect dir) isstart = (seg == 0) isend = (n < 1) ; DEBUG output("seg: %d, n: %L (start: %L, end: %L)\n", mod(seg, nseg), n, isstart, isend) when(isend l = (lenVect dir) if((mod(seg,2)==0) then end = addVect(end multVect(ndir (snap l*(n-1)))) else end = addVect(start multVect(ndir (snap l*(n-1)))) ) ) if((mod(seg, 2) == 0) then (dbCreatePathSeg id inductorLayer start end w if(!isstart then "custom" else "extend") if(!isend then "custom" else "truncate") list(if(isstart then 0 else whalv) if(isend then 0 else whalv) list(w2halv w2halv whalv w2halv w2halv whalv)) ) else (dbCreatePathSeg id inductorLayer start end w2 "truncate" "truncate" ) ) when(isstart ind_createStart(id start whalv ndir)) when((n<=1) ind_createEnd(id end whalv ndir)) n -= 1 (output "n=%L\n", n) (when (n > 0) (ind_drawSegment id n seg+1 end r) ) ; when ) ; uses ind_drawSegment to create a complete inductor with ; the given specification defun(drawInductor (n r width pitch) ; the PCell cell view id id = pcCellView (when (not id) (error "could not find cell view") ) ; when ; get manufacturing grid spacing and set global accordingly mfgGrid=1/techGetMfgGridResolution(techGetTechFile(id)) (output "using manufacturing grid of %L\n", mfgGrid) ; set multiple globals inductorLayer = '("TopMetal2", "drawing") output("generating inductor with r=%L, turns=%L, pitch=%L and width=%L\n" r n pitch width) whalv = snap(width/2) w = whalv*2 ; diagonal segment width w2halv = snap(width*sqrt(2)/2) w2 = 2*w2halv pitch = snap(pitch + w) ; pitch from segment sides r = snap(r - whalv) ; middle radius nseg = 8 ; octagonal inductor ; calculation globals ahalv = mconst.PI/nseg ; angle between segments talpha = tan(ahalv) hl = snap((r-w/2)*talpha) ; start point ; draw inductor (ind_drawSegment id n*nseg 0 -hl:r r) ) ; defines the inductor PCell (pcDefinePCell list( (ddGetObj "mmic14_inductors") "inductorPcell" "layout") list( ( turns "float" 1.0 ) ( radius "float" 100.0 ) ( width "float" 2.1 ); techGetSpacingRule(techGetTechFile(pcCellView) "minWidth" "TopMetal2" )) ( pitch "float" 2.1 ) ) (let () drawInductor(turns radius width pitch) ) )