hello everyone, I have a fundamental question abou...
# sky130
c
hello everyone, I have a fundamental question about layout, how is it possible to convert my schematic (or my netlist) in layout ? I download the skywater PDK here : https://github.com/google/skywater-pdk, I found basic cell ( nand, or ...) but not the nfet_01v8_lvt , pfet_01v8_lvt ... I saw I need to sign a NDA to have it but it's weird for an oppen PDK. Can you tell me if it's true for not waste my time ? If some one know how to generate the layout like this video on Klayout

https://www.youtube.com/watch?v=DcrpmWq88cc&t=180sβ–Ύ

, I thank you very much in advence to help me how to do that. Thanks agains. πŸ˜‡
πŸ‘ 1
s
@Charly Meyer could you send the screenshot where it's written about the NDA???
a
The skywater 130nm is mostly open and there is no NDAs afaik. You need to install Magic VLSI for layout and Parasitic/lvs/drc Then install open pdk, which installs all of the sky130 pdk files
KLayout is also a good layout tool, also supported by open_pdks XSchem is for schematic
OpenLane is for PnR and it supports sky130 open pdks
c
I installed Magic and Klayout, since 2 weed I'm trying to have the layout of the trasitors nfet_01V8 and pfet_01V8, but without sucess
I saw on a "layout editor" forum to have a custom transistor nfet_01V8 a NDA is needed. But I don't know
s
@Charly Meyer the layout editor may not be OpenSource
c
someone has already used transistors nfet_01V8 or pfet_01V8 into a layout ?
s
oh ok
l
@Charly Meyer

https://www.youtube.com/watch?v=RPppaGdjbj0β–Ύ

It is hard to learn how to make customs layouts with the OpenPDK, but it is not impossible. We have lots of open source analog circuits available already.
a
1. Magic VLSI has PCell generator for the transistors you mentioned 2. Documentation has information regarding the layers and shapes you need to draw to get the transistor you want
c
Thank you for your responces. I have already design several chips in 180nm with cadence
Arman Avetisyan did you designed some analog chips ? my goal is to creat a real functional chip, i don't want create layout just for fun.
I'm desperate, I looking for since 2/3 weeks in full time how to use these transistors for the layout. Now I suppose they are not available in open access
If I need to sign a NDA, I will sign a NDA
m
@yrrapt @Tim Edwards @Amro Tork Any comments?
@Charly Meyer Did you join #analog-design channel?
a
Both Skywaters 130nm and GF180MCU are open source and no NDA need to be signed. All tools used in the design are open source as well. No need to sign NDA.
a
Yes, I did design analog chip I used XSchem to design a GPIO cell. Then used KLayout+Magic to make the layout, drc, lvs, parasitic Then used OpenLane to make harden the digital section Finally, integrated all together using KLayout and Spice netlist My chip taped out @ MPW5
@Charly Meyer I am not sure what you want exactly? You can just use Magic VLSI to create a layout of this transistors. Good starting point is taking look at caravel (or caravel analog), which is template project that you can modify to get the layout that you want. Then you send it to efabless website for precheck and tapeout.
t
@Charly Meyer: For transistor information, you can look at the documentation here: https://skywater-pdk.readthedocs.io/en/main/rules/device-details.html. Unfortunately, the summary of some of the devices give you partial information and then point you to a SkyWater document number that is not something that is open-sourced. You can, of course, potentially sign an NDA with SkyWater and get access to whatever additional proprietary documentation you need. Often, the information is already there in the SPICE models themselves, if you know where to look. Getting a schematic devices transformed into layout subcells can be as simple as using the menu selection
File->Import from SPICE
in magic when using the sky130 open PDK tech file. Magic does not have the capacity to automatically place and route an analog design for you, but it will reliably generate parameterized device layouts to match what's in the schematic-captured netlist. I don't know what capability klayout has to generate device layouts from a netlist, but you can always generate them in magic, write that out to a GDS file, and import that file into klayout, if you prefer doing layout work in klayout.
πŸ‘πŸ» 1
πŸ‘ 1
c
thank you for your responses. My goal is to have the layout of N and P fet with klayout and I can choose their L and W.
πŸ‘ 1
I think Klayout can not generate layout from the netlist, but this is not the problem
may be it can help you. I have these errors when I lunch klayout
a
the error is caused by the bug in the klayout lvs deck
I dont know if it is fixed or still needs to be fixed
c
I found this here : https://antmicro-skywater-pdk-docs.readthedocs.io/en/latest/contents/file_types.html do you think that is needed to create transistor layout with custum L and W
the error when Iunch Klayout is there is no "cells" with contain sky130
s
@Charly Meyer export the PDK path and then relaunch klayout
c
which pdk part ? and how I do that ? I'm sorry But I'm blocked and I don't know how instal this library contain transistors
I found the fonction to generate nmos but the main question is intergre it on Klayout ?: from math import floor import gdsfactory as gf from gdsfactory.typings import Float2, LayerSpec @gf.cell def nmos( diffusion_layer: LayerSpec = (65, 20), poly_layer: LayerSpec = (66, 20), gate_width: float = 0.42, gate_length: float = 0.15, sd_width: float = 0.3, end_cap: float = 0.13, contact_size: Float2 = (0.17, 0.17), contact_spacing: Float2 = (0.17, 0.17), contact_layer: LayerSpec = (66, 44), contact_enclosure: Float2 = (0.06, 0.06), diff_spacing: float = 0.27, diff_enclosure: Float2 = (0.18, 0.18), diffp_layer: LayerSpec = (65, 44), pwell_layer: LayerSpec = (64, 13), dnwell_enclosure: Float2 = (0.4, 0.4), dnwell_layer: LayerSpec = (64, 18), nf: int = 1, sdm_enclosure: Float2 = (0.125, 0.125), nsdm_layer: LayerSpec = (93, 44), sdm_spacing: float = 0.13, psdm_layer: LayerSpec = (94, 20), li_width: float = 0.17, li_spacing: float = 0.17, li_layer: LayerSpec = (67, 20), li_enclosure: float = 0.08, mcon_layer: LayerSpec = (67, 44), mcon_enclosure: Float2 = (0.03, 0.06), m1_layer: LayerSpec = (68, 20), npc_layer: LayerSpec = (95, 20), npc_spacing: float = 0.09, ) -> gf.Component: """Return NMOS. Args: diffusion_layer: spec. poly_layer: spec. gate_width: for poly. gate_length: for poly. sd_width: source drain length. end_cap: end cap length. contact_size: contact dimension (length and width). contact_layer: for contacts. contact_enclosure: for contacts within diffusion or poly. diff_spacing: for two adjacent diffusions. diff_enclosure: for diffusion within well. diffp_layer: for bulk tie. dnwell layer: for deep nwell. nf: for finger option. .. code:: _______ | poly | _________| |_________ _ | sd_width| | sd_width| | |<------->| |<------->| |gate_width |_________| |_________| | | Lg | |<---->| |______| .. plot:: include source import sky130 c = sky130.pcells.nmos(gate_length=0.15, gate_width=0.42) c.plot() """ c = gf.Component() # generating poly and n+ diffusion w_p = end_cap + gate_width + end_cap # poly total width rect_p = gf.components.rectangle(size=(gate_length, w_p), layer=poly_layer) # adding fingers # poly = c.add_ref(rect_p) poly = c.add_array(rect_p, rows=1, columns=nf, spacing=[sd_width + gate_length, 0]) l_d = (nf + 1) * (sd_width + gate_length) - gate_length # n diffution total length rect_d = gf.components.rectangle(size=(l_d, gate_width), layer=diffusion_layer) diff_n = c.add_ref(rect_d) poly.movex(sd_width) poly.movey(-end_cap) # generating n+ implant rect_nm = gf.components.rectangle( size=(l_d + 2 * sdm_enclosure[0], gate_width + 2 * sdm_enclosure[1]), layer=nsdm_layer, ) nsdm = c.add_ref(rect_nm) nsdm.movex(-sdm_enclosure[0]) nsdm.movey(-sdm_enclosure[1]) # generating contacts and local interconnects and mcon and m1 of n+ diffusion rect_c = gf.components.rectangle(size=contact_size, layer=contact_layer) rect_mc = gf.components.rectangle(size=contact_size, layer=mcon_layer) nr = floor(gate_width / (2 * contact_size[1])) nc = floor(sd_width / (2 * contact_size[0])) con_sp = list(contact_spacing) con_sp[0] = con_sp[1] = contact_spacing[0] + contact_size[0] min_gate_wid = 0.42 cont_arr1 = c.add_array(rect_c, rows=nr, columns=nc, spacing=con_sp) cont_arr2 = c.add_array(rect_c, rows=nr, columns=nc, spacing=con_sp) cont_arr1.movey((min_gate_wid - contact_size[1]) / 2) cont_arr2.movey((min_gate_wid - contact_size[1]) / 2) mcont_arr1 = c.add_array(rect_mc, rows=nr, columns=nc, spacing=con_sp) mcont_arr2 = c.add_array(rect_mc, rows=nr, columns=nc, spacing=con_sp) mcont_arr1.movey((min_gate_wid - contact_size[1]) / 2) mcont_arr2.movey((min_gate_wid - contact_size[1]) / 2) rect_lid = gf.components.rectangle( size=(li_width, gate_width + li_enclosure), layer=li_layer ) li1 = c.add_array(rect_lid, rows=1, columns=nc, spacing=con_sp) li2 = c.add_array(rect_lid, rows=1, columns=nc, spacing=con_sp) # rect_m1d = gf.components.rectangle(size= ( contact_size[0] + 2*mcon_enclosure[0], cont_arr1.ymax - cont_arr1.ymin + contact_size[1] + 2*mcon_enclosure[1]), layer= m1_layer) rect_m1d = gf.components.rectangle( size=(contact_size[0] + 2 * mcon_enclosure[0], gate_width), layer=m1_layer ) m1d1 = c.add_array(rect_m1d, rows=1, columns=nc, spacing=con_sp) m1d2 = c.add_array(rect_m1d, rows=1, columns=nc, spacing=con_sp) if nc > 1: cont_arr1.movex((sd_width - (cont_arr1.xmax - cont_arr1.xmin)) / 2) cont_arr2.movex( (nf * (sd_width + gate_length)) + ((sd_width - (cont_arr2.xmax - cont_arr2.xmin)) / 2) ) mcont_arr1.movex((sd_width - (cont_arr1.xmax - cont_arr1.xmin)) / 2) mcont_arr2.movex( (nf * (sd_width + gate_length)) + ((sd_width - (cont_arr2.xmax - cont_arr2.xmin)) / 2) ) li1.movex((sd_width - (cont_arr1.xmax - cont_arr1.xmin)) / 2) li2.movex( (nf * (sd_width + gate_length)) + ((sd_width - (cont_arr2.xmax - cont_arr2.xmin)) / 2) ) m1d1.movex( (sd_width - (cont_arr1.xmax - cont_arr1.xmin)) / 2 - mcon_enclosure[0] ) m1d2.movex( (nf * (sd_width + gate_length)) + ((sd_width - (cont_arr2.xmax - cont_arr2.xmin)) / 2) - mcon_enclosure[0] ) else: cont_arr1.movex((sd_width - contact_size[0]) / 2) cont_arr2.movex( (nf * (sd_width + gate_length)) + ((sd_width - contact_size[0]) / 2) ) mcont_arr1.movex((sd_width - contact_size[0]) / 2) mcont_arr2.movex( (nf * (sd_width + gate_length)) + ((sd_width - contact_size[0]) / 2) ) li1.movex((sd_width - contact_size[0]) / 2) li2.movex((nf * (sd_width + gate_length)) + ((sd_width - contact_size[0]) / 2)) m1d1.movex((sd_width - contact_size[0]) / 2 - mcon_enclosure[0]) m1d2.movex( (nf * (sd_width + gate_length)) + ((sd_width - contact_size[0]) / 2) - mcon_enclosure[0] ) li1.movey(-li_enclosure / 2) li2.movey(-li_enclosure / 2) # generating contacts and local interconnects and mcon and m1 of poly if gate_length <= contact_size[0]: pc_x = contact_enclosure[0] + contact_size[0] + contact_enclosure[0] cont_p = c.add_array( rect_c, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) cont_p.movex(sd_width - ((pc_x - gate_length) / 2) + contact_enclosure[0]) cont_p.movey(gate_width + end_cap + contact_enclosure[1]) cont_p2 = c.add_array( rect_c, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) cont_p2.movex(sd_width - ((pc_x - gate_length) / 2) + contact_enclosure[0]) cont_p2.movey(-end_cap - contact_enclosure[1] - contact_size[1]) mcont_p = c.add_array( rect_mc, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) mcont_p.movex(sd_width - ((pc_x - gate_length) / 2) + contact_enclosure[0]) mcont_p.movey(gate_width + end_cap + contact_enclosure[1]) mcont_p2 = c.add_array( rect_mc, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) mcont_p2.movex(sd_width - ((pc_x - gate_length) / 2) + contact_enclosure[0]) mcont_p2.movey(-end_cap - contact_enclosure[1] - contact_size[1]) else: pc_x = gate_length nc_p = floor(pc_x / (2 * contact_size[0])) for i in range(nf): cont_arr3 = c.add_array(rect_c, rows=1, columns=nc_p, spacing=con_sp) cont_arr3.movex( sd_width + ((gate_length - (cont_arr3.xmax - cont_arr3.xmin)) / 2) + (i * (gate_length + sd_width)) ) cont_arr3.movey(gate_width + end_cap + contact_enclosure[1]) cont_arr5 = c.add_array(rect_c, rows=1, columns=nc_p, spacing=con_sp) cont_arr5.movex( sd_width + ((gate_length - (cont_arr5.xmax - cont_arr5.xmin)) / 2) + (i * (gate_length + sd_width)) ) cont_arr5.movey(-contact_size[1] - end_cap - contact_enclosure[1]) mcont_arr3 = c.add_array(rect_mc, rows=1, columns=nc_p, spacing=con_sp) mcont_arr3.movex( sd_width + ((gate_length - (cont_arr3.xmax - cont_arr3.xmin)) / 2) + (i * (gate_length + sd_width)) ) mcont_arr3.movey(gate_width + end_cap + contact_enclosure[1]) mcont_arr5 = c.add_array(rect_mc, rows=1, columns=nc_p, spacing=con_sp) mcont_arr5.movex( sd_width + ((gate_length - (cont_arr5.xmax - cont_arr5.xmin)) / 2) + (i * (gate_length + sd_width)) ) mcont_arr5.movey(-contact_size[1] - end_cap - contact_enclosure[1]) pc_size = ( pc_x, contact_enclosure[1] + contact_size[1] + contact_enclosure[1], ) # poly size to contain contact rect_pc = gf.components.rectangle(size=pc_size, layer=poly_layer) rect_m1p = gf.components.rectangle( size=( pc_x + 2 * mcon_enclosure[0] - 2 * contact_enclosure[0], contact_size[1] + 2 * mcon_enclosure[1], ), layer=m1_layer, ) pc_u = c.add_array(rect_pc, rows=1, columns=nf, spacing=[sd_width + gate_length, 0]) pc_u.movex(sd_width - ((pc_x - gate_length) / 2)) pc_u.movey(gate_width + end_cap) pc_d = c.add_array(rect_pc, rows=1, columns=nf, spacing=[sd_width + gate_length, 0]) pc_d.movex(sd_width - ((pc_x - gate_length) / 2)) pc_d.movey(-pc_size[1] - end_cap) m1p_u = c.add_array( rect_m1p, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) m1p_u.movex( sd_width - ((pc_x - gate_length) / 2) + contact_enclosure[0] - mcon_enclosure[0] ) m1p_u.movey(gate_width + end_cap + contact_enclosure[1] - mcon_enclosure[1]) m1p_d = c.add_array( rect_m1p, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) m1p_d.movex( sd_width - ((pc_x - gate_length) / 2) + contact_enclosure[0] - mcon_enclosure[0] ) m1p_d.movey(-pc_size[1] - end_cap + contact_enclosure[1] - contact_enclosure[1]) rect_lip = gf.components.rectangle( size=(pc_size[0] + li_enclosure, li_width), layer=li_layer ) lip_u = c.add_array( rect_lip, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) lip_u.movex(sd_width - ((pc_x - gate_length) / 2) - li_enclosure / 2) lip_u.movey(gate_width + end_cap + contact_enclosure[1]) lip_d = c.add_array( rect_lip, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) lip_d.movex(sd_width - ((pc_x - gate_length) / 2) - li_enclosure / 2) lip_d.movey(-pc_size[1] - end_cap + contact_enclosure[1]) # generating npc for poly contacts npc_en = end_cap - npc_spacing rect_npc = gf.components.rectangle( size=(pc_size[0] + npc_en, pc_size[1] + npc_en), layer=npc_layer ) npc_u = c.add_array( rect_npc, rows=1, columns=nf, spacing=[sd_width + gate_length, 0] ) .....
a
@Charly Meyer We already have that here:
c
Yes I found it there! but it was taken 1 month! I'm starting to go crazy. The best way I found to have the gds o a transistor is to lunch on python the fonction nmos in nmos.py with the L and W I want and extrct it with the fonction write_gds() and finaly open it with klayout
a
@Charly Meyer You don't need to do this
Please check the videos on youtube on efabless channel.