Skip to content

Commit

Permalink
Team: Salty Chip, Chipathon2024
Browse files Browse the repository at this point in the history
    Complete the first prototyping layout of the transmission gate in an interdigitized fashion
    #Status:Magic DRC passed, netlist generation for the LVS is still working in progress
    #PCell status: W.I.P.
    #User manual about the PCell: W.I.P.
    #Completion date (expected): 23.Nov.2024
  • Loading branch information
tsengs0 committed Nov 21, 2024
1 parent 84b94b3 commit 351cbdf
Show file tree
Hide file tree
Showing 9 changed files with 112 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
def initialise():
global inv_channel_width_base, tg_channel_width_base
inv_channel_width_base = 3.0
tg_channel_width_base = 3.0
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130
import reconfig_inv as reconfig_inv
import transmission_gate as tg
import comp_dc

TARGET_PDK = sky130
PWD_OUTPUT = subprocess.run(['pwd'], capture_output=True, text=True)
GDS_DIR = PWD_OUTPUT.stdout.strip() + "/gds"

pmos_width = 1.5
pmos_width = 6.0*2
pmos_length = 0.15
nmos_width = 1.5
nmos_width = 6.0*2
nmos_length = 0.15

def basic_tg_eval():
Expand All @@ -26,13 +27,15 @@ def basic_tg_eval():

tg_dut.show()
tg_dut.write_gds(f"{GDS_DIR}/{tg_dut.name}.gds")
'''
magic_drc_result = sky130.drc_magic(
layout=tg_dut,
design_name=tg_dut.name#,
#output_file=f"{absolute_path}/{tg.name}.rpt"
)
print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result)
print("--------------------------------------")
'''

def gate_ctrl_inv_eval():
gate_ctrl_inv = reconfig_inv.reconfig_inv(
Expand Down Expand Up @@ -75,8 +78,9 @@ def tg_with_ctrl_eval():

def main():
basic_tg_eval()
gate_ctrl_inv_eval()
#gate_ctrl_inv_eval()
#tg_with_ctrl_eval()

if __name__ == "__main__":
main()
comp_dc.initialise()
main()
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from glayout.flow.routing.L_route import L_route
from glayout.flow.routing.smart_route import smart_route

LONG_CHANNEL_WIDTH = 1.5
import comp_dc

#@cell
def short_channel_inv(
Expand Down Expand Up @@ -176,7 +176,7 @@ def reconfig_inv(
) -> Component:
if pmos_width != nmos_width:
raise ValueError("PCell constraint: the widths of PMOS and NMOS must be identical")
elif pmos_width >= LONG_CHANNEL_WIDTH: # Long-channel PMOS and NMOS
elif pmos_width >= comp_dc.inv_channel_width_base: # Long-channel PMOS and NMOS
inv = long_channel_inv(
pdk=pdk,
component_name=component_name,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict
import math
#from glayout.flow.pdk.gf180_mapped import gf180
from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130
from glayout.flow.pdk.mappedpdk import MappedPDK
from glayout.flow.pdk.util.comp_utils import evaluate_bbox
from glayout.flow.pdk.util.port_utils import set_port_orientation, rename_ports_by_orientation, create_private_ports
from gdsfactory import Component
from gdsfactory.components import rectangle
from glayout.flow.primitives.fet import pmos
Expand All @@ -11,14 +13,14 @@
from glayout.flow.routing.c_route import c_route
from glayout.flow.routing.L_route import L_route
from glayout.flow.routing.smart_route import smart_route
from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized
from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized
from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized, two_nfet_interdigitized, two_transistor_interdigitized
from glayout.flow.placement.common_centroid_ab_ba import common_centroid_ab_ba
from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port
from glayout.flow.primitives.via_gen import via_stack

# My own cell library
from reconfig_inv import reconfig_inv

LONG_CHANNEL_WIDTH = 1.5
import comp_dc

#@cell
def short_channel_tg(
Expand All @@ -36,8 +38,8 @@ def short_channel_tg(
# To prepare all necessary cells to construct a transmission gate, i.e.
# 1) PMOS
# 2) NMOS
pfet = pmos(pdk=pdk, gate_rmult=2, with_substrate_tap=False, with_dummy=(True, False), width=pmos_width, length=pmos_length)
nfet = nmos(pdk=pdk, gate_rmult=2, with_dnwell=False, with_substrate_tap=False, with_dummy=(False, True), width=nmos_width, length=nmos_length)
pfet = pmos(pdk=pdk, gate_rmult=2, with_tie=False, with_substrate_tap=False, with_dummy=(True, False), width=pmos_width, length=pmos_length)
nfet = nmos(pdk=pdk, gate_rmult=2, with_tie=False, with_dnwell=False, with_substrate_tap=False, with_dummy=(False, True), width=nmos_width, length=nmos_length)

# Placement and adding ports
top_level = Component(name=component_name)
Expand Down Expand Up @@ -109,11 +111,15 @@ def long_channel_tg(
add_pin: bool = True, # For LVS
**kwargs
) -> Component:
# To calculate the number of fingers for the underlying PMOS/NMOS layout
finger_num = math.ceil(pmos_width / comp_dc.tg_channel_width_base)
mos_width = comp_dc.tg_channel_width_base

# To prepare all necessary cells to construct a transmission gate, i.e.
# 1) PMOS
# 2) NMOS
pfet = pmos(pdk=pdk, gate_rmult=2, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length)
nfet = nmos(pdk=pdk, gate_rmult=2, with_dnwell=False, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length)
pfet = pmos(pdk=pdk, multipliers=1, fingers=finger_num, interfinger_rmult=3, gate_rmult=1, with_tie=False, with_substrate_tap=False, with_dummy=(False, False), width=mos_width, length=pmos_length)
nfet = nmos(pdk=pdk, multipliers=1, fingers=finger_num, interfinger_rmult=3, gate_rmult=1, with_tie=False, with_dnwell=False, with_substrate_tap=False, with_dummy=(False, False), width=mos_width, length=nmos_length)

# Placement and adding ports
top_level = Component(name=component_name)
Expand All @@ -124,18 +130,92 @@ def long_channel_tg(

# Placement
mos_spacing = pdk.util_max_metal_seperation()
if orientation_config["pmos_degree"] != None:
pfet_ref.rotate(orientation_config["pmos_degree"])
if orientation_config["nmos_degree"] != None:
nfet_ref.rotate(orientation_config["nmos_degree"])
#if orientation_config["pmos_degree"] != None:
# pfet_ref.rotate(orientation_config["pmos_degree"])
#if orientation_config["nmos_degree"] != None:
# nfet_ref.rotate(orientation_config["nmos_degree"])
rename_ports_by_orientation(nfet_ref.mirror_y()) # To vertically flip the NMOS such that the its gate point toward the PMOS's gate
pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)


pmos_drain_viaStack = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
pmos_drain_viaStack1 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
pmos_drain_viaStack2 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
pmos_drain_viaStack3 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
pmos_drain_viaStack4 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
pmos_drain_viaStack5 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")

nmos_drain_viaStack = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
nmos_drain_viaStack1 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
nmos_drain_viaStack2 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
nmos_drain_viaStack3 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
nmos_drain_viaStack4 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")
nmos_drain_viaStack5 = via_stack(pdk=pdk, glayer1="met2", glayer2="met3")

pmos_drain_viaStack_ref = prec_ref_center(pmos_drain_viaStack)
pmos_drain_viaStack1_ref = prec_ref_center(pmos_drain_viaStack1)
pmos_drain_viaStack2_ref = prec_ref_center(pmos_drain_viaStack2)
pmos_drain_viaStack3_ref = prec_ref_center(pmos_drain_viaStack3)
pmos_drain_viaStack4_ref = prec_ref_center(pmos_drain_viaStack4)
pmos_drain_viaStack5_ref = prec_ref_center(pmos_drain_viaStack5)
nmos_drain_viaStack_ref = prec_ref_center(nmos_drain_viaStack)
nmos_drain_viaStack1_ref = prec_ref_center(nmos_drain_viaStack1)
nmos_drain_viaStack2_ref = prec_ref_center(nmos_drain_viaStack2)
nmos_drain_viaStack3_ref = prec_ref_center(nmos_drain_viaStack3)
nmos_drain_viaStack4_ref = prec_ref_center(nmos_drain_viaStack4)
nmos_drain_viaStack5_ref = prec_ref_center(nmos_drain_viaStack5)
top_level.add(pmos_drain_viaStack_ref)
top_level.add(pmos_drain_viaStack1_ref)
top_level.add(pmos_drain_viaStack2_ref)
top_level.add(pmos_drain_viaStack3_ref)
top_level.add(pmos_drain_viaStack4_ref)
top_level.add(pmos_drain_viaStack5_ref)
top_level.add(nmos_drain_viaStack_ref)
top_level.add(nmos_drain_viaStack1_ref)
top_level.add(nmos_drain_viaStack2_ref)
top_level.add(nmos_drain_viaStack3_ref)
top_level.add(nmos_drain_viaStack4_ref)
top_level.add(nmos_drain_viaStack5_ref)

pmos_drain_viaStack_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)
pmos_drain_viaStack1_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)
pmos_drain_viaStack2_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)
pmos_drain_viaStack3_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing - pdk.get_grule("met3")["min_separation"] - pdk.get_grule("met3")["min_width"])
pmos_drain_viaStack4_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing - pdk.get_grule("met3")["min_separation"] - pdk.get_grule("met3")["min_width"])
pmos_drain_viaStack5_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing - pdk.get_grule("met3")["min_separation"] - pdk.get_grule("met3")["min_width"])
nmos_drain_viaStack3_ref.movey(pdk.get_grule("met3")["min_separation"]+pdk.get_grule("met3")["min_width"])
nmos_drain_viaStack4_ref.movey(pdk.get_grule("met3")["min_separation"]+pdk.get_grule("met3")["min_width"])
nmos_drain_viaStack5_ref.movey(pdk.get_grule("met3")["min_separation"]+pdk.get_grule("met3")["min_width"])
pmos_drain_viaStack1_ref.movex(pfet_ref.ports["source_W"].center[0]+0.15)
pmos_drain_viaStack2_ref.movex(-pfet_ref.ports["source_W"].center[0]-0.15)
pmos_drain_viaStack4_ref.movex(pfet_ref.ports["source_W"].center[0]+0.15)
pmos_drain_viaStack5_ref.movex(-pfet_ref.ports["source_W"].center[0]-0.15)
nmos_drain_viaStack1_ref.movex(pfet_ref.ports["source_W"].center[0]+0.15)
nmos_drain_viaStack2_ref.movex(-pfet_ref.ports["source_W"].center[0]-0.15)
nmos_drain_viaStack4_ref.movex(pfet_ref.ports["source_W"].center[0]+0.15)
nmos_drain_viaStack5_ref.movex(-pfet_ref.ports["source_W"].center[0]-0.15)

c = Component()
c.add_polygon(
[
(nmos_drain_viaStack1_ref.xmin, nmos_drain_viaStack1_ref.ymin),#leftBottom_pos
(nmos_drain_viaStack2_ref.xmax, nmos_drain_viaStack2_ref.ymin),#rightBottom_pos
(pmos_drain_viaStack2_ref.xmax, pmos_drain_viaStack2_ref.ymax),#rightTop_pos
(pmos_drain_viaStack1_ref.xmin, pmos_drain_viaStack1_ref.ymax) #leftTop_pos
],
layer=pdk.get_glayer("met3")
)
c_ref = top_level.add_ref(c)

# Routing
# To simplify the routing for the parallel-gate transistors, the layout is realised as follow which is expected to be equivalent to a TG
# a) PMOS.source connected to NMOS.source
# b) PMOS.drain connected to NMOS.drain
top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_source_S"], nfet_ref.ports["multiplier_0_drain_S"], glayer1="met3") # "in" of the TG
top_level << c_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_W"], cglayer="met3") # "out" of the TG
# b) PMOS.drain connected to NMOS.drain
top_level << c_route(pdk, pfet_ref.ports["drain_E"], nfet_ref.ports["drain_E"], cglayer="met3") # "out" of the TG

#top_level << straight_route(pdk, pmos_drain_viaStack_ref.ports["top_met_S"], nmos_drain_viaStack_ref.ports["top_met_S"])#, glayer1="met3")
#top_level << straight_route(pdk, pmos_drain_viaStack1_ref.ports["top_met_S"], nmos_drain_viaStack1_ref.ports["top_met_S"])
#top_level << straight_route(pdk, pmos_drain_viaStack2_ref.ports["top_met_S"], nmos_drain_viaStack2_ref.ports["top_met_S"])

# Add the ports aligned with the basic PMOS and NMOS
top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_")
Expand All @@ -151,11 +231,11 @@ def long_channel_tg(
# --- Port: A, i.e. input of the transmission gate
A_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy()
A_pin.add_label(text="A", layer=met1_label)
pin_info.append((A_pin, top_level.ports.get(f"nmos_drain_S"), None))
pin_info.append((A_pin, top_level.ports.get(f"nmos_source_S"), None))
# --- Port: Y, i.e. output of the transmission gate
Y_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy()
Y_pin.add_label(text="Y", layer=met1_label)
pin_info.append((Y_pin, top_level.ports.get(f"nmos_drain_N"), None))
pin_info.append((Y_pin, top_level.ports.get(f"nmos_drain_S"), None))
# --- Port: C, i.e. gate control to the NMOS
C_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy()
C_pin.add_label(text="C", layer=met1_label)
Expand Down Expand Up @@ -280,7 +360,7 @@ def reconfig_tg(
) -> Component:
if pmos_width != nmos_width:
raise ValueError("PCell constraint: the widths of PMOS and NMOS must be identical")
elif pmos_width >= LONG_CHANNEL_WIDTH: # Long-channel PMOS and NMOS
elif pmos_width >= comp_dc.tg_channel_width_base: # Long-channel PMOS and NMOS
tg = long_channel_tg(
pdk=pdk,
component_name=component_name,
Expand Down

0 comments on commit 351cbdf

Please sign in to comment.