Skip to content

Commit

Permalink
Merge pull request efabless#23 from mole99/pcells-improvements
Browse files Browse the repository at this point in the history
PCells Improvements
  • Loading branch information
mole99 authored Aug 13, 2024
2 parents b8a16c0 + 617395b commit 44068ad
Show file tree
Hide file tree
Showing 10 changed files with 82 additions and 43 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ This package contains the Skywater 130nm PDK for KLayout.
You have two options for using this package:

1. Clone this repository
2. Install the complete sky130 PDK from [open_pdks](https://github.com/RTimothyEdwards/open_pdks) either manually or with [volare](https://github.com/efabless/volare). The PDK also includes this package.
2. Install the complete sky130 PDK from [open_pdks](https://github.com/RTimothyEdwards/open_pdks) either manually or with [volare](https://github.com/efabless/volare). The PDK also includes this package.

When you start KLayout, you must reference this package. This can be done by setting the environment variable `KLAYOUT_HOME`. For example, inside this repository:
When you start KLayout, you must load this package. This can be done by setting the environment variable `KLAYOUT_PATH`. For example, inside this repository:

```console
KLAYOUT_HOME=./sky130_tech klayout -e
KLAYOUT_PATH=./sky130_tech klayout -e
```

### PCells
Expand Down
10 changes: 5 additions & 5 deletions sky130_tech/tech/sky130/pymacros/cells/cap.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,12 @@ def __init__(self):
self.Type_handle.default = self.Type_handle.choice_values()[0]


self.param("l", self.TypeDouble, "length", default=l_min, unit="um")
self.param("w", self.TypeDouble, "width", default=w_min, unit="um")
self.param("tap_con_col", self.TypeInt, "tap Contacts Columns", default=1)
self.param("l", self.TypeDouble, "Length", default=l_min, unit="um")
self.param("w", self.TypeDouble, "Width", default=w_min, unit="um")
self.param("tap_con_col", self.TypeInt, "Tap Contacts Columns", default=1)

self.param("gr", self.TypeBoolean, "Gaurd Ring", default=0)
self.param("grw", self.TypeDouble, "Gaurd Ring Width", default=grw_min, unit="um")
self.param("gr", self.TypeBoolean, "Guard Ring", default=0)
self.param("grw", self.TypeDouble, "Guard Ring Width", default=grw_min, unit="um")

self.param("nf", self.TypeDouble, "Number of Fingers", default=1)
#self.param("n", self.TypeDouble, "instance number", default=1)
Expand Down
12 changes: 6 additions & 6 deletions sky130_tech/tech/sky130/pymacros/cells/diode.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,13 +139,13 @@ def __init__(self):
self.Type_handle.add_choice("sky130_fd_pr__diode_pd2nw_11v0", "sky130_fd_pr__diode_pd2nw_11v0")
self.Type_handle.default = self.Type_handle.choice_values()[0]

self.param("w", self.TypeDouble, "width", default=d_min, unit="um")
self.param("l", self.TypeDouble, "length", default=d_min, unit="um")
self.param("cath_w", self.TypeDouble, "Cathode width", default=grw_min, unit="um")
self.param("grw", self.TypeDouble, "Gaurd Ring width", default=grw_min, unit="um")
self.param("w", self.TypeDouble, "Width", default=d_min, unit="um")
self.param("l", self.TypeDouble, "Length", default=d_min, unit="um")
self.param("cath_w", self.TypeDouble, "Cathode Width", default=grw_min, unit="um")
self.param("grw", self.TypeDouble, "Guard Ring Width", default=grw_min, unit="um")

self.param("area", self.TypeDouble,"Area", readonly=True, unit="um^2")
self.param("perim", self.TypeDouble,"Perimeter", readonly=True, unit="um")
self.param("area", self.TypeDouble, "Area", readonly=True, unit="um^2")
self.param("perim", self.TypeDouble, "Perimeter", readonly=True, unit="um")

#self.param("n", self.TypeInt, "n", default=1)

Expand Down
44 changes: 23 additions & 21 deletions sky130_tech/tech/sky130/pymacros/cells/draw_fet.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def draw_pfet(
) -> gf.Component:

'''
Retern pfet
Return pfet
Args:
cell : kdb.Cell cell to place layout into
Expand All @@ -57,7 +57,7 @@ def draw_pfet(
inter_sd_l : Float of source and drain diffusion length between fingers
nf : integer of number of fingers
M : integer of number of multipliers
grw : gaurd ring width when enabled
grw : guard ring width when enabled
type : string of the device type
bulk : String of bulk connection type (None, Bulk Tie, Guard Ring)
con_bet_fin : boolean of having contacts for diffusion between fingers
Expand Down Expand Up @@ -384,7 +384,7 @@ def draw_pfet(



elif bulk == "Gaurd Ring":
elif bulk == "guard ring":

psdm = c_inst.add_ref(gf.components.rectangle(size=(l_d+ 2*diff_psdm_enc, w+ 2*diff_psdm_enc),layer= psdm_layer))
psdm.move((-diff_psdm_enc,-diff_psdm_enc))
Expand All @@ -394,7 +394,6 @@ def draw_pfet(
rect_bulk_in = c_temp.add_ref(gf.components.rectangle(size=((c_inst.xmax - c_inst.xmin) + 2*diff_tap_spacing,
(c_inst.ymax - c_inst.ymin) + 2*poly_tap_spacing )
, layer= tap_layer))

rect_bulk_in.move((c_inst.xmin-diff_tap_spacing,c_inst.ymin - poly_tap_spacing))
rect_bulk_out = c_temp.add_ref(gf.components.rectangle(size=((rect_bulk_in.xmax - rect_bulk_in.xmin) + 2*grw,(rect_bulk_in.ymax - rect_bulk_in.ymin) + 2*grw )
, layer= tap_layer))
Expand All @@ -409,7 +408,7 @@ def draw_pfet(
nsdm_out.move((rect_bulk_out.xmin - tap_nsdm_enc, rect_bulk_out.ymin - tap_nsdm_enc))
nsdm = c.add_ref(gf.boolean(A= nsdm_out , B = nsdm_in , operation= "A-B", layer= nsdm_layer) )

# adding contacts
# generating contacts

if grw < licon_size[0] + 2*licon_t_enc :
g_con_range = (B.ymin , B.ymax )
Expand All @@ -422,20 +421,20 @@ def draw_pfet(
ring_con_up = c.add_ref(via_generator(x_range=(rect_bulk_in.xmin+0.17,rect_bulk_in.xmax-0.17),y_range=(rect_bulk_in.ymax,rect_bulk_out.ymax)
, via_enclosure=licon_dt_enc, via_layer=licon_layer,via_size=licon_size,via_spacing=licon_spacing))

ring_con_r = c.add_ref(via_generator(x_range=(rect_bulk_out.xmin,rect_bulk_in.xmin),y_range=g_con_range
ring_con_r = c.add_ref(via_generator(x_range=(rect_bulk_out.xmin,rect_bulk_in.xmin),y_range=(rect_bulk_in.ymin+0.17,rect_bulk_in.ymax-0.17)
, via_enclosure=licon_dt_enc, via_layer=licon_layer,via_size=licon_size,via_spacing=licon_spacing))

ring_con_l = c.add_ref(via_generator(x_range=(rect_bulk_in.xmax,rect_bulk_out.xmax),y_range=g_con_range
ring_con_l = c.add_ref(via_generator(x_range=(rect_bulk_in.xmax,rect_bulk_out.xmax),y_range=(rect_bulk_in.ymin+0.17,rect_bulk_in.ymax-0.17)
, via_enclosure=licon_dt_enc, via_layer=licon_layer,via_size=licon_size,via_spacing=licon_spacing))

tap_li_in = c_temp.add_ref(gf.components.rectangle(size=((l_d ) + 2*diff_tap_spacing,
tap_li_in = c_temp.add_ref(gf.components.rectangle(size=((c_inst.xmax - c_inst.xmin) + 2*diff_tap_spacing,
(c_inst.ymax - c_inst.ymin) + 2*poly_tap_spacing )
, layer= li_layer))
tap_li_in.move((-diff_tap_spacing,c_inst.ymin - poly_tap_spacing))
tap_li_in.move((c_inst.xmin - diff_tap_spacing, c_inst.ymin - poly_tap_spacing))
tap_li_out = c_temp.add_ref(gf.components.rectangle(size=((rect_bulk_in.xmax - rect_bulk_in.xmin) + 2*grw,(rect_bulk_in.ymax - rect_bulk_in.ymin) + 2*grw )
, layer= li_layer))
tap_li_out.move((rect_bulk_in.xmin - grw , rect_bulk_in.ymin -grw ))
li = c.add_ref(gf.boolean(A= rect_bulk_out , B = rect_bulk_in , operation= "A-B", layer= li_layer) )
li = c.add_ref(gf.boolean(A= tap_li_out , B = tap_li_in , operation= "A-B", layer= li_layer) )


# generating nwell
Expand All @@ -447,7 +446,7 @@ def draw_pfet(



if bulk != "Gaurd Ring":
if bulk != "guard ring":
c.add_ref(c_inst)

# nwell generation
Expand Down Expand Up @@ -496,7 +495,7 @@ def draw_nfet(
) : #-> gf.Component:

'''
Retern nfet
Return nfet
Args:
cell : kdb.Cell cell to place layout into
Expand All @@ -506,7 +505,7 @@ def draw_nfet(
inter_sd_l : Float of source and drain diffusion length between fingers
nf : integer of number of fingers
M : integer of number of multipliers
grw : gaurd ring width when enabled
grw : guard ring width when enabled
type : string of the device type
bulk : String of bulk connection type (None, Bulk Tie, Guard Ring)
con_bet_fin : boolean of having contacts for diffusion between fingers
Expand Down Expand Up @@ -840,7 +839,7 @@ def draw_nfet(



elif bulk == "Gaurd Ring":
elif bulk == "guard ring":

nsdm = c_inst.add_ref(gf.components.rectangle(size=(l_d+ 2*diff_nsdm_enc, w+ 2*diff_nsdm_enc),layer= nsdm_layer))
nsdm.move((-diff_nsdm_enc,-diff_nsdm_enc))
Expand All @@ -860,7 +859,7 @@ def draw_nfet(
, layer= psdm_layer))
psdm_in.move((rect_bulk_in.xmin + tap_psdm_enc, rect_bulk_in.ymin + tap_psdm_enc))
psdm_out = c_temp.add_ref(gf.components.rectangle(size=((rect_bulk_out.xmax - rect_bulk_out.xmin) + 2*tap_psdm_enc, (rect_bulk_out.ymax - rect_bulk_out.ymin) + 2*tap_psdm_enc )
, layer= nsdm_layer))
, layer= psdm_layer))
psdm_out.move((rect_bulk_out.xmin - tap_psdm_enc, rect_bulk_out.ymin - tap_psdm_enc))
psdm = c.add_ref(gf.boolean(A= psdm_out , B = psdm_in , operation= "A-B", layer= psdm_layer) )

Expand All @@ -881,14 +880,17 @@ def draw_nfet(
ring_con_l = c.add_ref(via_generator(x_range=(rect_bulk_in.xmax,rect_bulk_out.xmax),y_range=(rect_bulk_in.ymin+0.17,rect_bulk_in.ymax-0.17)
, via_enclosure=licon_dt_enc, via_layer=licon_layer,via_size=licon_size,via_spacing=licon_spacing))

tap_li_in = c_temp.add_ref(gf.components.rectangle(size=((l_d ) + 2*diff_tap_spacing,
(c_inst.ymax - c_inst.ymin) + 2*poly_tap_spacing )
, layer= li_layer))
tap_li_in.move((-diff_tap_spacing,c_inst.ymin - poly_tap_spacing))
tap_li_in = c_temp.add_ref(gf.components.rectangle(size=(
(c_inst.xmax - c_inst.xmin) + 2*diff_tap_spacing,
(c_inst.ymax - c_inst.ymin) + 2*poly_tap_spacing ),
layer= li_layer
)
)
tap_li_in.move((c_inst.xmin - diff_tap_spacing, c_inst.ymin - poly_tap_spacing))
tap_li_out = c_temp.add_ref(gf.components.rectangle(size=((rect_bulk_in.xmax - rect_bulk_in.xmin) + 2*grw,(rect_bulk_in.ymax - rect_bulk_in.ymin) + 2*grw )
, layer= li_layer))
tap_li_out.move((rect_bulk_in.xmin - grw , rect_bulk_in.ymin -grw ))
li = c.add_ref(gf.boolean(A= rect_bulk_out , B = rect_bulk_in , operation= "A-B", layer= li_layer) )
li = c.add_ref(gf.boolean(A= tap_li_out , B = tap_li_in , operation= "A-B", layer= li_layer) )



Expand All @@ -904,7 +906,7 @@ def draw_nfet(



if bulk != "Gaurd Ring":
if bulk != "guard ring":
c.add_ref(c_inst)


Expand Down
28 changes: 27 additions & 1 deletion sky130_tech/tech/sky130/pymacros/cells/draw_guard_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,8 @@ def draw_gr (
in_l : float = 1,
in_w : float = 1,
grw : float = 0.17,
con_lev = "li"
con_lev = "li",
implant_type = "None"
) :

'''
Expand All @@ -44,16 +45,37 @@ def draw_gr (
con_spacing = (0.19, 0.19)
con_enc = (0.12, 0.12)

tap_nsdm_enc : float = 0.125
tap_psdm_enc : float = 0.125

c = open_component("sky_ring_gen")
c_temp = gf.Component("temp_store")

# Choose the implant
if implant_type == 'nsdm':
implant_layer = nsdm_layer
if implant_type == 'psdm':
implant_layer = psdm_layer

# Add the implant layer
if implant_type != 'None':
implant_in = c_temp.add_ref(gf.components.rectangle(size=(in_w - 2*tap_nsdm_enc, in_l - 2*tap_nsdm_enc), layer=implant_layer))
implant_in.move((tap_nsdm_enc, tap_nsdm_enc))
implant_out = c_temp.add_ref(gf.components.rectangle(size=(in_w + 2*grw + 2*tap_nsdm_enc, in_l + 2*grw + 2*tap_nsdm_enc), layer=implant_layer))
implant_out.move((-grw - tap_nsdm_enc, -grw - tap_nsdm_enc))
implant = c.add_ref(gf.boolean(A=implant_out, B=implant_in, operation="A-B", layer=implant_layer))

inner = c_temp.add_ref(gf.components.rectangle(size=(in_w, in_l), layer=tap_layer))
outer = c_temp.add_ref(gf.components.rectangle(size=(inner.xmax - inner.xmin + 2*grw , inner.ymax - inner.ymin + 2*grw), layer=tap_layer))
outer.move((-grw, -grw))

gr = c.add_ref(gf.boolean(A=outer, B=inner , operation="A-B", layer=tap_layer))

if con_lev == "li" or con_lev == "metal1":
inner = c_temp.add_ref(gf.components.rectangle(size=(in_w, in_l), layer=li_layer))
outer = c_temp.add_ref(gf.components.rectangle(size=(inner.xmax - inner.xmin + 2*grw , inner.ymax - inner.ymin + 2*grw), layer=li_layer))
outer.move((-grw, -grw))

li = c.add_ref(gf.boolean(A=outer, B=inner, operation="A-B", layer=li_layer))

if grw < con_size[0] + 2*con_enc[0]:
Expand All @@ -73,6 +95,10 @@ def draw_gr (


if con_lev == "metal1" :
inner = c_temp.add_ref(gf.components.rectangle(size=(in_w, in_l), layer=m1_layer))
outer = c_temp.add_ref(gf.components.rectangle(size=(inner.xmax - inner.xmin + 2*grw , inner.ymax - inner.ymin + 2*grw), layer=m1_layer))
outer.move((-grw, -grw))

m1 = c.add_ref(gf.boolean(A=outer, B=inner, operation="A-B", layer=m1_layer))

mcon_l = c.add_ref(via_generator(x_range=(outer.xmin, inner.xmin), y_range=(inner.ymin + 0.17 , inner.ymax - 0.17), via_enclosure=con_enc, via_layer=mcon_layer
Expand Down
6 changes: 3 additions & 3 deletions sky130_tech/tech/sky130/pymacros/cells/fet.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ def __init__(self):
self.Type_handle = self.param("bulk", self.TypeString, "Bulk Type")
self.Type_handle.add_choice("None", "None")
self.Type_handle.add_choice("bulk tie", "bulk tie")
self.Type_handle.add_choice("Gaurd Ring", "Gaurd Ring")
self.Type_handle.add_choice("guard ring", "guard ring")
self.Type_handle.default = self.Type_handle.choice_values()[0]

self.Type_handle = self.param("gate_con_pos", self.TypeString, "Gate Contact Position")
Expand All @@ -68,7 +68,7 @@ def __init__(self):



self.param("l", self.TypeDouble, "length", default=fet_01v8_l, unit="um")
self.param("l", self.TypeDouble, "Length", default=fet_01v8_l, unit="um")
self.param("w", self.TypeDouble, "Width", default=fet_w, unit="um")
self.param("sd_con_col", self.TypeInt, "Diffusion Contacts Columns", default=1)
self.param("inter_sd_l", self.TypeDouble, "Between Fingers Diffusion Length", default=fet_inter_ld, unit="um")
Expand Down Expand Up @@ -174,7 +174,7 @@ def __init__(self):
self.Type_handle = self.param("bulk", self.TypeString, "Bulk Type")
self.Type_handle.add_choice("None", "None")
self.Type_handle.add_choice("bulk tie", "bulk tie")
self.Type_handle.add_choice("Gaurd Ring", "Gaurd Ring")
self.Type_handle.add_choice("guard ring", "guard ring")
self.Type_handle.default = self.Type_handle.choice_values()[0]

self.Type_handle = self.param("gate_con_pos", self.TypeString, "Gate Contact Position")
Expand Down
8 changes: 7 additions & 1 deletion sky130_tech/tech/sky130/pymacros/cells/gr.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ def __init__(self):
self.Type_handle.add_choice("li", "li")
self.Type_handle.add_choice("metal1", "metal1")
self.Type_handle.default = self.Type_handle.choice_values()[0]

self.Type_handle = self.param("implant_type", self.TypeString, "Implant Type")
self.Type_handle.add_choice("None", "None")
self.Type_handle.add_choice("psdm", "psdm")
self.Type_handle.add_choice("nsdm", "nsdm")
self.Type_handle.default = self.Type_handle.choice_values()[0]

def display_text_impl(self):
# Provide a descriptive text for the cell
Expand Down Expand Up @@ -94,5 +100,5 @@ def transformation_from_shape_impl(self):
return pya.Trans(self.shape.bbox().center())

def produce_impl(self):
draw_gr(cell=self.cell, in_l=self.in_l, in_w=self.in_w , grw= self.grw , con_lev=self.con_lev)
draw_gr(cell=self.cell, in_l=self.in_l, in_w=self.in_w , grw= self.grw , con_lev=self.con_lev, implant_type=self.implant_type)

4 changes: 4 additions & 0 deletions sky130_tech/tech/sky130/pymacros/cells/pdk.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ def take_component(c : gf.Component, target_cell : kdb.Cell):

# TODO: have an API for this
source_cell = c._kdb_cell

# Since dbu for sky130 is 0.001nm, but the manufacturing grid is 0.005nm
# snap to 0.005nm grid to prevent offgrid DRC errors
source_cell.layout().scale_and_snap(source_cell, 5, mult=1, div=1)

cm = kdb.CellMapping()
cm.for_single_cell(target_cell, source_cell)
Expand Down
6 changes: 3 additions & 3 deletions sky130_tech/tech/sky130/pymacros/cells/res_klayout_panel.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,10 @@ def __init__(self, l_min, w_min):

self.Type_handle = self.param("type", self.TypeString, "Device Type")

self.param("len", self.TypeDouble, "length", default=l_min, unit="um")
self.param("w", self.TypeDouble, "width", default=w_min, unit="um")
self.param("len", self.TypeDouble, "Length", default=l_min, unit="um")
self.param("w", self.TypeDouble, "Width", default=w_min, unit="um")

self.param("gr", self.TypeBoolean, "Gaurd Ring", default=1)
self.param("gr", self.TypeBoolean, "Guard Ring", default=1)
self.param(
"area", self.TypeDouble, "Area", readonly=True, unit="um^2"
)
Expand Down
1 change: 1 addition & 0 deletions sky130_tech/tech/sky130/sky130.lyt
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
<original-base-path>$PDK_ROOT/$PDK/libs.tech/klayout</original-base-path>
<layer-properties_file>sky130.lyp</layer-properties_file>
<add-other-layers>true</add-other-layers>
<default-grids>0.01,0.005!</default-grids>
<reader-options>
<gds2>
<box-mode>1</box-mode>
Expand Down

0 comments on commit 44068ad

Please sign in to comment.