Implemented the photodiode device in the parameterized device generator for magic.
diff --git a/sky130/magic/sky130.tcl b/sky130/magic/sky130.tcl index bcf4df5..59bbc67 100644 --- a/sky130/magic/sky130.tcl +++ b/sky130/magic/sky130.tcl
@@ -101,6 +101,8 @@ "magic::gencell sky130::sky130_fd_pr__diode_pw2nd_05v5" pdk1 magic::add_toolkit_command $layoutframe "p-diode" \ "magic::gencell sky130::sky130_fd_pr__diode_pd2nw_05v5" pdk1 + magic::add_toolkit_command $layoutframe "photodiode" \ + "magic::gencell sky130::sky130_fd_pr__photodiode" pdk1 magic::add_toolkit_separator $layoutframe pdk1 magic::add_toolkit_command $layoutframe "MOS varactor" \ @@ -868,6 +870,10 @@ full_metal 1 vias 1 viagb 0 viagt 0 viagl 0 viagr 0} } +proc sky130::sky130_fd_pr__photodiode_defaults {} { + return {nx 1 ny 1 deltax 0 deltay 0 xstep 8.0 ystep 8.0} +} + proc sky130::sky130_fd_pr__diode_pd2nw_05v5_defaults {} { return {w 0.45 l 0.45 area 0.2025 peri 1.8 \ nx 1 ny 1 dummy 0 lmin 0.45 wmin 0.45 \ @@ -927,6 +933,10 @@ return [sky130::diode_convert $parameters] } +proc sky130::sky130_fd_pr__photodiode_convert {parameters} { + return [sky130::fixed_convert $parameters] +} + proc sky130::sky130_fd_pr__diode_pd2nw_05v5_convert {parameters} { return [sky130::diode_convert $parameters] } @@ -961,6 +971,10 @@ sky130::diode_dialog sky130_fd_pr__diode_pw2nd_11v0 $parameters } +proc sky130::sky130_fd_pr__photodiode_dialog {parameters} { + sky130::fixed_dialog $parameters +} + proc sky130::sky130_fd_pr__diode_pd2nw_05v5_dialog {parameters} { sky130::diode_dialog sky130_fd_pr__diode_pd2nw_05v5 $parameters } @@ -995,6 +1009,10 @@ sky130::diode_check $parameters } +proc sky130::sky130_fd_pr__photodiode_check {parameters} { + sky130::fixed_check $parameters +} + proc sky130::sky130_fd_pr__diode_pd2nw_05v5_check {parameters} { sky130::diode_check $parameters } @@ -1209,6 +1227,153 @@ } #---------------------------------------------------------------- +# Photodiode: Draw a single device +#---------------------------------------------------------------- + +proc sky130::photodiode_device {parameters} { + + # Set a local variable for each parameter (e.g., $l, $w, etc.) + foreach key [dict keys $parameters] { + set $key [dict get $parameters $key] + } + + # Draw the device + pushbox + box size 0 0 + + # Device has ntap fixed width of 0.41 x 0.41 + # Surrounded by nwell 0.84 x 0.84 + # Surrounded by deep nwell 3.0 x 3.0 + + pushbox + box grow c 0.205um + paint nsd + popbox + pushbox + box grow c 0.42um + paint nwell + popbox + pushbox + box grow c 1.5um + paint photo + + set cext [sky130::getbox] + + popbox + + # Only enough space for one contact + set w ${contact_size} + set l ${contact_size} + + set cext [sky130::unionbox $cext [sky130::draw_contact ${w} ${l} \ + 0 ${metal_surround} ${contact_size} \ + nsd nsc li horz]] + + popbox + return $cext +} + +#---------------------------------------------------------------- + +proc sky130::photodiode_draw {parameters} { + + # Set a local variable for each parameter (e.g., $l, $w, etc.) + foreach key [dict keys $parameters] { + set $key [dict get $parameters $key] + } + + pushbox + box values 0 0 0 0 + + # Determine the base device dimensions by drawing one device + # while all layers are locked (nothing drawn). This allows the + # base drawing routine to do complicated geometry without having + # to duplicate it here with calculations. + + tech lock * + set bbox [sky130::photodiode_device $parameters] + # puts stdout "Diagnostic: Device bounding box e $bbox (um)" + tech unlock * + + set fw [- [lindex $bbox 2] [lindex $bbox 0]] + set fh [- [lindex $bbox 3] [lindex $bbox 1]] + set lw [+ [lindex $bbox 2] [lindex $bbox 0]] + set lh [+ [lindex $bbox 3] [lindex $bbox 1]] + + # Determine tile width and height + + set dx [+ $fw $end_spacing] + set dy [+ $fh $end_spacing] + + # Determine core width and height + set corex [+ [* [- $nx 1] $dx] $fw] + set corey [+ [* [- $ny 1] $dy] $fh] + set corellx [/ [+ [- $corex $fw] $lw] 2.0] + set corelly [/ [+ [- $corey $fh] $lh] 2.0] + + # Calculate guard ring size (measured to contact center) + # Spacing between photodiode (deep nwell) and deep nwell (other) is 5.3um + set gx [+ $corex 15.965] + set gy [+ $corey 15.965] + + pushbox + + # The deep nwell is offset 0.315 from the nwell ring center to get the + # right overlap. The deep nwell ring has a minimum width of 3um. + set hgx [/ $gx 2.0] + set hgy [/ $gy 2.0] + set dwx [+ $hgx 0.315] + set dwy [+ $hgy 0.315] + box grow e ${dwx}um + box grow w ${dwx}um + box grow n ${dwy}um + box grow s ${dwy}um + paint dnwell + box grow e -3.0um + box grow w -3.0um + box grow n -3.0um + box grow s -3.0um + erase dnwell + + popbox + + # Draw the guard ring first. 0.63 is the amount nwell surrounds contact; + # 0.63 * 2 + 0.17 = total nwell width 1.43um, needed to cover dnwell edge. + set newdict [dict create \ + sub_type space \ + guard_sub_type nwell \ + guard_sub_surround 0.63 \ + plus_diff_type nsd \ + plus_contact_type nsc \ + ] + set guarddict [dict merge $parameters $newdict] + sky130::guard_ring $gx $gy $guarddict + + # Draw outside P-ring and generated the 2nd ring + set gx [+ $gx [* 2.0 [+ 0.56 $diff_spacing $diff_surround]] $contact_size] + set gy [+ $gy [* 2.0 [+ 0.56 $diff_spacing $diff_surround]] $contact_size] + sky130::guard_ring $gx $gy $parameters + + pushbox + box move w ${corellx}um + box move s ${corelly}um + + for {set xp 0} {$xp < $nx} {incr xp} { + pushbox + for {set yp 0} {$yp < $ny} {incr yp} { + sky130::photodiode_device $parameters + box move n ${dy}um + } + popbox + box move e ${dx}um + } + popbox + popbox + + tech revert +} + +#---------------------------------------------------------------- proc sky130::sky130_fd_pr__diode_pw2nd_05v5_draw {parameters} { @@ -1422,6 +1587,31 @@ } #---------------------------------------------------------------- +# The photodiode has its own drawing routine, so +#---------------------------------------------------------------- + +proc sky130::sky130_fd_pr__photodiode_draw {parameters} { + # Set a local variable for each rule in ruleset + foreach key [dict keys $sky130::ruleset] { + set $key [dict get $sky130::ruleset $key] + } + + set newdict [dict create \ + guard 1 \ + sub_type space \ + end_spacing 5.0 \ + end_surround 1.0 \ + sub_spacing 5.3 \ + guard_sub_type pwell \ + guard_sub_surround 0.18 \ + plus_diff_type psd \ + plus_contact_type psc \ + ] + set drawdict [dict merge $sky130::ruleset $newdict $parameters] + return [sky130::photodiode_draw $drawdict] +} + +#---------------------------------------------------------------- # Drawn capacitor routines # NOTE: Work in progress. These values need to be corrected. #----------------------------------------------------------------
diff --git a/sky130/magic/sky130.tech b/sky130/magic/sky130.tech index b5546bf..7c5e949 100644 --- a/sky130/magic/sky130.tech +++ b/sky130/magic/sky130.tech
@@ -82,6 +82,7 @@ # sky130_fd_pr__res_iso_pw rpw pwell resistor (in deep nwell) # sky130_fd_pr__esd_nfet_g5v0d10v5 mvnfetesd ESD thickox nFET # sky130_fd_pr__esd_pfet_g5v0d10v5 mvpfetesd ESD thickox pFET +# sky130_fd_pr__photodiode photo Photodiode # # (*) Note that ppres may extract into some generic type called # "sky130_fd_pr__res_xhigh_po", but only specific sizes of xhrpoly are @@ -142,6 +143,7 @@ # Deep nwell dwell dnwell,dnw dwell isosubstrate,isosub + dwell photodiode,photo # Wells well nwell,nw @@ -474,6 +476,7 @@ nwell nwell pwell pwell rpwell pwell ptransistor_stripes + photo nwell nwell_field_implant ndiff ndiffusion fomfill ndiffusion pdiff pdiffusion @@ -693,7 +696,7 @@ #----------------------------------------------------- connect - *nwell,*nsd,*mvnsd,dnwell,pnp *nwell,*nsd,*mvnsd,dnwell,pnp + *nwell,*nsd,*mvnsd,dnwell,pnp,photo *nwell,*nsd,*mvnsd,dnwell,pnp,photo pwell,*psd,*mvpsd,npn pwell,*psd,*mvpsd,npn *li,coreli,lifill *li,coreli,lifill *m1,m1fill,obsmcon *m1,m1fill,obsmcon @@ -751,7 +754,7 @@ # DNWELL #---------------------------------------------------------------- - layer DNWELL dnwell,npn + layer DNWELL dnwell,npn,photo calma 64 18 layer PWRES rpw @@ -974,6 +977,9 @@ mask-hints PNPID calma 82 44 + layer PHOTO photo + calma 81 81 + #---------------------------------------------------------------- # RPM #---------------------------------------------------------------- @@ -2387,6 +2393,9 @@ and-not NWELL,nwelcheck and NPNID + layer photo DNWELL + and PHOTO + layer rpw PWRES and DNWELL labels PWRES @@ -3927,6 +3936,8 @@ calma CAPID 82 64 # Core area ID mark calma COREID 81 2 + # Photodiode ID mark + calma PHOTO 81 81 # Standard cell ID mark calma STDCELL 81 4 # Padframe cell ID mark @@ -4104,6 +4115,11 @@ "P+ diff cannot straddle Deep N-well (dnwell.5)" variants (fast),(full) + width photo 3000 "Photodiode width < %d (photo.2)" + spacing photo photo 5000 touching_ok "Photodiode spacing < %d (photo.3)" + spacing photo dnwell 5300 touching_illegal \ + "Photodiode spacing to deep nwell < %d (photo.4)" + #----------------------------- # NWELL #----------------------------- @@ -5394,6 +5410,8 @@ device resistor sky130_fd_pr__res_generic_m4 rm4 *m4 device resistor sky130_fd_pr__res_generic_m5 rm5 *m5 #endif (METAL5) + device ndiode sky130_fd_pr__model__parasitic__diode_ps2dn \ + photo pwell,space/w error a=area device rsubcircuit sky130_fd_pr__res_high_po_0p35 xhrpoly \ xpc pwell,space/w error +res0p35 l=l