From 65adac2bd5bf606974c7950c65d0ca68a51132e5 Mon Sep 17 00:00:00 2001 From: MMIC Praktikum Date: Thu, 6 Dec 2018 12:35:30 +0100 Subject: [PATCH] first working pcell --- inductor_2 | 266 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 266 insertions(+) create mode 100644 inductor_2 diff --git a/inductor_2 b/inductor_2 new file mode 100644 index 0000000..e32bbf6 --- /dev/null +++ b/inductor_2 @@ -0,0 +1,266 @@ +(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) + ) +) + +