inductor_pcell_virtuoso/inductor_2

493 lines
8.9 KiB
Plaintext
Raw Normal View History

2018-12-06 12:35:30 +01:00
(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))
)
2018-12-06 16:55:09 +01:00
; multiplies a point p with a 2x2 matrix m
(defun matmult (m p)
result = list()
for(j 1 2
temp = 0
for(i 1 2
a = nthelem(j nthelem(i m))
b = nthelem(i p)
temp += a*b
)
result = append(result list(temp))
)
result
)
2018-12-06 12:35:30 +01:00
; 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
2018-12-06 16:55:09 +01:00
(center points left right up viaDef)
viaDef = (techFindViaDefByName (techGetTechFile id) "TM2_TM1")
2018-12-06 12:35:30 +01:00
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))
)
2018-12-06 16:55:09 +01:00
/*(dbCreateVia
id
viaDef
(addVect center (multVect dir -w))
"R0"
list(
list("cutWidth" (snap w-0.6))
list("cutHeight" (snap w-0.6))
)
)*/
; create underpass
/*(dbCreatePathSeg
id
underpassLayer
(addVect center (multVect dir -w))
(addVect (addVect center (multVect dir -w)) (multVect up -20))
w*2
"extend"
"extend"
)*/
/*(ind_createPin
2018-12-06 12:35:30 +01:00
id
"inner"
points
list("TopMetal2" "drawing")
2018-12-06 16:55:09 +01:00
)*/
2018-12-06 12:35:30 +01:00
)
)
; 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))
)
2018-12-06 16:55:09 +01:00
/*(ind_createPin
2018-12-06 12:35:30 +01:00
id
"outer"
points
list("TopMetal2" "drawing")
2018-12-06 16:55:09 +01:00
)*/
2018-12-06 12:35:30 +01:00
)
; 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
)
2018-12-06 16:55:09 +01:00
defun(ind_gndshield (r width pitch gap window)
(output "draw gnd shield with r=%L and w=%L\n", r, width)
r2 = r + width
m = 1/tan(mconst.PI/nseg)
segw = 2*r/m
pitch += width
(defun iszero (x)
abs(x) < 1/mfgGrid
)
(defun sign (x)
(if iszero(x)
then 0
else
(if (x > 0)
then 1
else -1
)
)
)
(defun cleanup (vect)
(sign car(vect)):(sign cadr(vect))
)
for(n 0 nseg-1
angle = mconst.PI*2/nseg * n
rotmat = list(
list(cos(angle) -sin(angle))
list(sin(angle) cos(angle))
)
w1 = width
w = w1
(when ((mod n 2) == 1)
w2 = w1*sqrt(2)
w= w2
)
w1 = (snap w1)
w2 = (snap w2)
w = (snap w)
; contact_ring = append(contact_ring list(list(r2*cos(angle-mconst.PI/nseg) r2*sin(angle-mconst.PI/nseg))))
for(y 0 floor(segw/(2*pitch))
yr = (snap y*pitch)
a = (snap min(yr*m + gap, r))
l = (r-a)
(when ((mod n 2) == 1)
l /= sqrt(2)
)
l = (snap l)
dir = (cleanup matmult(rotmat 0:-1))
(output "%P\n", dir)
start = matmult(rotmat yr:r)
start = (floor((car start)*50.0)/50.0):(floor((cadr start)*50.0)/50.0)
end = (addVect start (multVect dir l))
(dbCreatePathSeg
id
gndshield_layer
start
end
w
"truncate"
"truncate"
)
when(y != 0
start = -car(start):cadr(start)
end = -car(end):cadr(end)
dbCreatePathSeg(
id
gndshield_layer
start
end
w
"truncate"
"truncate"
)
)
) ; for
a = (floor r/m*mfgGrid/2)/(0.5*mfgGrid)
b = (snap r)
start = 0:0
end = 0:0
(print n)
(case n
(0
start = -a:b
end = a:b
)
(1
start = b:-a
end = a:-b
)
(2
start = b:-a
end = b:a
)
(3
start = a:b
end = b:a
)
(4
start = a:-b
end = -a:-b
)
(5
start = -a:-b
end = -b:-a
)
(6
start = -b:-a
end = -b:a
)
(7
start = -b:a
end = (addVect -a:b -window:-window)
)
)
; draw contact ring
(apply 'dbCreatePathSeg
id
gndshield_layer
start
end
w
if(mod(n 2)==0
then list(
"truncate"
"truncate"
list(0 0)
)
else list(
"custom"
(if n==7 then "truncate" else "custom")
list(
w1/2
(if n==7 then 0 else w1/2)
list(w1/2 w1/2 w2/2 w1/2 w1/2 w2/2)
)
)
)
)
)
)
)
2018-12-06 12:35:30 +01:00
; 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
; set multiple globals
inductorLayer = '("TopMetal2", "drawing")
2018-12-06 16:55:09 +01:00
underpassLayer = '("TopMetal1", "drawing")
2018-12-06 12:35:30 +01:00
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)
)
2018-12-06 16:55:09 +01:00
(defun drawGndShield (r pitch width window)
; setup gndshield
id = pcCellView
gndshield_layer = '("Metal1" "drawing")
nseg = 8
(ind_gndshield r pitch width width*2 (snap window))
)
(defun setup ()
; get manufacturing grid spacing and set global accordingly
mfgGrid=1/techGetMfgGridResolution(techGetTechFile(pcCellView))
(output "using manufacturing grid of %L\n", mfgGrid)
)
2018-12-06 12:35:30 +01:00
; 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 )
2018-12-06 16:55:09 +01:00
( gndshield "boolean" nil )
( gndpitch "float" 2.1 )
( gndwidth "float" 2.1 )
( gndoverlap "float" 3 )
( gndwindow "float" 2.1 )
2018-12-06 12:35:30 +01:00
)
(let
()
2018-12-06 16:55:09 +01:00
(setup)
(drawInductor turns radius width pitch)
(when gndshield
(drawGndShield radius+gndoverlap gndwidth gndpitch gndwindow)
)
2018-12-06 12:35:30 +01:00
)
)