From 1a3770b668be703e84e483458a2f114fad735786 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 3 Nov 2024 12:47:20 +0000 Subject: [PATCH 01/21] Add the transmission gate (still onging) folder from the SaltyChi team in Chipathon 2024 --- .../transmission_gate_saltychip/inv_lib.py | 43 ++++++++++ .../transmission_gate.py | 83 +++++++++++++++++++ 2 files changed, 126 insertions(+) create mode 100755 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py create mode 100755 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py new file mode 100755 index 000000000..3d6b13370 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py @@ -0,0 +1,43 @@ +#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 prec_ref_center, movex, movey, evaluate_bbox, align_comp_to_port +from gdsfactory import Component +from gdsfactory.components import rectangle +from glayout.flow.primitives.fet import pmos +from glayout.flow.primitives.fet import nmos +from glayout.flow.routing.straight_route import straight_route +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 + +def basic_inv_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length, orientation): + # Create a top level component + top_level = Component("inverter") + # To prepare one PMOS and one NMOS for the subsequent inverter cell construction + pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) + + # Instantiation of above PMOS and NMOS under the top level + pfet_ref = prec_ref_center(pfet) + nfet_ref = prec_ref_center(nfet) + top_level.add(pfet_ref) + top_level.add(nfet_ref) + + # To add the ports + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + + # Placement (relative move) + mos_spacing = pdk.util_max_metal_seperation() + if(orientation=="horizontal"): + #pfet_ref.drotate(90) + #nfet_ref.drotate(90) + pass + pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) + + # Routing + top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_E"]) + top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_gate_W"], nfet_ref.ports["multiplier_0_gate_W"]) + + return top_level diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py new file mode 100755 index 000000000..1d75347b7 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -0,0 +1,83 @@ +#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 gdsfactory import Component +from gdsfactory.components import rectangle +from glayout.flow.primitives.fet import pmos +from glayout.flow.primitives.fet import nmos +from glayout.flow.routing.straight_route import straight_route +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.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port + +# My own cell library +from inv_lib import basic_inv_cell + +def naive_tg_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): + # To prepare all necessary cells to construct a transmission gate, i.e. + # 1) PMOS + # 2) NMOS + # 3) Inverter (to control the gates of above PMOS and NMOS) + pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) + inv = basic_inv_cell(pdk=pdk, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation="vertical") + + # Placement and adding ports + top_level = Component(name="TG") + pfet_ref = prec_ref_center(pfet) + nfet_ref = prec_ref_center(nfet) +# inv_ref = prec_ref_center(inv) + top_level.add(pfet_ref) + top_level.add(nfet_ref) +# top_level.add(inv_ref) + inv_ref = top_level << inv + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + top_level.add_ports(inv_ref.get_ports_list(), prefix="inv_") + + # Placement + mos_spacing = pdk.util_max_metal_seperation() + pfet_ref.movey(evaluate_bbox(nfet_ref)[1]+mos_spacing) + pfet_ref.movex(evaluate_bbox(inv_ref)[0]+mos_spacing) # Placing the TG's PMOS at right side of the inverter + nfet_ref.movex(evaluate_bbox(inv_ref)[0]+mos_spacing) # Placing the TG's NMOS at right side of the inverter + + # Routing + top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG + top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"]) # "out" of the TG + top_level << smart_route(pdk, inv_ref.ports["pmos_multiplier_0_drain_W"], pfet_ref.ports["multiplier_0_gate_W"]) # connect inv's output to PMOS's gate + top_level << straight_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_E"], nfet_ref.ports["multiplier_0_gate_E"]) + + # Add pins and text labels for LVS + pins_labels_info = list() # list that contains all port and component information + + # To define the layers + gds_met1 = pdk.get_glayer("met2")[0] + gds_met2 = gds_met1+1 + gds_met3 = gds_met2+1 + gds_met4 = gds_met3+1 + gds_met5 = gds_met4+1 + # To get the respective layers of the underlying TG's PMOS.source port PMOS.drain port + tg_din_portLayer = top_level.ports["pmos_multiplier_0_source_W"].layer[0] + tg_dout_portLayer = top_level.ports["pmos_multiplier_0_drain_E"].layer[0] + # To create the pins w/ labels and append to info list + tg_din_pin = rectangle(layer=(tg_din_portLayer, 16), size=(1, 1),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) + tg_dout_pin = rectangle(layer=(tg_dout_portLayer, 16), size=(1, 1), centered=True).copy() + tg_din_pin.add_label(text="Vin", layer=(tg_din_portLayer, 5)) + tg_dout_pin.add_label(text="Vout", layer=(tg_dout_portLayer, 5)) + pins_labels_info.append((tg_din_pin, top_level.ports["pmos_multiplier_0_source_W"], None)) + pins_labels_info.append((tg_dout_pin, top_level.ports["pmos_multiplier_0_drain_E"], None)) + + #print(top_level.ports["pmos_multiplier_0_source_W"].name) + #top_level.pprint_ports() + + # Move everythin to position + for comp, prt, alignment in pins_labels_info: + alignment = ('c', 'b') if alignment is None else alignment + compref = align_comp_to_port(comp, prt, alignment=alignment) + #top_level.add(compref) + + return top_level #top_level.flatten() From 0377bae1691e1c4740fbc02bd9d762ab6870e6e0 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 3 Nov 2024 13:05:57 +0000 Subject: [PATCH 02/21] Add the README and __init__.py files for the transmission gate block Developer: SaltyChip team in Chipathon 2024 --- .../flow/blocks/transmission_gate_saltychip/README.md | 6 ++++++ .../flow/blocks/transmission_gate_saltychip/__init__.py | 2 ++ 2 files changed, 8 insertions(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md new file mode 100644 index 000000000..11a8225b4 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md @@ -0,0 +1,6 @@ +# Transmission gate block for SAR A/D converter + +| Design File | Description | Remark | +| --- | --- | --- | +| inv_lib.py | Layout generation of inverter for controlling the transmission gate's PMOS and NMOS | | +| transmission_gate.py | Layout generation of a transmission gate | The layout is still under construction | diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py new file mode 100644 index 000000000..8118c6390 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py @@ -0,0 +1,2 @@ +from glayout.flow.blocks.transmission_gate_saltychip.inv_lib import basic_inv_cell +from glayout.flow.blocks.transmission_gate_saltychip.transmission_gate import naive_tg_cell From 5d7dc555ecc00a32bf9ed7ee42b1b616bb0aa497 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 3 Nov 2024 13:28:15 +0000 Subject: [PATCH 03/21] Add mimcap array layout --- .../transmission_gate_saltychip/README.md | 3 + .../mimcap_array.py | 451 ++++++++++++++++++ 2 files changed, 454 insertions(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md index 11a8225b4..d2cc04388 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md @@ -1,6 +1,9 @@ # Transmission gate block for SAR A/D converter +- Team: SaltyChip +- Design (our target): DAC for 6-bit A/D converter | Design File | Description | Remark | | --- | --- | --- | | inv_lib.py | Layout generation of inverter for controlling the transmission gate's PMOS and NMOS | | | transmission_gate.py | Layout generation of a transmission gate | The layout is still under construction | +| mimcap_array.py | Layout generation of a 8x8 MIM capacitor array | Transmission gate combined with a MIM capacitor array is the aim in this project | diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py new file mode 100644 index 000000000..0b87f2310 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py @@ -0,0 +1,451 @@ +# Primitives +from glayout.flow.primitives.mimcap import mimcap +from glayout.flow.primitives.mimcap import mimcap_array +from glayout.flow.primitives.via_gen import via_stack, via_array + +# Standard +from glayout.flow.pdk.mappedpdk import MappedPDK +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 + +# gdsfactory +from gdsfactory import Component +from gdsfactory.cell import cell +from gdsfactory.components.rectangle import rectangle + +# Utility +from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_center, prec_array, align_comp_to_port + +# Routing +from glayout.flow.routing.straight_route import straight_route +from glayout.flow.routing.c_route import c_route + +import copy + +def get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: + """returns the glayer metal below and glayer metal above capmet + args: pdk + """ + capmettop = pdk.layer_to_glayer(pdk.get_grule("capmet")["capmettop"]) + capmetbottom = pdk.layer_to_glayer(pdk.get_grule("capmet")["capmetbottom"]) + pdk.has_required_glayers(["capmet",capmettop,capmetbottom]) + pdk.activate() + return capmettop, capmetbottom + +def create_6bit_dac_mimcap_array(pdk: MappedPDK): + """ + Creates a 6-bit DAC using an 8x8 MIM capacitor array with binary weighting. + """ + # Create the top-level component + dac_mim_cap = Component("6bit_DAC_MIMCAP_Array") + + ''' + # Define unit capacitor size (for example, 2x2 microns) + unit_size = [5.0, 5.0] + unit_mimcap = mimcap(pdk, size=unit_size) + + # Define bit weights for binary weighted capacitors + bit_weights = [32, 16, 8, 4, 2, 1] # From MSB to LSB + total_units = sum(bit_weights) + total_caps = 64 # 8x8 array + dummy_units = total_caps - total_units # Extra units as dummy + + # Generate common centroid indices for optimal matching + cap_indices = [(i, j) for i in range(8) for j in range(8)] + ''' + + # metal and via layers + met2 = pdk.get_glayer('met3') + met3_capmetbottom = pdk.get_glayer('met4') + met4_capmettop = pdk.get_glayer('met5') + via3 = pdk.get_glayer('via4') + mimcap_arr = Component("mimcap_arr") + #test_cap << rectangle(size=(1, 1), layer=via3) + mimcap_single_size = 5 + mimcap_single = mimcap(pdk, size=(mimcap_single_size,mimcap_single_size)) + rows_num = 8 + columns_num = 8 + mimcap_space = 10*pdk.get_grule("capmet")["min_separation"] + met4_width = pdk.get_grule("met5")["min_width"] + array_ref = mimcap_arr << prec_array(mimcap_single, rows=rows_num, columns=columns_num, spacing=2*[mimcap_space]) + mimcap_arr.add_ports(array_ref.get_ports_list()) + mim_metal_space = mimcap_space/9 + ##################### + port_pairs = list() + port_sides_pairs = list() + via_refs = list() + for rownum in range(rows_num): + for colnum in range(columns_num): + base_mimcap = f"row{rownum}_col{colnum}_" + right_mimcap = f"row{rownum}_col{colnum+1}_" + up_mimcap = f"row{rownum+1}_col{colnum}_" + capmetbottom = "met4" + capmettop = "met5" + + # Bottom Metal + level = "bottom_met_" + layer = capmetbottom + base_east_port = mimcap_arr.ports.get(base_mimcap+level+"E") + right_west_port = mimcap_arr.ports.get(right_mimcap+level+"W") + base_north_port = mimcap_arr.ports.get(base_mimcap+level+"N") + up_south_port = mimcap_arr.ports.get(up_mimcap+level+"S") + if rownum == rows_num-1 and colnum == columns_num-1: + pass #continue + elif rownum == rows_num-1: + port_pairs.append((base_east_port,right_west_port,layer)) + elif colnum == columns_num-1: + port_pairs.append((base_north_port,up_south_port,layer)) + else: + port_pairs.append((base_east_port,right_west_port,layer)) + port_pairs.append((base_north_port,up_south_port,layer)) + + # Top metal + level = "top_met_" + position_up = "up_" + position_down = "down_" + position_right = "right_" + position_left = "left_" + layer = capmettop + base_east_port = mimcap_arr.ports.get(base_mimcap+level+"E") + met4_distance_from_center = base_east_port.width/2 - pdk.get_grule(layer)["min_width"] + if base_east_port is not None: + base_east_port_up = base_east_port.copy() + base_east_port_up.name = base_mimcap+position_up+level+"E" + base_east_port_up.center[1] += met4_distance_from_center #(base_east_port_up.width/2 - pdk.get_grule(layer)["min_width"]) + base_east_port_up_space1 = base_east_port_up.copy() + base_east_port_up_space1.name = base_mimcap+position_up+level+"W" + base_east_port_up_space1.center[0] += mim_metal_space*1 + base_east_port_up_space4 = base_east_port_up.copy() + base_east_port_up_space4.name = base_mimcap+position_up+level+"W" + base_east_port_up_space4.center[0] += mim_metal_space*4 + base_east_port_down = base_east_port.copy() + base_east_port_down.name = base_mimcap+position_down+level+"E" + base_east_port_down.center[1] -= met4_distance_from_center #(base_north_port.width/2 - pdk.get_grule(layer)["min_width"]) + base_east_port_down_space1 = base_east_port_down.copy() + base_east_port_down_space1.name = base_mimcap+position_down+level+"W" + base_east_port_down_space1.center[0] += mim_metal_space*1 + base_east_port_down_space4 = base_east_port_down.copy() + base_east_port_down_space4.name = base_mimcap+position_down+level+"W" + base_east_port_down_space4.center[0] += mim_metal_space*4 + right_west_port = mimcap_arr.ports.get(right_mimcap+level+"W") + if right_west_port is not None: + right_west_port_up = right_west_port.copy() + right_west_port_up.name = right_mimcap+position_up+level+"W" + right_west_port_up.center[1] += met4_distance_from_center #(right_west_port_up.width/2 - pdk.get_grule(layer)["min_width"]) + right_west_port_up_space3 = right_west_port_up.copy() + right_west_port_up_space3.name = right_mimcap+position_up+level+"E" + right_west_port_up_space3.center[0] -= mim_metal_space*3 + right_west_port_up_space4 = right_west_port_up.copy() + right_west_port_up_space4.name = right_mimcap+position_up+level+"E" + right_west_port_up_space4.center[0] -= mim_metal_space*4 + right_west_port_up_space7 = right_west_port_up.copy() + right_west_port_up_space7.name = right_mimcap+position_up+level+"E" + right_west_port_up_space7.center[0] -= mim_metal_space*7 + right_west_port_down = right_west_port.copy() + right_west_port_down.name = right_mimcap+position_down+level+"W" + right_west_port_down.center[1] -= met4_distance_from_center #(right_west_port_down.width/2 - pdk.get_grule(layer)["min_width"]) + right_west_port_down_space3 = right_west_port_down.copy() + right_west_port_down_space3.name = right_mimcap+position_down+level+"E" + right_west_port_down_space3.center[0] -= mim_metal_space*3 + right_west_port_down_space4 = right_west_port_down.copy() + right_west_port_down_space4.name = right_mimcap+position_down+level+"E" + right_west_port_down_space4.center[0] -= mim_metal_space*4 + right_west_port_down_space7 = right_west_port_down.copy() + right_west_port_down_space7.name = right_mimcap+position_down+level+"E" + right_west_port_down_space7.center[0] -= mim_metal_space*7 + base_north_port = mimcap_arr.ports.get(base_mimcap+level+"N") + if base_north_port is not None: + base_north_port_right = base_north_port.copy() + base_north_port_right.name = base_mimcap+position_right+level+"N" + base_north_port_right.center[0] += met4_distance_from_center #(base_north_port_right.width/2 - pdk.get_grule(layer)["min_width"]) + base_north_port_right_space = base_north_port_right.copy() + base_north_port_right_space.name = base_mimcap+position_right+level+"S" + base_north_port_right_space.center[1] += mim_metal_space*4 + base_north_port_left = base_north_port.copy() + base_north_port_left.name = base_mimcap+position_left+level+"N" + base_north_port_left.center[0] -= met4_distance_from_center #(base_north_port_left.width/2 - pdk.get_grule(layer)["min_width"]) + base_north_port_left_space = base_north_port_left.copy() + base_north_port_left_space.name = base_mimcap+position_left+level+"S" + base_north_port_left_space.center[1] += mim_metal_space*4 + up_south_port = mimcap_arr.ports.get(up_mimcap+level+"S") + if up_south_port is not None: + up_south_port_right = up_south_port.copy() + up_south_port_right.name = base_mimcap+position_right+level+"S" + up_south_port_right.center[0] += met4_distance_from_center #(up_south_port_right.width/2 - pdk.get_grule(layer)["min_width"]) + up_south_port_right_space = up_south_port_right.copy() + up_south_port_right_space.name = base_mimcap+position_right+level+"N" + up_south_port_right_space.center[1] -= mim_metal_space*4 + up_south_port_left = up_south_port.copy() + up_south_port_left.name = base_mimcap+position_left+level+"S" + up_south_port_left.center[0] -= met4_distance_from_center #(up_south_port_left.width/2 - pdk.get_grule(layer)["min_width"]) + up_south_port_left_space = up_south_port_left.copy() + up_south_port_left_space.name = base_mimcap+position_left+level+"N" + up_south_port_left_space.center[1] -= mim_metal_space*4 + + ''' + if rownum in (0,1,2,4): + if colnum == 0: + base_west_side_port = mimcap_arr.ports.get(base_mimcap+level+"W") + base_west_side_port.name = base_mimcap+level+"westside_"+"W" + base_west_side_port.center + += met4_distance_from_center + else: + if colnum == 7: + ''' + + if rownum == 0: + # North and South + if colnum in (2,3,5,6): + port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) + port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) + port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) + port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) + else: + port_pairs.append((base_north_port_left,up_south_port_left,layer)) + port_pairs.append((base_north_port_right,up_south_port_right,layer)) + # West and East + if colnum in (5,6): #(1,7) + port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) + via_mimcap = via_stack(pdk, "met3", capmettop) + #via_mimcap = via_array(pdk, "met3", capmettop, size=(met4_width,met4_width), num_vias=(2,2), fullbottom=False) + via_refs.append(align_comp_to_port(via_mimcap, right_west_port_up_space7, ("c", "c"))) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + elif rownum == 1: + # North and South + if colnum in (1,2,4,5): + port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) + port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) + port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) + port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) + else: + port_pairs.append((base_north_port_left,up_south_port_left,layer)) + port_pairs.append((base_north_port_right,up_south_port_right,layer)) + # West and East + if colnum in (0,2,3,5): #(4,4) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) + elif colnum in (1,6): #(1,7) + port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) + elif colnum == 4: #(4,3) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + elif rownum == 2: + # North and South + if colnum in (0,1,2,3,4,5,7): + port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) + port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) + port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) + port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) + else: + port_pairs.append((base_north_port_left,up_south_port_left,layer)) + port_pairs.append((base_north_port_right,up_south_port_right,layer)) + # West and East + if colnum in (4,5): #(4,4) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) + elif colnum in (0,6): #(1,7) + port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) + elif colnum == 3: #(4,3) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + elif rownum == 3: + # North and South + if colnum in (0,1,2,3,5,6,7): + port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) + port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) + port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) + port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) + else: + port_pairs.append((base_north_port_left,up_south_port_left,layer)) + port_pairs.append((base_north_port_right,up_south_port_right,layer)) + # West and East + if colnum in (0,1,2,3): #(4,4) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + elif rownum == 4: + # North and South + if colnum in (0,2,3,4,5,6,7): + port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) + port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) + port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) + port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) + else: + port_pairs.append((base_north_port_left,up_south_port_left,layer)) + port_pairs.append((base_north_port_right,up_south_port_right,layer)) + # West and East + if colnum in (2,3): #(4,4) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) + elif colnum in (5,6): #(1,7) + port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) + elif colnum == 4: #(4,3) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + elif rownum == 5: + # North and South + if colnum in (2,3,5,6): + port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) + port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) + port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) + port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) + else: + port_pairs.append((base_north_port_left,up_south_port_left,layer)) + port_pairs.append((base_north_port_right,up_south_port_right,layer)) + # West and East + if colnum in (2,3,6): #(4,4) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) + elif colnum == 1: #(1,7) + port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) + elif colnum == 0: #(4,3) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + elif rownum == 6: + # North and South + if colnum in (1,2,4,5): + port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) + port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) + port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) + port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) + else: + port_pairs.append((base_north_port_left,up_south_port_left,layer)) + port_pairs.append((base_north_port_right,up_south_port_right,layer)) + # West and East + if colnum in (1,2,3,4,5,6): #(4,4) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) + elif colnum == 0: #(4,3) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + elif rownum == 7: + # West and East + if colnum == 1: #(4,4) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) + elif colnum == 0: #(4,3) + port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) + port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) + port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) + port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) + elif colnum == columns_num-1: + pass #continue + else: + port_pairs.append((base_east_port_up,right_west_port_up,layer)) + port_pairs.append((base_east_port_down,right_west_port_down,layer)) + + # metal2 + layer = "met3" + base_east_port_metal2_up = mimcap_arr.ports.get(base_mimcap+level+"E") + base_east_port_metal2_up.name = base_mimcap+"east_metal2_up" + base_east_port_metal2_up.center[0] += mim_metal_space*3 + base_east_port_metal2_up.center[1] += (met4_distance_from_center + met4_width/2) + base_east_port_metal2_up.orientation = 270 + base_east_port_metal2_up.layer = met2 + base_east_port_metal2_down = base_east_port_metal2_up.copy() + base_east_port_metal2_down.name = base_mimcap+"east_metal2_down" + if colnum == 4: + base_east_port_metal2_down.center[1] -= (mimcap_single_size*15/2 + mimcap_space*8) + else: + base_east_port_metal2_down.center[1] -= (mimcap_single_size*17/2 + mimcap_space*8) + port_pairs.append((base_east_port_metal2_up,base_east_port_metal2_down,layer)) + base_west_port_metal2_up = mimcap_arr.ports.get(base_mimcap+level+"W") + base_west_port_metal2_up.name = base_mimcap+"west_metal2_up" + base_west_port_metal2_up.center[0] -= mim_metal_space*3 + base_west_port_metal2_up.center[1] += (met4_distance_from_center + met4_width/2) + base_west_port_metal2_up.orientation = 270 + base_west_port_metal2_up.layer = met2 + base_west_port_metal2_down = base_west_port_metal2_up.copy() + base_west_port_metal2_down.name = base_mimcap+"west_metal2_down" + if colnum in (1,2,6,7): + base_west_port_metal2_down.center[1] -= (mimcap_single_size*15/2 + mimcap_space*8) + else: + base_west_port_metal2_down.center[1] -= (mimcap_single_size*17/2 + mimcap_space*8) + port_pairs.append((base_west_port_metal2_up,base_west_port_metal2_down,layer)) + + for port_pair in port_pairs: + mimcap_arr << straight_route(pdk, port_pair[0], port_pair[1], width=met4_width) + for via_ref in via_refs: + mimcap_arr.add(via_refs) + + cap_ref = dac_mim_cap.add_ref(mimcap_arr) + #cap_ref.movey(-30) + + + return dac_mim_cap + + + +# Create and show the DAC MIM capacitor array layout +dac_mimcap_component = create_6bit_dac_mimcap_array(sky130).show() From 23738f6a9e9cdff7e86bdb4dcb67529af1f19aa0 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 3 Nov 2024 13:36:09 +0000 Subject: [PATCH 04/21] Update the progress in the README --- .../glayout/flow/blocks/transmission_gate_saltychip/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md index d2cc04388..4049e2a20 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md @@ -1,6 +1,7 @@ # Transmission gate block for SAR A/D converter - Team: SaltyChip -- Design (our target): DAC for 6-bit A/D converter +- Design (our target): DAC for 6-bit A/D converter +- Progress: ongoing, 03/11/2024 | Design File | Description | Remark | | --- | --- | --- | From de306c858d390f6c13bfb85cb4df68f7501efab7 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Fri, 8 Nov 2024 07:59:24 +0000 Subject: [PATCH 05/21] Modify the layout of the transmission by rotating every MOSFET 90 degree --- .../transmission_gate_saltychip/__init__.py | 4 +- .../transmission_gate_saltychip/inv_lib.py | 9 ++-- .../transmission_gate.py | 52 +++++++++++++------ 3 files changed, 43 insertions(+), 22 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py index 8118c6390..841af6bae 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py @@ -1,2 +1,2 @@ -from glayout.flow.blocks.transmission_gate_saltychip.inv_lib import basic_inv_cell -from glayout.flow.blocks.transmission_gate_saltychip.transmission_gate import naive_tg_cell +from glayout.flow.blocks.transmission_gate_saltychip.inv_lib import reconfig_inv +from glayout.flow.blocks.transmission_gate_saltychip.transmission_gate import tg_with_inv diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py index 3d6b13370..bd0f3eb87 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py @@ -11,9 +11,9 @@ from glayout.flow.routing.L_route import L_route from glayout.flow.routing.smart_route import smart_route -def basic_inv_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length, orientation): +def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_width, nmos_length, orientation): # Create a top level component - top_level = Component("inverter") + top_level = Component(component_name) # To prepare one PMOS and one NMOS for the subsequent inverter cell construction pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) @@ -31,8 +31,9 @@ def basic_inv_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_len # Placement (relative move) mos_spacing = pdk.util_max_metal_seperation() if(orientation=="horizontal"): - #pfet_ref.drotate(90) - #nfet_ref.drotate(90) + pfet_ref.rotate(90) + nfet_ref.rotate(90) + else: pass pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index 1d75347b7..c2bf6437e 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -15,46 +15,38 @@ from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port # My own cell library -from inv_lib import basic_inv_cell +from inv_lib import reconfig_inv def naive_tg_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS # 2) NMOS - # 3) Inverter (to control the gates of above PMOS and NMOS) pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) - inv = basic_inv_cell(pdk=pdk, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation="vertical") - + # Placement and adding ports top_level = Component(name="TG") pfet_ref = prec_ref_center(pfet) nfet_ref = prec_ref_center(nfet) -# inv_ref = prec_ref_center(inv) top_level.add(pfet_ref) top_level.add(nfet_ref) -# top_level.add(inv_ref) - inv_ref = top_level << inv top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - top_level.add_ports(inv_ref.get_ports_list(), prefix="inv_") # Placement mos_spacing = pdk.util_max_metal_seperation() - pfet_ref.movey(evaluate_bbox(nfet_ref)[1]+mos_spacing) - pfet_ref.movex(evaluate_bbox(inv_ref)[0]+mos_spacing) # Placing the TG's PMOS at right side of the inverter - nfet_ref.movex(evaluate_bbox(inv_ref)[0]+mos_spacing) # Placing the TG's NMOS at right side of the inverter + #mos_spacing = pdk.get_grule("met1")["min_width"]) + pfet_ref.rotate(90) + nfet_ref.rotate(90) + pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) # Routing top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG - top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"]) # "out" of the TG - top_level << smart_route(pdk, inv_ref.ports["pmos_multiplier_0_drain_W"], pfet_ref.ports["multiplier_0_gate_W"]) # connect inv's output to PMOS's gate - top_level << straight_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_E"], nfet_ref.ports["multiplier_0_gate_E"]) + top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_source_W"]) # "out" of the TG # Add pins and text labels for LVS pins_labels_info = list() # list that contains all port and component information - - # To define the layers + # To define the layers gds_met1 = pdk.get_glayer("met2")[0] gds_met2 = gds_met1+1 gds_met3 = gds_met2+1 @@ -81,3 +73,31 @@ def naive_tg_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_leng #top_level.add(compref) return top_level #top_level.flatten() + +def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): + # To prepare all necessary cells to construct a transmission gate, i.e. + # 1) transmission gate + # 2) Inverter + tg = naive_tg_cell(pdk=pdk, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length) + inv = reconfig_inv(pdk=pdk, component_name="gate_ctrl_inv", pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation="horizontal") + + # Placement and adding ports + top_level = Component(name="tg_with_inv") + tg_ref = prec_ref_center(tg) + inv_ref = prec_ref_center(inv) + top_level.add(tg_ref) + top_level.add(inv_ref) + top_level.add_ports(tg_ref.get_ports_list(), prefix="tg_") + top_level.add_ports(inv_ref.get_ports_list(), prefix="inv_") + + # Placement + mos_spacing = pdk.util_max_metal_seperation() + tg_ref.movex(evaluate_bbox(inv)[0] + mos_spacing) + + # Routing + #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG + #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"]) # "out" of the TG + + return top_level #top_level.flatten() + +tg_with_inv(pdk=sky130, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15).show() From b1d1ae02ffb3c15cbb6fd8bd887260242e5ecb19 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 10 Nov 2024 13:28:10 +0000 Subject: [PATCH 06/21] Add dummy cells to the PMOS-NMOS pair for the TG against the asymmetical layout (form of parallel-gate transistors) --- .../transmission_gate.py | 98 ++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index c2bf6437e..043f12b9a 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -1,3 +1,4 @@ +from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict #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 @@ -16,7 +17,7 @@ # My own cell library from inv_lib import reconfig_inv - +''' def naive_tg_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS @@ -98,6 +99,101 @@ def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"]) # "out" of the TG + return top_level #top_level.flatten() +''' +def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_width, pmos_length, nmos_width, nmos_length): + # To prepare all necessary cells to construct a transmission gate, i.e. + # 1) PMOS + # 2) NMOS + pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length) + + # Placement and adding ports + top_level = Component(name="TG") + pfet_ref = prec_ref_center(pfet) + nfet_ref = prec_ref_center(nfet) + top_level.add(pfet_ref) + top_level.add(nfet_ref) + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + #top_level.add_port( + # name="", center=[0, width / 2], width=width, orientation=180, layer=layer + #) + + # Placement + mos_spacing = pdk.util_max_metal_seperation() + #mos_spacing = pdk.get_grule("met1")["min_width"]) + if flip_config["degree"] != None: + pfet_ref.rotate(flip_config["degree"]) + nfet_ref.rotate(flip_config["degree"]) + pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) + + # 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 << smart_route(pdk, pfet_ref.ports["multiplier_0_source_E"], nfet_ref.ports["multiplier_0_source_E"]) # "in" of the TG + top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_drain_E"]) # "out" of the TG + + # Add pins and text labels for LVS + pins_labels_info = list() # list that contains all port and component information + # To define the layers + gds_met1 = pdk.get_glayer("met2")[0] + gds_met2 = gds_met1+1 + gds_met3 = gds_met2+1 + gds_met4 = gds_met3+1 + gds_met5 = gds_met4+1 + # To get the respective layers of the underlying TG's PMOS.source port PMOS.drain port + tg_din_portLayer = top_level.ports["pmos_multiplier_0_source_W"].layer[0] + tg_dout_portLayer = top_level.ports["pmos_multiplier_0_drain_E"].layer[0] + # To create the pins w/ labels and append to info list + tg_din_pin = rectangle(layer=(tg_din_portLayer, 16), size=(1, 1),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) + tg_dout_pin = rectangle(layer=(tg_dout_portLayer, 16), size=(1, 1), centered=True).copy() + tg_din_pin.add_label(text="Vin", layer=(tg_din_portLayer, 5)) + tg_dout_pin.add_label(text="Vout", layer=(tg_dout_portLayer, 5)) + pins_labels_info.append((tg_din_pin, top_level.ports["pmos_multiplier_0_source_W"], None)) + pins_labels_info.append((tg_dout_pin, top_level.ports["pmos_multiplier_0_drain_E"], None)) + + #print(top_level.ports["pmos_multiplier_0_source_W"].name) + #top_level.pprint_ports() + + # Move everythin to position + for comp, prt, alignment in pins_labels_info: + alignment = ('c', 'b') if alignment is None else alignment + compref = align_comp_to_port(comp, prt, alignment=alignment) + #top_level.add(compref) + + return top_level #top_level.flatten() + +def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): + # To prepare all necessary cells to construct a transmission gate, i.e. + # 1) transmission gate + # 2) Inverter + tg = naive_tg_cell(pdk=pdk, flip_config={"degree": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length) + inv = reconfig_inv(pdk=pdk, component_name="gate_ctrl_inv", pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation="horizontal") + + # Instantiation of the essential cells + top_level = Component(name="tg_with_inv") + tg_ref = prec_ref_center(tg) + inv_ref = prec_ref_center(inv) + top_level.add(tg_ref) + top_level.add(inv_ref) + + # Adding the ports + top_level.add_ports(tg_ref.get_ports_list(), prefix="tg_") + top_level.add_ports(inv_ref.get_ports_list(), prefix="inv_") + + # Placement + mos_spacing = pdk.util_max_metal_seperation() + nwell_min_spacing = pdk.get_grule("nwell")["min_separation"] + inv_cell_width = inv_ref.xsize # or = evaluate_bbox(inv)[0] + tg_ref.movex(inv_cell_width + nwell_min_spacing) + + # Routing + #top_level << smart + #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG + #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"]) # "out" of the TG + return top_level #top_level.flatten() tg_with_inv(pdk=sky130, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15).show() From ecabeed291c7171c48ec30b94489a1145a62a1e1 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 10 Nov 2024 15:08:10 +0000 Subject: [PATCH 07/21] Complete routing of the TG w/ an inverter for controlling the gates of the TG's PMOS and NMOS Next step: to add the I/O ports for the upcoming LVS work --- .../transmission_gate_saltychip/inv_lib.py | 12 ++++++------ .../transmission_gate.py | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py index bd0f3eb87..6a1347ced 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py @@ -15,8 +15,8 @@ def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_w # Create a top level component top_level = Component(component_name) # To prepare one PMOS and one NMOS for the subsequent inverter cell construction - pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) - nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) + pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length) # Instantiation of above PMOS and NMOS under the top level pfet_ref = prec_ref_center(pfet) @@ -24,10 +24,6 @@ def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_w top_level.add(pfet_ref) top_level.add(nfet_ref) - # To add the ports - top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") - top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - # Placement (relative move) mos_spacing = pdk.util_max_metal_seperation() if(orientation=="horizontal"): @@ -41,4 +37,8 @@ def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_w top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_E"]) top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_gate_W"], nfet_ref.ports["multiplier_0_gate_W"]) + # To add the ports + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + return top_level diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index 043f12b9a..f9b1a4f6d 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -105,8 +105,8 @@ def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_ # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS # 2) NMOS - pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length) - nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length) + pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=nmos_width, length=nmos_length) # Placement and adding ports top_level = Component(name="TG") @@ -114,11 +114,6 @@ def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_ nfet_ref = prec_ref_center(nfet) top_level.add(pfet_ref) top_level.add(nfet_ref) - top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") - top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - #top_level.add_port( - # name="", center=[0, width / 2], width=width, orientation=180, layer=layer - #) # Placement mos_spacing = pdk.util_max_metal_seperation() @@ -135,6 +130,12 @@ def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_ top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_E"], nfet_ref.ports["multiplier_0_source_E"]) # "in" of the TG top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_drain_E"]) # "out" of the TG + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + #top_level.add_port( + # name="", center=[0, width / 2], width=width, orientation=180, layer=layer + #) + # Add pins and text labels for LVS pins_labels_info = list() # list that contains all port and component information # To define the layers @@ -190,7 +191,8 @@ def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length tg_ref.movex(inv_cell_width + nwell_min_spacing) # Routing - #top_level << smart + top_level << smart_route(pdk, inv_ref.ports["pmos_multiplier_0_drain_E"], tg_ref.ports["pmos_multiplier_0_gate_W"]) + top_level << smart_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_S"], tg_ref.ports["nmos_multiplier_0_gate_S"]) #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"]) # "out" of the TG From 929bf0b1ebb3607cb2ab7f43c010c1b785e3b44c Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 10 Nov 2024 15:22:12 +0000 Subject: [PATCH 08/21] Add the first draft of layout report and GDS w/o I/O port yet --- .../gds/tg_with_inv.gds | Bin 0 -> 60798 bytes .../report/figures/tg_with_inv.png | Bin 0 -> 107783 bytes .../transmission_gate.py | 9 ++++++++- 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/report/figures/tg_with_inv.png diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds new file mode 100644 index 0000000000000000000000000000000000000000..4f9d91f6cad27cd70607190ca75db6d98c2297ba GIT binary patch literal 60798 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 literal 0 HcmV?d00001 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/report/figures/tg_with_inv.png b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/report/figures/tg_with_inv.png new file mode 100644 index 0000000000000000000000000000000000000000..272497ec56d1f0211e67b506aff81e0176ea569f GIT binary patch literal 107783 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�!lwp|;0 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 Date: Wed, 13 Nov 2024 05:07:51 +0000 Subject: [PATCH 09/21] Add the external I/O ports for the transmission gate --- .../transmission_gate_saltychip/__init__.py | 2 + .../cell_config.py | 67 ++++++++++++++++++ .../transmission_gate_saltychip/eval.py | 40 +++++++++++ .../gds/tg_with_inv.gds | Bin 60798 -> 61684 bytes .../report/figures/tg_with_inv.png | Bin 107783 -> 99588 bytes .../transmission_gate.py | 22 +++--- 6 files changed, 117 insertions(+), 14 deletions(-) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py index 841af6bae..813e096a6 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py @@ -1,2 +1,4 @@ from glayout.flow.blocks.transmission_gate_saltychip.inv_lib import reconfig_inv from glayout.flow.blocks.transmission_gate_saltychip.transmission_gate import tg_with_inv +from glayout.flow.blocks.transmission_gate_saltychip.cell_config import add_port_lvs +from glayout.flow.blocks.transmission_gate_saltychip.eval import main diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py new file mode 100644 index 000000000..915d85688 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py @@ -0,0 +1,67 @@ +from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict +#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 gdsfactory import Component +from gdsfactory.components import rectangle +from glayout.flow.primitives.fet import pmos +from glayout.flow.primitives.fet import nmos +from glayout.flow.routing.straight_route import straight_route +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.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port + +def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ]) -> Component: + ''' + To add external I/O ports onto the cell for LVS + + @ args: + # pdk: please refer to the glayout library + # comp: please refer to the glayout library + # port_list: tuple[ dict[str, Union[float, str]] ] specifying new port's corresponding pin size, and + the name of new port and exiting port managed to align with in the given + component, e.g. + ( + { + "new_port": "drain_new", + "new_port_label": "drain_new_label", + "pin_width": 0.5, + "pin_height": 0.5, + "ref_port": "multiplier_0_drain_E" + }, + { + "new_port": "source_new", + "new_port_label": "source_new_label", + "pin_width": 1.5, + "pin_height": 1.5, + "ref_port": "multiplier_0_source_E" + } + ) + + # return: gdsfactory.Component + + @ Limitations: + # So far, only skywater130 process is validated + ''' + + # Add pins and text labels for LVS + pins_labels_info = list() # list that contains all port and component information + print(f"port_list: {port_list}") + for port in port_list: + # To get the layer's data type mapped to the GDS + ref_port_layer = comp.ports[ port["ref_port"] ].layer[0] # [0]: layer mapping, [1]: pin, drawing, label, net, etc. + + # To create the pin w/ label where the layer[1] is mapped to 16 + new_port_pin = rectangle(layer=(ref_port_layer, 16), size=(port["pin_width"], port["pin_height"]),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) + new_port_pin.add_label(text=port["new_port_label"], layer=(ref_port_layer, 5)) # layer[1]=5 mapped to the "label" datatype in the GDS + + # To align the new port with the designated port existing in the given component + alignment = ('c', 'b') + comp_ref = align_comp_to_port(new_port_pin, comp.ports[ port["ref_port"] ], alignment=alignment) + comp.add(comp_ref) + + return comp \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py new file mode 100644 index 000000000..66b15b77c --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -0,0 +1,40 @@ +import transmission_gate as tg +#from glayout.flow.pdk.gf180_mapped import gf180 +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 +import cell_config as config + +def main(): + tg_inst = tg.tg_with_inv(pdk=sky130, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15) + tg_inst = config.add_port_lvs( + pdk=sky130, + comp=tg_inst, + port_list=[ + { + "new_port": "tg_ctrl", + "new_port_label": "ctrl", + "pin_width": tg_inst.ports["inv_nmos_multiplier_0_gate_S"].width, + "pin_height": tg_inst.ports["inv_nmos_multiplier_0_gate_S"].width, + "ref_port": "inv_nmos_multiplier_0_gate_S" + }, + { + "new_port": "tg_din", + "new_port_label": "din", + "pin_width": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_source_S"].width, + "pin_height": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_source_S"].width, + "ref_port": "tg_pmos_multiplier_0_source_W" + }, + { + "new_port": "tg_dout", + "new_port_label": "dout", + "pin_width": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_drain_S"].width, + "pin_height": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_drain_S"].width, + "ref_port": "tg_nmos_multiplier_0_drain_N" + } + ] + ) + #tg_inst.flatten() + tg_inst.show() + tg_inst.write_gds("gds/tg_with_inv.gds") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds index 4f9d91f6cad27cd70607190ca75db6d98c2297ba..0e475572f10bbac3c96f480c5c96fe5822d2c0ea 100644 GIT binary patch delta 871 zcmex&i}}k#<_#Q-^;`@LB0_ATd3lMssVVV>DF!J?DQQUzJOa!N42)9$|NpCEU=d_s zU_n)9YGILev|=WLTNlCwDVS`y}V* z79>)ZlQ`H&`LvL5jI4; zKrP#>RTXHBB4J`|W@wz8Hd(7`%I3IjTUj^ryK@ zzz|iPY-=ktS@*5qYSzVF8d}BQsgYP8R4&uE}?85|E96Yv9@zvUy(>Fp&1Ma~pB2OfFAtOJWYSmFgnoy+9Dt-j1GEDQinQtj6O delta 229 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

JR`4TOjBPJVLk-qU=u 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 literal 107783 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�!lwp|;0 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 Date: Thu, 14 Nov 2024 10:45:59 +0800 Subject: [PATCH 10/21] Create a Colab notebook generating and displaying the transmission gate's GDSII image, according to the main layout work in "transmission_gate.py" and "eval.py". --- .../transmission_gate_saltychip/tg_gen.ipynb | 2326 +++++++++++++++++ 1 file changed, 2326 insertions(+) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb new file mode 100644 index 000000000..45d4fc14b --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb @@ -0,0 +1,2326 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "include_colab_link": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "id": "view-in-github", + "colab_type": "text" + }, + "source": [ + "\"Open" + ] + }, + { + "cell_type": "markdown", + "source": [ + "#Chipathon2024 SaltyChip Group\n", + "##テグさんのトランスミッションゲートをnotebbokで表示されるようにしてみた。\n", + "最初にOpenFASoCをクーロンして、sky130、gf180、gdsfactoryをインストールします。\n", + "micromambaを使ったバイナリ依存klayoutをインストールします。\n", + "\n", + "\n", + "\n", + "* Chipathon2024 GitHub:\n", + "https://github.com/sscs-ose/sscs-ose-chipathon.github.io\n", + "\n", + "\n", + "\n", + "\n", + "\n" + ], + "metadata": { + "id": "o2n-cd6kYdjt" + } + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + }, + "id": "2fBvSrYFYB1K", + "outputId": "90eb55c6-a4e2-42cf-966d-e79c278aaf28" + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Cloning into 'OpenFASOC'...\n", + "remote: Enumerating objects: 16501, done.\u001b[K\n", + "remote: Counting objects: 100% (3739/3739), done.\u001b[K\n", + "remote: Compressing objects: 100% (549/549), done.\u001b[K\n", + "remote: Total 16501 (delta 3311), reused 3398 (delta 3185), pack-reused 12762 (from 1)\u001b[K\n", + "Receiving objects: 100% (16501/16501), 410.32 MiB | 20.14 MiB/s, done.\n", + "Resolving deltas: 100% (10104/10104), done.\n", + "Updating files: 100% (1849/1849), done.\n", + "Collecting sky130\n", + " Downloading sky130-0.12.2-py3-none-any.whl.metadata (1.6 kB)\n", + "Collecting gdsfactory~=8.5.2 (from sky130)\n", + " Downloading gdsfactory-8.5.6-py3-none-any.whl.metadata (11 kB)\n", + "Collecting PySpice (from sky130)\n", + " Downloading PySpice-1.5-py2.py3-none-any.whl.metadata (15 kB)\n", + "Requirement already satisfied: jinja2<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.1.4)\n", + "Collecting loguru<1 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading loguru-0.7.2-py3-none-any.whl.metadata (23 kB)\n", + "Requirement already satisfied: matplotlib<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.8.0)\n", + "Requirement already satisfied: numpy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (1.26.4)\n", + "Collecting omegaconf<3 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading omegaconf-2.3.0-py3-none-any.whl.metadata (3.9 kB)\n", + "Requirement already satisfied: orjson<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.10.11)\n", + "Requirement already satisfied: pandas<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (2.2.2)\n", + "Collecting pydantic<2.9,>=2.8.2 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading pydantic-2.8.2-py3-none-any.whl.metadata (125 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m125.2/125.2 kB\u001b[0m \u001b[31m8.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hCollecting pydantic-settings<3 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading pydantic_settings-2.6.1-py3-none-any.whl.metadata (3.5 kB)\n", + "Collecting pydantic-extra-types<3 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading pydantic_extra_types-2.10.0-py3-none-any.whl.metadata (3.5 kB)\n", + "Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (6.0.2)\n", + "Collecting qrcode (from gdsfactory~=8.5.2->sky130)\n", + " Downloading qrcode-8.0-py3-none-any.whl.metadata (17 kB)\n", + "Collecting rectpack<1 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading rectpack-0.2.2.tar.gz (17 kB)\n", + " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: rich<14 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (13.9.4)\n", + "Requirement already satisfied: scipy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (1.13.1)\n", + "Requirement already satisfied: shapely<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (2.0.6)\n", + "Requirement already satisfied: toolz<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (0.12.1)\n", + "Collecting types-PyYAML (from gdsfactory~=8.5.2->sky130)\n", + " Downloading types_PyYAML-6.0.12.20240917-py3-none-any.whl.metadata (1.6 kB)\n", + "Requirement already satisfied: typer<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (0.13.0)\n", + "Collecting watchdog<5 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl.metadata (38 kB)\n", + "Collecting kfactory~=0.18.0 (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", + " Downloading kfactory-0.18.4-py3-none-any.whl.metadata (4.4 kB)\n", + "Collecting freetype-py (from gdsfactory~=8.5.2->sky130)\n", + " Downloading freetype_py-2.5.1-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.metadata (6.3 kB)\n", + "Collecting mapbox_earcut (from gdsfactory~=8.5.2->sky130)\n", + " Downloading mapbox_earcut-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.1 kB)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.4.2)\n", + "Requirement already satisfied: scikit-image in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (0.24.0)\n", + "Collecting trimesh<4.5,>=4.4.1 (from gdsfactory~=8.5.2->sky130)\n", + " Downloading trimesh-4.4.9-py3-none-any.whl.metadata (18 kB)\n", + "Requirement already satisfied: ipykernel in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (5.5.6)\n", + "Requirement already satisfied: cffi>=1.14 in /usr/local/lib/python3.10/dist-packages (from PySpice->sky130) (1.17.1)\n", + "Collecting ply>=3.11 (from PySpice->sky130)\n", + " Downloading ply-3.11-py2.py3-none-any.whl.metadata (844 bytes)\n", + "Requirement already satisfied: requests>=2.23 in /usr/local/lib/python3.10/dist-packages (from PySpice->sky130) (2.32.3)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi>=1.14->PySpice->sky130) (2.22)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2<4->gdsfactory~=8.5.2->sky130) (3.0.2)\n", + "Collecting aenum (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", + " Downloading aenum-3.1.15-py3-none-any.whl.metadata (3.7 kB)\n", + "Requirement already satisfied: cachetools>=5.2.0 in /usr/local/lib/python3.10/dist-packages (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (5.5.0)\n", + "Requirement already satisfied: gitpython in /usr/local/lib/python3.10/dist-packages (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.1.43)\n", + "Collecting klayout>=0.29.3 (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", + " Downloading klayout-0.29.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (782 bytes)\n", + "Collecting rectangle-packer (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", + " Downloading rectangle_packer-2.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.4 kB)\n", + "Collecting ruamel.yaml (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", + " Downloading ruamel.yaml-0.18.6-py3-none-any.whl.metadata (23 kB)\n", + "Requirement already satisfied: tomli in /usr/local/lib/python3.10/dist-packages (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.0.2)\n", + "\u001b[33mWARNING: kfactory 0.18.4 does not provide the extra 'git'\u001b[0m\u001b[33m\n", + "\u001b[0mRequirement already satisfied: ipython in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (7.34.0)\n", + "Requirement already satisfied: ipywidgets in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (7.7.1)\n", + "Requirement already satisfied: ipytree in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.2)\n", + "Requirement already satisfied: ipyevents in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.0.2)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (1.3.0)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (4.54.1)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (1.4.7)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (24.2)\n", + "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (11.0.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (3.2.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (2.8.2)\n", + "Collecting antlr4-python3-runtime==4.9.* (from omegaconf<3->gdsfactory~=8.5.2->sky130)\n", + " Downloading antlr4-python3-runtime-4.9.3.tar.gz (117 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m117.0/117.0 kB\u001b[0m \u001b[31m10.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory~=8.5.2->sky130) (2024.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory~=8.5.2->sky130) (2024.2)\n", + "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<2.9,>=2.8.2->gdsfactory~=8.5.2->sky130) (0.7.0)\n", + "Collecting pydantic-core==2.20.1 (from pydantic<2.9,>=2.8.2->gdsfactory~=8.5.2->sky130)\n", + " Downloading pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)\n", + "Requirement already satisfied: typing-extensions>=4.6.1 in /usr/local/lib/python3.10/dist-packages (from pydantic<2.9,>=2.8.2->gdsfactory~=8.5.2->sky130) (4.12.2)\n", + "Collecting python-dotenv>=0.21.0 (from pydantic-settings<3->gdsfactory~=8.5.2->sky130)\n", + " Downloading python_dotenv-1.0.1-py3-none-any.whl.metadata (23 kB)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (3.4.0)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (3.10)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (2.2.3)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (2024.8.30)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory~=8.5.2->sky130) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory~=8.5.2->sky130) (2.18.0)\n", + "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory~=8.5.2->sky130) (8.1.7)\n", + "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory~=8.5.2->sky130) (1.5.4)\n", + "Requirement already satisfied: ipython-genutils in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (0.2.0)\n", + "Requirement already satisfied: traitlets>=4.1.0 in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (5.7.1)\n", + "Requirement already satisfied: jupyter-client in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (6.1.12)\n", + "Requirement already satisfied: tornado>=4.2 in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (6.3.3)\n", + "Requirement already satisfied: imageio>=2.33 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory~=8.5.2->sky130) (2.36.0)\n", + "Requirement already satisfied: tifffile>=2022.8.12 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory~=8.5.2->sky130) (2024.9.20)\n", + "Requirement already satisfied: lazy-loader>=0.4 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory~=8.5.2->sky130) (0.4)\n", + "Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (75.1.0)\n", + "Collecting jedi>=0.16 (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", + " Downloading jedi-0.19.2-py2.py3-none-any.whl.metadata (22 kB)\n", + "Requirement already satisfied: decorator in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.4.2)\n", + "Requirement already satisfied: pickleshare in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.7.5)\n", + "Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.0.48)\n", + "Requirement already satisfied: backcall in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.0)\n", + "Requirement already satisfied: matplotlib-inline in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.1.7)\n", + "Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.9.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich<14->gdsfactory~=8.5.2->sky130) (0.1.2)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib<4->gdsfactory~=8.5.2->sky130) (1.16.0)\n", + "Requirement already satisfied: gitdb<5,>=4.0.1 in /usr/local/lib/python3.10/dist-packages (from gitpython->kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.0.11)\n", + "Requirement already satisfied: widgetsnbextension~=3.6.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.6.10)\n", + "Requirement already satisfied: jupyterlab-widgets>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.0.13)\n", + "Requirement already satisfied: jupyter-core>=4.6.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory~=8.5.2->sky130) (5.7.2)\n", + "Requirement already satisfied: pyzmq>=13 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory~=8.5.2->sky130) (24.0.1)\n", + "Collecting ruamel.yaml.clib>=0.2.7 (from ruamel.yaml->kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", + " Downloading ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.7 kB)\n", + "\u001b[33mWARNING: typer 0.13.0 does not provide the extra 'all'\u001b[0m\u001b[33m\n", + "\u001b[0mRequirement already satisfied: smmap<6,>=3.0.1 in /usr/local/lib/python3.10/dist-packages (from gitdb<5,>=4.0.1->gitpython->kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (5.0.1)\n", + "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /usr/local/lib/python3.10/dist-packages (from jedi>=0.16->ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.8.4)\n", + "Requirement already satisfied: platformdirs>=2.5 in /usr/local/lib/python3.10/dist-packages (from jupyter-core>=4.6.0->jupyter-client->ipykernel->gdsfactory~=8.5.2->sky130) (4.3.6)\n", + "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.10/dist-packages (from pexpect>4.3->ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.7.0)\n", + "Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/dist-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.13)\n", + "Requirement already satisfied: notebook>=4.4.1 in /usr/local/lib/python3.10/dist-packages (from widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (6.5.5)\n", + "Requirement already satisfied: argon2-cffi in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (23.1.0)\n", + "Requirement already satisfied: nbformat in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (5.10.4)\n", + "Requirement already satisfied: nbconvert>=5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (7.16.4)\n", + "Requirement already satisfied: nest-asyncio>=1.5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.6.0)\n", + "Requirement already satisfied: Send2Trash>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.8.3)\n", + "Requirement already satisfied: terminado>=0.8.3 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.18.1)\n", + "Requirement already satisfied: prometheus-client in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.21.0)\n", + "Requirement already satisfied: nbclassic>=0.4.7 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.1.0)\n", + "Requirement already satisfied: notebook-shim>=0.2.3 in /usr/local/lib/python3.10/dist-packages (from nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.4)\n", + "Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.12.3)\n", + "Requirement already satisfied: bleach!=5.0.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (6.2.0)\n", + "Requirement already satisfied: defusedxml in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.7.1)\n", + "Requirement already satisfied: jupyterlab-pygments in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.3.0)\n", + "Requirement already satisfied: mistune<4,>=2.0.3 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.0.2)\n", + "Requirement already satisfied: nbclient>=0.5.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.10.0)\n", + "Requirement already satisfied: pandocfilters>=1.4.1 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.5.1)\n", + "Requirement already satisfied: tinycss2 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.4.0)\n", + "Requirement already satisfied: fastjsonschema>=2.15 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.20.0)\n", + "Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.23.0)\n", + "Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.10/dist-packages (from argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (21.2.0)\n", + "Requirement already satisfied: webencodings in /usr/local/lib/python3.10/dist-packages (from bleach!=5.0.0->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.5.1)\n", + "Requirement already satisfied: attrs>=22.2.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (24.2.0)\n", + "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2024.10.1)\n", + "Requirement already satisfied: referencing>=0.28.4 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.35.1)\n", + "Requirement already satisfied: rpds-py>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.21.0)\n", + "Requirement already satisfied: jupyter-server<3,>=1.8 in /usr/local/lib/python3.10/dist-packages (from notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.24.0)\n", + "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/dist-packages (from beautifulsoup4->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.6)\n", + "Requirement already satisfied: anyio<4,>=3.1.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.7.1)\n", + "Requirement already satisfied: websocket-client in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.8.0)\n", + "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.3.1)\n", + "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.2.2)\n", + "Downloading sky130-0.12.2-py3-none-any.whl (38.2 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m38.2/38.2 MB\u001b[0m \u001b[31m10.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading gdsfactory-8.5.6-py3-none-any.whl (631 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m631.9/631.9 kB\u001b[0m \u001b[31m39.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading PySpice-1.5-py2.py3-none-any.whl (158 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m158.5/158.5 kB\u001b[0m \u001b[31m13.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading kfactory-0.18.4-py3-none-any.whl (147 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m147.2/147.2 kB\u001b[0m \u001b[31m12.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading loguru-0.7.2-py3-none-any.whl (62 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m62.5/62.5 kB\u001b[0m \u001b[31m5.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading omegaconf-2.3.0-py3-none-any.whl (79 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m79.5/79.5 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading ply-3.11-py2.py3-none-any.whl (49 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.6/49.6 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading pydantic-2.8.2-py3-none-any.whl (423 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m423.9/423.9 kB\u001b[0m \u001b[31m27.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.1/2.1 MB\u001b[0m \u001b[31m72.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading pydantic_extra_types-2.10.0-py3-none-any.whl (34 kB)\n", + "Downloading pydantic_settings-2.6.1-py3-none-any.whl (28 kB)\n", + "Downloading trimesh-4.4.9-py3-none-any.whl (700 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m700.1/700.1 kB\u001b[0m \u001b[31m42.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl (82 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m82.9/82.9 kB\u001b[0m \u001b[31m6.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading freetype_py-2.5.1-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.0 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.0/1.0 MB\u001b[0m \u001b[31m53.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading mapbox_earcut-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (110 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m111.0/111.0 kB\u001b[0m \u001b[31m9.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading qrcode-8.0-py3-none-any.whl (45 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m45.7/45.7 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading types_PyYAML-6.0.12.20240917-py3-none-any.whl (15 kB)\n", + "Downloading klayout-0.29.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (23.6 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m23.6/23.6 MB\u001b[0m \u001b[31m70.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)\n", + "Downloading aenum-3.1.15-py3-none-any.whl (137 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m137.6/137.6 kB\u001b[0m \u001b[31m11.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading rectangle_packer-2.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (305 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m305.6/305.6 kB\u001b[0m \u001b[31m22.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading ruamel.yaml-0.18.6-py3-none-any.whl (117 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m117.8/117.8 kB\u001b[0m \u001b[31m9.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading jedi-0.19.2-py2.py3-none-any.whl (1.6 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m54.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (722 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m722.2/722.2 kB\u001b[0m \u001b[31m41.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hBuilding wheels for collected packages: antlr4-python3-runtime, rectpack\n", + " Building wheel for antlr4-python3-runtime (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for antlr4-python3-runtime: filename=antlr4_python3_runtime-4.9.3-py3-none-any.whl size=144555 sha256=d1fc8d45a104ab2b00078f5e1b20ce2486c797f67872640d8e1b3fd83820ae66\n", + " Stored in directory: /root/.cache/pip/wheels/12/93/dd/1f6a127edc45659556564c5730f6d4e300888f4bca2d4c5a88\n", + " Building wheel for rectpack (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for rectpack: filename=rectpack-0.2.2-py3-none-any.whl size=19333 sha256=bcb65018a8633671446a0dfe8d0cf57c940086a5715d86235221f459493048b8\n", + " Stored in directory: /root/.cache/pip/wheels/e9/ea/e9/cd0237c0ccb9cb7312bb94cc023689592c4f07e4f3b1b9dd00\n", + "Successfully built antlr4-python3-runtime rectpack\n", + "Installing collected packages: rectpack, rectangle-packer, ply, klayout, antlr4-python3-runtime, aenum, watchdog, types-PyYAML, trimesh, ruamel.yaml.clib, qrcode, python-dotenv, pydantic-core, omegaconf, mapbox_earcut, loguru, jedi, freetype-py, ruamel.yaml, pydantic, PySpice, pydantic-settings, pydantic-extra-types, kfactory, gdsfactory, sky130\n", + " Attempting uninstall: pydantic-core\n", + " Found existing installation: pydantic_core 2.23.4\n", + " Uninstalling pydantic_core-2.23.4:\n", + " Successfully uninstalled pydantic_core-2.23.4\n", + " Attempting uninstall: pydantic\n", + " Found existing installation: pydantic 2.9.2\n", + " Uninstalling pydantic-2.9.2:\n", + " Successfully uninstalled pydantic-2.9.2\n", + "Successfully installed PySpice-1.5 aenum-3.1.15 antlr4-python3-runtime-4.9.3 freetype-py-2.5.1 gdsfactory-8.5.6 jedi-0.19.2 kfactory-0.18.4 klayout-0.29.8 loguru-0.7.2 mapbox_earcut-1.0.2 omegaconf-2.3.0 ply-3.11 pydantic-2.8.2 pydantic-core-2.20.1 pydantic-extra-types-2.10.0 pydantic-settings-2.6.1 python-dotenv-1.0.1 qrcode-8.0 rectangle-packer-2.0.2 rectpack-0.2.2 ruamel.yaml-0.18.6 ruamel.yaml.clib-0.2.12 sky130-0.12.2 trimesh-4.4.9 types-PyYAML-6.0.12.20240917 watchdog-4.0.2\n" + ] + }, + { + "output_type": "display_data", + "data": { + "application/vnd.colab-display-data+json": { + "pip_warning": { + "packages": [ + "pydevd_plugins" + ] + }, + "id": "85f88f72a59f488eb4b4198dbc9cc332" + } + }, + "metadata": {} + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Collecting gf180\n", + " Downloading gf180-0.1.0-py3-none-any.whl.metadata (2.1 kB)\n", + "Collecting prettyprinttree\n", + " Downloading PrettyPrintTree-2.0.1-py3-none-any.whl.metadata (9.6 kB)\n", + "Collecting svgutils\n", + " Downloading svgutils-0.3.4-py3-none-any.whl.metadata (1.1 kB)\n", + "Collecting gdsfactory<7.17,>=7.16.0 (from gf180)\n", + " Downloading gdsfactory-7.16.0-py3-none-any.whl.metadata (11 kB)\n", + "Collecting colorama (from prettyprinttree)\n", + " Downloading colorama-0.4.6-py2.py3-none-any.whl.metadata (17 kB)\n", + "Collecting cmd2 (from prettyprinttree)\n", + " Downloading cmd2-2.5.5-py3-none-any.whl.metadata (13 kB)\n", + "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from svgutils) (5.3.0)\n", + "Collecting flatdict (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading flatdict-4.0.1.tar.gz (8.3 kB)\n", + " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + "Collecting gdstk<0.10,>=0.9.49 (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading gdstk-0.9.57-cp310-cp310-manylinux_2_28_x86_64.whl.metadata (8.7 kB)\n", + "Requirement already satisfied: jinja2<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.1.4)\n", + "Requirement already satisfied: loguru<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.7.2)\n", + "Requirement already satisfied: matplotlib<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.8.0)\n", + "Requirement already satisfied: numpy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (1.26.4)\n", + "Requirement already satisfied: omegaconf<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.3.0)\n", + "Requirement already satisfied: orjson<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.10.11)\n", + "Requirement already satisfied: pandas<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.2.2)\n", + "Collecting pydantic<2.7,>=2 (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading pydantic-2.6.4-py3-none-any.whl.metadata (85 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m85.1/85.1 kB\u001b[0m \u001b[31m4.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hRequirement already satisfied: pydantic-settings<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.6.1)\n", + "Requirement already satisfied: pydantic-extra-types<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.10.0)\n", + "Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (6.0.2)\n", + "Requirement already satisfied: qrcode in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (8.0)\n", + "Requirement already satisfied: rectpack<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.2.2)\n", + "Requirement already satisfied: rich<14 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (13.9.4)\n", + "Requirement already satisfied: scipy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (1.13.1)\n", + "Requirement already satisfied: shapely<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.0.6)\n", + "Requirement already satisfied: toolz<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.12.1)\n", + "Requirement already satisfied: types-PyYAML in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (6.0.12.20240917)\n", + "Requirement already satisfied: typer<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.13.0)\n", + "Requirement already satisfied: watchdog<5 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (4.0.2)\n", + "Collecting kfactory<0.12,>=0.9.1 (from kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading kfactory-0.11.4-py3-none-any.whl.metadata (4.5 kB)\n", + "Requirement already satisfied: freetype-py in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.5.1)\n", + "Requirement already satisfied: mapbox_earcut in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (1.0.2)\n", + "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.4.2)\n", + "Collecting pyglet<2 (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading pyglet-1.5.29-py3-none-any.whl.metadata (7.6 kB)\n", + "Requirement already satisfied: scikit-image in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.24.0)\n", + "Collecting trimesh<4.2,>=4 (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading trimesh-4.1.8-py3-none-any.whl.metadata (18 kB)\n", + "Collecting ipycytoscape (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading ipycytoscape-1.3.3-py2.py3-none-any.whl.metadata (7.5 kB)\n", + "Requirement already satisfied: ipyevents in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.0.2)\n", + "Requirement already satisfied: ipykernel in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (5.5.6)\n", + "Collecting ipympl (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading ipympl-0.9.4-py3-none-any.whl.metadata (8.7 kB)\n", + "Requirement already satisfied: ipytree in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.2.2)\n", + "Requirement already satisfied: ipywidgets in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (7.7.1)\n", + "Requirement already satisfied: pyperclip in /usr/local/lib/python3.10/dist-packages (from cmd2->prettyprinttree) (1.9.0)\n", + "Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/dist-packages (from cmd2->prettyprinttree) (0.2.13)\n", + "Requirement already satisfied: typing_extensions in /usr/local/lib/python3.10/dist-packages (from gdstk<0.10,>=0.9.49->gdsfactory<7.17,>=7.16.0->gf180) (4.12.2)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2<4->gdsfactory<7.17,>=7.16.0->gf180) (3.0.2)\n", + "Requirement already satisfied: klayout>=0.28.17 in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.29.8)\n", + "Requirement already satisfied: ruamel.yaml in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.18.6)\n", + "Requirement already satisfied: cachetools>=5.2.0 in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (5.5.0)\n", + "Requirement already satisfied: tomli in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2.0.2)\n", + "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2.32.3)\n", + "Requirement already satisfied: aenum in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.1.15)\n", + "Requirement already satisfied: ipython in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (7.34.0)\n", + "Requirement already satisfied: gitpython in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.1.43)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (1.3.0)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (4.54.1)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (1.4.7)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (24.2)\n", + "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (11.0.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (3.2.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (2.8.2)\n", + "Requirement already satisfied: antlr4-python3-runtime==4.9.* in /usr/local/lib/python3.10/dist-packages (from omegaconf<3->gdsfactory<7.17,>=7.16.0->gf180) (4.9.3)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory<7.17,>=7.16.0->gf180) (2024.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory<7.17,>=7.16.0->gf180) (2024.2)\n", + "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<2.7,>=2->gdsfactory<7.17,>=7.16.0->gf180) (0.7.0)\n", + "Collecting pydantic-core==2.16.3 (from pydantic<2.7,>=2->gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.5 kB)\n", + "INFO: pip is looking at multiple versions of pydantic-settings to determine which version is compatible with other requirements. This could take a while.\n", + "Collecting pydantic-settings<3 (from gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading pydantic_settings-2.6.0-py3-none-any.whl.metadata (3.5 kB)\n", + " Downloading pydantic_settings-2.5.2-py3-none-any.whl.metadata (3.5 kB)\n", + " Downloading pydantic_settings-2.5.1-py3-none-any.whl.metadata (3.5 kB)\n", + " Downloading pydantic_settings-2.5.0-py3-none-any.whl.metadata (3.5 kB)\n", + " Downloading pydantic_settings-2.4.0-py3-none-any.whl.metadata (3.5 kB)\n", + " Downloading pydantic_settings-2.3.4-py3-none-any.whl.metadata (3.3 kB)\n", + " Downloading pydantic_settings-2.3.3-py3-none-any.whl.metadata (3.3 kB)\n", + "INFO: pip is still looking at multiple versions of pydantic-settings to determine which version is compatible with other requirements. This could take a while.\n", + " Downloading pydantic_settings-2.3.2-py3-none-any.whl.metadata (3.3 kB)\n", + " Downloading pydantic_settings-2.3.1-py3-none-any.whl.metadata (3.3 kB)\n", + " Downloading pydantic_settings-2.3.0-py3-none-any.whl.metadata (3.3 kB)\n", + " Downloading pydantic_settings-2.2.1-py3-none-any.whl.metadata (3.1 kB)\n", + "Requirement already satisfied: python-dotenv>=0.21.0 in /usr/local/lib/python3.10/dist-packages (from pydantic-settings<3->gdsfactory<7.17,>=7.16.0->gf180) (1.0.1)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory<7.17,>=7.16.0->gf180) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory<7.17,>=7.16.0->gf180) (2.18.0)\n", + "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory<7.17,>=7.16.0->gf180) (8.1.7)\n", + "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory<7.17,>=7.16.0->gf180) (1.5.4)\n", + "Collecting spectate>=1.0.0 (from ipycytoscape->gdsfactory<7.17,>=7.16.0->gf180)\n", + " Downloading spectate-1.0.1-py2.py3-none-any.whl.metadata (2.2 kB)\n", + "Requirement already satisfied: ipython-genutils~=0.2.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.2.0)\n", + "Requirement already satisfied: traitlets>=4.3.1 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (5.7.1)\n", + "Requirement already satisfied: widgetsnbextension~=3.6.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.6.10)\n", + "Requirement already satisfied: jupyterlab-widgets>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.0.13)\n", + "Requirement already satisfied: jupyter-client in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (6.1.12)\n", + "Requirement already satisfied: tornado>=4.2 in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (6.3.3)\n", + "Requirement already satisfied: imageio>=2.33 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory<7.17,>=7.16.0->gf180) (2.36.0)\n", + "Requirement already satisfied: tifffile>=2022.8.12 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory<7.17,>=7.16.0->gf180) (2024.9.20)\n", + "Requirement already satisfied: lazy-loader>=0.4 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory<7.17,>=7.16.0->gf180) (0.4)\n", + "Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (75.1.0)\n", + "Requirement already satisfied: jedi>=0.16 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.19.2)\n", + "Requirement already satisfied: decorator in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (4.4.2)\n", + "Requirement already satisfied: pickleshare in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.7.5)\n", + "Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.0.48)\n", + "Requirement already satisfied: backcall in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.2.0)\n", + "Requirement already satisfied: matplotlib-inline in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.1.7)\n", + "Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (4.9.0)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich<14->gdsfactory<7.17,>=7.16.0->gf180) (0.1.2)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (1.16.0)\n", + "Requirement already satisfied: notebook>=4.4.1 in /usr/local/lib/python3.10/dist-packages (from widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (6.5.5)\n", + "Requirement already satisfied: gitdb<5,>=4.0.1 in /usr/local/lib/python3.10/dist-packages (from gitpython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (4.0.11)\n", + "Requirement already satisfied: jupyter-core>=4.6.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (5.7.2)\n", + "Requirement already satisfied: pyzmq>=13 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (24.0.1)\n", + "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.4.0)\n", + "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.10)\n", + "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2.2.3)\n", + "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2024.8.30)\n", + "Requirement already satisfied: ruamel.yaml.clib>=0.2.7 in /usr/local/lib/python3.10/dist-packages (from ruamel.yaml->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.2.12)\n", + "\u001b[33mWARNING: typer 0.13.0 does not provide the extra 'all'\u001b[0m\u001b[33m\n", + "\u001b[0mRequirement already satisfied: smmap<6,>=3.0.1 in /usr/local/lib/python3.10/dist-packages (from gitdb<5,>=4.0.1->gitpython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (5.0.1)\n", + "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /usr/local/lib/python3.10/dist-packages (from jedi>=0.16->ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.8.4)\n", + "Requirement already satisfied: platformdirs>=2.5 in /usr/local/lib/python3.10/dist-packages (from jupyter-core>=4.6.0->jupyter-client->ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (4.3.6)\n", + "Requirement already satisfied: argon2-cffi in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (23.1.0)\n", + "Requirement already satisfied: nbformat in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (5.10.4)\n", + "Requirement already satisfied: nbconvert>=5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (7.16.4)\n", + "Requirement already satisfied: nest-asyncio>=1.5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.6.0)\n", + "Requirement already satisfied: Send2Trash>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.8.3)\n", + "Requirement already satisfied: terminado>=0.8.3 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.18.1)\n", + "Requirement already satisfied: prometheus-client in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.21.0)\n", + "Requirement already satisfied: nbclassic>=0.4.7 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.1.0)\n", + "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.10/dist-packages (from pexpect>4.3->ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.7.0)\n", + "Requirement already satisfied: notebook-shim>=0.2.3 in /usr/local/lib/python3.10/dist-packages (from nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.2.4)\n", + "Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (4.12.3)\n", + "Requirement already satisfied: bleach!=5.0.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (6.2.0)\n", + "Requirement already satisfied: defusedxml in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.7.1)\n", + "Requirement already satisfied: jupyterlab-pygments in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.3.0)\n", + "Requirement already satisfied: mistune<4,>=2.0.3 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.0.2)\n", + "Requirement already satisfied: nbclient>=0.5.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.10.0)\n", + "Requirement already satisfied: pandocfilters>=1.4.1 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.5.1)\n", + "Requirement already satisfied: tinycss2 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.4.0)\n", + "Requirement already satisfied: fastjsonschema>=2.15 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2.20.0)\n", + "Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (4.23.0)\n", + "Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.10/dist-packages (from argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (21.2.0)\n", + "Requirement already satisfied: webencodings in /usr/local/lib/python3.10/dist-packages (from bleach!=5.0.0->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.5.1)\n", + "Requirement already satisfied: attrs>=22.2.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (24.2.0)\n", + "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2024.10.1)\n", + "Requirement already satisfied: referencing>=0.28.4 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.35.1)\n", + "Requirement already satisfied: rpds-py>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.21.0)\n", + "Requirement already satisfied: jupyter-server<3,>=1.8 in /usr/local/lib/python3.10/dist-packages (from notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.24.0)\n", + "Requirement already satisfied: cffi>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from argon2-cffi-bindings->argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.17.1)\n", + "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/dist-packages (from beautifulsoup4->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2.6)\n", + "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2.22)\n", + "Requirement already satisfied: anyio<4,>=3.1.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.7.1)\n", + "Requirement already satisfied: websocket-client in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.8.0)\n", + "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.3.1)\n", + "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.2.2)\n", + "Downloading gf180-0.1.0-py3-none-any.whl (135 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m135.6/135.6 kB\u001b[0m \u001b[31m8.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading PrettyPrintTree-2.0.1-py3-none-any.whl (14 kB)\n", + "Downloading svgutils-0.3.4-py3-none-any.whl (10 kB)\n", + "Downloading gdsfactory-7.16.0-py3-none-any.whl (834 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m834.2/834.2 kB\u001b[0m \u001b[31m33.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading cmd2-2.5.5-py3-none-any.whl (151 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m151.3/151.3 kB\u001b[0m \u001b[31m12.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n", + "Downloading gdstk-0.9.57-cp310-cp310-manylinux_2_28_x86_64.whl (533 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m533.9/533.9 kB\u001b[0m \u001b[31m35.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading kfactory-0.11.4-py3-none-any.whl (114 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m114.7/114.7 kB\u001b[0m \u001b[31m6.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading pydantic-2.6.4-py3-none-any.whl (394 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m394.9/394.9 kB\u001b[0m \u001b[31m27.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.2 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.2/2.2 MB\u001b[0m \u001b[31m70.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading pydantic_settings-2.2.1-py3-none-any.whl (13 kB)\n", + "Downloading pyglet-1.5.29-py3-none-any.whl (1.1 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.1/1.1 MB\u001b[0m \u001b[31m51.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading trimesh-4.1.8-py3-none-any.whl (690 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m690.6/690.6 kB\u001b[0m \u001b[31m42.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading ipycytoscape-1.3.3-py2.py3-none-any.whl (3.6 MB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.6/3.6 MB\u001b[0m \u001b[31m83.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading ipympl-0.9.4-py3-none-any.whl (516 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m516.3/516.3 kB\u001b[0m \u001b[31m32.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hDownloading spectate-1.0.1-py2.py3-none-any.whl (11 kB)\n", + "Building wheels for collected packages: flatdict\n", + " Building wheel for flatdict (setup.py) ... \u001b[?25l\u001b[?25hdone\n", + " Created wheel for flatdict: filename=flatdict-4.0.1-py3-none-any.whl size=6928 sha256=cbe7b9ecdeb813ed4b936db444d4d7b1e3115b3811fed30a7561ac5da3fd548a\n", + " Stored in directory: /root/.cache/pip/wheels/71/12/62/88c5bf37619c2d7481eedb8abd0dde6674e88dce45a7805a6f\n", + "Successfully built flatdict\n", + "Installing collected packages: pyglet, flatdict, trimesh, svgutils, spectate, pydantic-core, gdstk, colorama, cmd2, pydantic, prettyprinttree, pydantic-settings, kfactory, ipympl, ipycytoscape, gdsfactory, gf180\n", + " Attempting uninstall: trimesh\n", + " Found existing installation: trimesh 4.4.9\n", + " Uninstalling trimesh-4.4.9:\n", + " Successfully uninstalled trimesh-4.4.9\n", + " Attempting uninstall: pydantic-core\n", + " Found existing installation: pydantic_core 2.20.1\n", + " Uninstalling pydantic_core-2.20.1:\n", + " Successfully uninstalled pydantic_core-2.20.1\n", + " Attempting uninstall: pydantic\n", + " Found existing installation: pydantic 2.8.2\n", + " Uninstalling pydantic-2.8.2:\n", + " Successfully uninstalled pydantic-2.8.2\n", + " Attempting uninstall: pydantic-settings\n", + " Found existing installation: pydantic-settings 2.6.1\n", + " Uninstalling pydantic-settings-2.6.1:\n", + " Successfully uninstalled pydantic-settings-2.6.1\n", + " Attempting uninstall: kfactory\n", + " Found existing installation: kfactory 0.18.4\n", + " Uninstalling kfactory-0.18.4:\n", + " Successfully uninstalled kfactory-0.18.4\n", + " Attempting uninstall: gdsfactory\n", + " Found existing installation: gdsfactory 8.5.6\n", + " Uninstalling gdsfactory-8.5.6:\n", + " Successfully uninstalled gdsfactory-8.5.6\n", + "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", + "albumentations 1.4.20 requires pydantic>=2.7.0, but you have pydantic 2.6.4 which is incompatible.\n", + "langchain 0.3.7 requires pydantic<3.0.0,>=2.7.4, but you have pydantic 2.6.4 which is incompatible.\n", + "sky130 0.12.2 requires gdsfactory~=8.5.2, but you have gdsfactory 7.16.0 which is incompatible.\u001b[0m\u001b[31m\n", + "\u001b[0mSuccessfully installed cmd2-2.5.5 colorama-0.4.6 flatdict-4.0.1 gdsfactory-7.16.0 gdstk-0.9.57 gf180-0.1.0 ipycytoscape-1.3.3 ipympl-0.9.4 kfactory-0.11.4 prettyprinttree-2.0.1 pydantic-2.6.4 pydantic-core-2.16.3 pydantic-settings-2.2.1 pyglet-1.5.29 spectate-1.0.1 svgutils-0.3.4 trimesh-4.1.8\n", + "Collecting gdsfactory==7.7.0\n", + " Downloading gdsfactory-7.7.0-py3-none-any.whl.metadata (10 kB)\n", + "Requirement already satisfied: flatdict in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (4.0.1)\n", + "Requirement already satisfied: gdstk<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.9.57)\n", + "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (3.1.4)\n", + "Requirement already satisfied: loguru<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.7.2)\n", + "Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (3.8.0)\n", + "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (1.26.4)\n", + "Requirement already satisfied: omegaconf<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.3.0)\n", + "Requirement already satisfied: orjson in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (3.10.11)\n", + "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.2.2)\n", + "Requirement already satisfied: pydantic<3,>=2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.6.4)\n", + "Requirement already satisfied: pydantic-settings in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.2.1)\n", + "Requirement already satisfied: pydantic-extra-types in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.10.0)\n", + "Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (6.0.2)\n", + "Requirement already satisfied: qrcode in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (8.0)\n", + "Requirement already satisfied: rectpack in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.2.2)\n", + "Requirement already satisfied: rich in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (13.9.4)\n", + "Requirement already satisfied: scipy in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (1.13.1)\n", + "Requirement already satisfied: shapely<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.0.6)\n", + "Requirement already satisfied: toolz in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.12.1)\n", + "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (4.66.6)\n", + "Requirement already satisfied: types-PyYAML in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (6.0.12.20240917)\n", + "Requirement already satisfied: typer in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.13.0)\n", + "Requirement already satisfied: watchdog in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (4.0.2)\n", + "Requirement already satisfied: typing_extensions in /usr/local/lib/python3.10/dist-packages (from gdstk<1->gdsfactory==7.7.0) (4.12.2)\n", + "Requirement already satisfied: antlr4-python3-runtime==4.9.* in /usr/local/lib/python3.10/dist-packages (from omegaconf<3->gdsfactory==7.7.0) (4.9.3)\n", + "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=2->gdsfactory==7.7.0) (0.7.0)\n", + "Requirement already satisfied: pydantic-core==2.16.3 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=2->gdsfactory==7.7.0) (2.16.3)\n", + "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->gdsfactory==7.7.0) (3.0.2)\n", + "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (1.3.0)\n", + "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (0.12.1)\n", + "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (4.54.1)\n", + "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (1.4.7)\n", + "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (24.2)\n", + "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (11.0.0)\n", + "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (3.2.0)\n", + "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (2.8.2)\n", + "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->gdsfactory==7.7.0) (2024.2)\n", + "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas->gdsfactory==7.7.0) (2024.2)\n", + "Requirement already satisfied: python-dotenv>=0.21.0 in /usr/local/lib/python3.10/dist-packages (from pydantic-settings->gdsfactory==7.7.0) (1.0.1)\n", + "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich->gdsfactory==7.7.0) (3.0.0)\n", + "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich->gdsfactory==7.7.0) (2.18.0)\n", + "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer->gdsfactory==7.7.0) (8.1.7)\n", + "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer->gdsfactory==7.7.0) (1.5.4)\n", + "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich->gdsfactory==7.7.0) (0.1.2)\n", + "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib->gdsfactory==7.7.0) (1.16.0)\n", + "Downloading gdsfactory-7.7.0-py3-none-any.whl (801 kB)\n", + "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m801.2/801.2 kB\u001b[0m \u001b[31m16.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", + "\u001b[?25hInstalling collected packages: gdsfactory\n", + " Attempting uninstall: gdsfactory\n", + " Found existing installation: gdsfactory 7.16.0\n", + " Uninstalling gdsfactory-7.16.0:\n", + " Successfully uninstalled gdsfactory-7.16.0\n", + "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", + "gf180 0.1.0 requires gdsfactory<7.17,>=7.16.0, but you have gdsfactory 7.7.0 which is incompatible.\n", + "sky130 0.12.2 requires gdsfactory~=8.5.2, but you have gdsfactory 7.7.0 which is incompatible.\u001b[0m\u001b[31m\n", + "\u001b[0mSuccessfully installed gdsfactory-7.7.0\n", + "bin/micromamba\n", + "env: CONDA_PREFIX=/content/conda-env\n", + "Empty environment created at prefix: /content/conda-env\n", + "\u001b[?25l\u001b[2K\u001b[0G[+] 0.0s\n", + "\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.1s\n", + "litex-hub/linux-64.. ⣾ \n", + "litex-hub/noarch (.. ⣾ \n", + "main/linux-64 (che.. ⣾ \n", + "main/noarch (check.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.2s\n", + "litex-hub/linux-64.. ⣾ \n", + "litex-hub/noarch (.. ⣾ \n", + "main/linux-64 (che.. ⣾ \n", + "main/noarch (check.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.3s\n", + "litex-hub/linux-64.. ⣾ \n", + "litex-hub/noarch (.. ⣾ \n", + "main/linux-64 (che.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.4s\n", + "litex-hub/noarch (.. ⣾ \n", + "main/linux-64 (che.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.5s\n", + "litex-hub/noarch (.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[0G\u001b[?25h\u001b[?25l\u001b[2K\u001b[0G[+] 0.0s\n", + "\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.1s\n", + "litex-hub/linux-64 | \n", + "litex-hub/noarch ⣾ \n", + "main/linux-64 ⣾ \n", + "main/noarch | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.2s\n", + "litex-hub/linux-64 | \n", + "litex-hub/noarch ⣾ \n", + "main/linux-64 ⣾ \n", + "main/noarch | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.3s\n", + "litex-hub/linux-64 | \n", + "litex-hub/noarch ⣾ \n", + "main/linux-64 ⣾ \n", + "main/noarch | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glitex-hub/noarch \n", + "[+] 0.4s\n", + "litex-hub/linux-64 | \n", + "main/linux-64 ⣾ \n", + "main/noarch 3%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.5s\n", + "litex-hub/linux-64 | \n", + "main/linux-64 2%\n", + "main/noarch 15%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.6s\n", + "litex-hub/linux-64 | \n", + "main/linux-64 9%\n", + "main/noarch 36%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gmain/noarch \n", + "[+] 0.7s\n", + "litex-hub/linux-64 | \n", + "main/linux-64 11%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.8s\n", + "litex-hub/linux-64 3%\n", + "main/linux-64 42%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.9s\n", + "litex-hub/linux-64 27%\n", + "main/linux-64 83%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gmain/linux-64 \n", + "[+] 1.0s\n", + "litex-hub/linux-64 57%\u001b[2K\u001b[1A\u001b[2K\u001b[0Glitex-hub/linux-64 \n", + "\u001b[?25h\n", + "\u001b[31m\u001b[1merror libmamba\u001b[m Could not lock non-existing path '/root/.mamba/pkgs'\n", + "\n", + "Transaction\n", + "\n", + " Prefix: /content/conda-env\n", + "\n", + " Updating specs:\n", + "\n", + " - klayout\n", + "\n", + "\n", + " Package Version Build Channel Size\n", + "─────────────────────────────────────────────────────────────────────────────────────────\n", + " Install:\n", + "─────────────────────────────────────────────────────────────────────────────────────────\n", + "\n", + " \u001b[32m+ _libgcc_mutex \u001b[0m 0.1 main main 3kB\n", + " \u001b[32m+ _openmp_mutex \u001b[0m 5.1 1_gnu main 21kB\n", + " \u001b[32m+ bzip2 \u001b[0m 1.0.8 h5eee18b_6 main 428kB\n", + " \u001b[32m+ c-ares \u001b[0m 1.19.1 h5eee18b_0 main 116kB\n", + " \u001b[32m+ ca-certificates \u001b[0m 2024.9.24 h06a4308_0 main 140kB\n", + " \u001b[32m+ certifi \u001b[0m 2022.12.7 py37h06a4308_0 main 155kB\n", + " \u001b[32m+ curl \u001b[0m 8.2.1 h37d81fd_0 main 89kB\n", + " \u001b[32m+ dbus \u001b[0m 1.13.18 hb2f20db_0 main 600kB\n", + " \u001b[32m+ expat \u001b[0m 2.6.3 h6a678d5_0 main 201kB\n", + " \u001b[32m+ fontconfig \u001b[0m 2.13.0 h9420a91_0 main 298kB\n", + " \u001b[32m+ freetype \u001b[0m 2.12.1 h4a9f257_0 main 972kB\n", + " \u001b[32m+ glib \u001b[0m 2.78.4 h6a678d5_0 main 499kB\n", + " \u001b[32m+ glib-tools \u001b[0m 2.78.4 h6a678d5_0 main 113kB\n", + " \u001b[32m+ gmp \u001b[0m 6.2.1 h295c915_3 main 822kB\n", + " \u001b[32m+ gst-plugins-base\u001b[0m 1.14.1 h6a678d5_1 main 2MB\n", + " \u001b[32m+ gstreamer \u001b[0m 1.14.1 h5eee18b_1 main 2MB\n", + " \u001b[32m+ icu \u001b[0m 58.2 he6710b0_3 main 24MB\n", + " \u001b[32m+ jpeg \u001b[0m 9e h5eee18b_3 main 284kB\n", + " \u001b[32m+ klayout \u001b[0m 0.28.17_212_gfa14afbbf 20240223_100318_py37 litex-hub 27MB\n", + " \u001b[32m+ krb5 \u001b[0m 1.20.1 h568e23c_1 main 1MB\n", + " \u001b[32m+ ld_impl_linux-64\u001b[0m 2.40 h12ee557_0 main 723kB\n", + " \u001b[32m+ libcurl \u001b[0m 8.2.1 h91b91d3_0 main 386kB\n", + " \u001b[32m+ libedit \u001b[0m 3.1.20230828 h5eee18b_0 main 196kB\n", + " \u001b[32m+ libev \u001b[0m 4.33 h7f8727e_1 main 109kB\n", + " \u001b[32m+ libffi \u001b[0m 3.4.4 h6a678d5_1 main 154kB\n", + " \u001b[32m+ libgcc-ng \u001b[0m 11.2.0 h1234567_1 main 9MB\n", + " \u001b[32m+ libgit2 \u001b[0m 1.6.4 ha637b67_0 main 1MB\n", + " \u001b[32m+ libglib \u001b[0m 2.78.4 hdc74915_0 main 2MB\n", + " \u001b[32m+ libgomp \u001b[0m 11.2.0 h1234567_1 main 573kB\n", + " \u001b[32m+ libiconv \u001b[0m 1.16 h5eee18b_3 main 1MB\n", + " \u001b[32m+ libnghttp2 \u001b[0m 1.52.0 ha637b67_1 main 717kB\n", + " \u001b[32m+ libpng \u001b[0m 1.6.39 h5eee18b_0 main 363kB\n", + " \u001b[32m+ libssh2 \u001b[0m 1.10.0 h37d81fd_2 main 312kB\n", + " \u001b[32m+ libstdcxx-ng \u001b[0m 11.2.0 h1234567_1 main 6MB\n", + " \u001b[32m+ libuuid \u001b[0m 1.41.5 h5eee18b_0 main 29kB\n", + " \u001b[32m+ libxcb \u001b[0m 1.15 h7f8727e_0 main 623kB\n", + " \u001b[32m+ libxml2 \u001b[0m 2.9.9 20220706_155948 litex-hub 1MB\n", + " \u001b[32m+ ncurses \u001b[0m 6.4 h6a678d5_0 main 1MB\n", + " \u001b[32m+ openssl \u001b[0m 1.1.1w h7f8727e_0 main 4MB\n", + " \u001b[32m+ pcre2 \u001b[0m 10.42 hebb0a14_1 main 3MB\n", + " \u001b[32m+ pip \u001b[0m 22.3.1 py37h06a4308_0 main 3MB\n", + " \u001b[32m+ python \u001b[0m 3.7.16 h7a1cb2a_0 main 49MB\n", + " \u001b[32m+ qt \u001b[0m 5.9.7 h5867ecd_1 main 90MB\n", + " \u001b[32m+ readline \u001b[0m 8.2 h5eee18b_0 main 468kB\n", + " \u001b[32m+ ruby \u001b[0m 2.5.1 haf1161a_0 main 5MB\n", + " \u001b[32m+ setuptools \u001b[0m 65.6.3 py37h06a4308_0 main 1MB\n", + " \u001b[32m+ sqlite \u001b[0m 3.45.3 h5eee18b_0 main 2MB\n", + " \u001b[32m+ tk \u001b[0m 8.6.14 h39e8969_0 main 4MB\n", + " \u001b[32m+ wheel \u001b[0m 0.38.4 py37h06a4308_0 main 59kB\n", + " \u001b[32m+ xz \u001b[0m 5.4.6 h5eee18b_1 main 717kB\n", + " \u001b[32m+ yaml \u001b[0m 0.1.7 had09818_2 main 87kB\n", + " \u001b[32m+ zlib \u001b[0m 1.2.13 h5eee18b_1 main 127kB\n", + "\n", + " Summary:\n", + "\n", + " Install: 52 packages\n", + "\n", + " Total download: 249MB\n", + "\n", + "─────────────────────────────────────────────────────────────────────────────────────────\n", + "\n", + "\n", + "\n", + "Transaction starting\n", + "\u001b[?25l\u001b[2K\u001b[0G[+] 0.0s\n", + "Downloading 5%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.1s\n", + "Downloading (5) 0%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.2s\n", + "Downloading (5) 0%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.3s\n", + "Downloading (5) 0%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.4s\n", + "Downloading (5) 0%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.5s\n", + "Downloading (5) 0%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.6s\n", + "Downloading (5) 0%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.7s\n", + "Downloading (5) 0%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.8s\n", + "Downloading (5) 1%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.9s\n", + "Downloading (5) 1%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.0s\n", + "Downloading (5) 1%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.1s\n", + "Downloading (5) 3%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.2s\n", + "Downloading (5) 6%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibgcc-ng 8.9MB @ 7.4MB/s 1.2s\n", + "[+] 1.3s\n", + "Downloading (5) 10%\n", + "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.4s\n", + "Downloading (5) 13%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.5s\n", + "Downloading (5) 18%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.6s\n", + "Downloading (5) 23%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.7s\n", + "Downloading (5) 31%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.8s\n", + "Downloading (5) 39%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gklayout 26.7MB @ 14.3MB/s 1.8s\n", + "[+] 1.9s\n", + "Downloading (5) 43%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.0s\n", + "Downloading (5) 45%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gicu 23.8MB @ 11.7MB/s 2.0s\n", + "[+] 2.1s\n", + "Downloading (5) 47%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.2s\n", + "Downloading (5) 49%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.3s\n", + "Downloading (5) 52%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibstdcxx-ng 6.4MB @ 4.6MB/s 1.2s\n", + "[+] 2.4s\n", + "Downloading (5) 58%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.5s\n", + "Downloading (5) 61%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.6s\n", + "Downloading (5) 65%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.7s\n", + "Downloading (5) 68%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.8s\n", + "Downloading (5) 70%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gpython 48.7MB @ 16.5MB/s 2.8s\n", + "[+] 2.9s\n", + "Downloading (5) 72%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.0s\n", + "Downloading (5) 74%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.1s\n", + "Downloading (5) 75%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.2s\n", + "Downloading (5) 78%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.3s\n", + "Downloading (5) 80%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gopenssl 4.0MB @ 2.9MB/s 1.3s\n", + "ruby 5.3MB @ 3.1MB/s 1.4s\n", + "[+] 3.4s\n", + "Downloading (5) 80%\n", + "Extracting (5) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.5s\n", + "Downloading (5) 80%\n", + "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.6s\n", + "Downloading (5) 81%\n", + "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.7s\n", + "Downloading (5) 83%\n", + "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gtk 3.6MB @ 2.4MB/s 1.4s\n", + "[+] 3.8s\n", + "Downloading (5) 84%\n", + "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gpcre2 3.3MB @ 3.2MB/s 1.0s\n", + "[+] 3.9s\n", + "Downloading (5) 85%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.0s\n", + "Downloading (5) 86%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.1s\n", + "Downloading (5) 87%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.2s\n", + "Downloading (5) 88%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.3s\n", + "Downloading (5) 88%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.4s\n", + "Downloading (5) 89%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.5s\n", + "Downloading (5) 92%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gpip 2.8MB @ 2.2MB/s 1.2s\n", + "[+] 4.6s\n", + "Downloading (5) 93%\n", + "Extracting (10) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Ggst-plugins-base 2.3MB @ 1.6MB/s 1.3s\n", + "[+] 4.7s\n", + "Downloading (5) 94%\n", + "Extracting (10) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gsqlite 1.7MB @ 1.5MB/s 0.9s\n", + "gstreamer 1.7MB @ 1.8MB/s 0.9s\n", + "[+] 4.8s\n", + "Downloading (5) 96%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.9s\n", + "Downloading (5) 96%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.0s\n", + "Downloading (5) 97%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gqt 90.0MB @ 17.8MB/s 5.0s\n", + "[+] 5.1s\n", + "Downloading (5) 97%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.2s\n", + "Downloading (5) 97%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.3s\n", + "Downloading (5) 98%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibglib 1.6MB @ 932.0kB/s 0.9s\n", + "[+] 5.4s\n", + "Downloading (5) 98%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.5s\n", + "Downloading (5) 98%\n", + "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.6s\n", + "Downloading (5) 98%\n", + "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gsetuptools 1.4MB @ 987.1kB/s 1.0s\n", + "libiconv 1.4MB @ 850.5kB/s 1.0s\n", + "krb5 1.4MB @ 849.1kB/s 0.9s\n", + "[+] 5.7s\n", + "Downloading (5) 98%\n", + "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.8s\n", + "Downloading (5) 98%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.9s\n", + "Downloading (5) 99%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibxml2 1.4MB @ 834.9kB/s 0.9s\n", + "[+] 6.0s\n", + "Downloading (5) 98%\n", + "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.1s\n", + "Downloading (5) 98%\n", + "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.2s\n", + "Downloading (5) 99%\n", + "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.3s\n", + "Downloading (5) 99%\n", + "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibgit2 1.2MB @ 804.6kB/s 1.0s\n", + "[+] 6.4s\n", + "Downloading (5) 99%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.5s\n", + "Downloading (5) 99%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gncurses 1.2MB @ 937.3kB/s 0.9s\n", + "freetype 972.0kB @ 896.8kB/s 0.9s\n", + "[+] 6.6s\n", + "Downloading (5) 99%\n", + "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.7s\n", + "Downloading (5) 99%\n", + "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.8s\n", + "Downloading (5) 99%\n", + "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Ggmp 822.4kB @ 698.3kB/s 1.1s\n", + "[+] 6.9s\n", + "Downloading (5) 99%\n", + "Extracting (22) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gld_impl_linux-64 723.1kB @ 375.9kB/s 1.0s\n", + "[+] 7.0s\n", + "Downloading (5) 99%\n", + "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.1s\n", + "Downloading (5) 99%\n", + "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.2s\n", + "Downloading (5) 99%\n", + "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibxcb 623.5kB @ 577.3kB/s 0.7s\n", + "libnghttp2 716.6kB @ 539.0kB/s 0.8s\n", + "xz 716.9kB @ 446.2kB/s 0.9s\n", + "[+] 7.3s\n", + "Downloading (5) 99%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.4s\n", + "Downloading (5) 99%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.5s\n", + "Downloading (5) 99%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.6s\n", + "Downloading (5) 99%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.7s\n", + "Downloading (5) 99%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.8s\n", + "Downloading (5) 100%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibgomp 573.2kB @ 429.0kB/s 0.9s\n", + "[+] 7.9s\n", + "Downloading (5) 100%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gdbus 600.2kB @ 313.4kB/s 1.1s\n", + "[+] 8.0s\n", + "Downloading (5) 100%\n", + "Extracting (27) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.1s\n", + "Downloading (5) 100%\n", + "Extracting (27) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gglib 499.0kB @ 409.8kB/s 0.9s\n", + "readline 467.7kB @ 420.7kB/s 0.9s\n", + "bzip2 427.5kB @ 433.5kB/s 0.9s\n", + "[+] 8.2s\n", + "Downloading (5) 100%\n", + "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.3s\n", + "Downloading (5) 100%\n", + "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.4s\n", + "Downloading (5) 100%\n", + "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.5s\n", + "Downloading (5) 100%\n", + "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.6s\n", + "Downloading (5) 100%\n", + "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibssh2 311.8kB @ ??.?MB/s 0.5s\n", + "[+] 8.7s\n", + "Downloading (5) 100%\n", + "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibpng 362.6kB @ 468.9kB/s 0.8s\n", + "[+] 8.8s\n", + "Downloading (5) 100%\n", + "Extracting (31) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gfontconfig 297.6kB @ 429.9kB/s 0.7s\n", + "libcurl 386.4kB @ 406.6kB/s 1.0s\n", + "[+] 8.9s\n", + "Downloading (5) 100%\n", + "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gjpeg 283.5kB @ 240.5kB/s 0.7s\n", + "[+] 9.0s\n", + "Downloading (5) 100%\n", + "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.1s\n", + "Downloading (5) 100%\n", + "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.2s\n", + "Downloading (5) 100%\n", + "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.3s\n", + "Downloading (5) 100%\n", + "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.4s\n", + "Downloading (5) 100%\n", + "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gexpat 200.8kB @ 178.1kB/s 0.8s\n", + "[+] 9.5s\n", + "Downloading (5) 100%\n", + "Extracting (35) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibffi 154.0kB @ 111.1kB/s 0.7s\n", + "libedit 195.8kB @ 243.1kB/s 0.8s\n", + "[+] 9.6s\n", + "Downloading (5) 100%\n", + "Extracting (37) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gcertifi 155.3kB @ 150.2kB/s 0.8s\n", + "ca-certificates 139.9kB @ 91.3kB/s 0.7s\n", + "[+] 9.7s\n", + "Downloading (5) 100%\n", + "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.8s\n", + "Downloading (5) 100%\n", + "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.9s\n", + "Downloading (5) 100%\n", + "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gglib-tools 112.6kB @ 275.5kB/s 0.4s\n", + "[+] 10.0s\n", + "Downloading (5) 100%\n", + "Extracting (40) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.1s\n", + "Downloading (5) 100%\n", + "Extracting (40) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gzlib 127.1kB @ 105.1kB/s 0.7s\n", + "c-ares 116.3kB @ 115.3kB/s 0.7s\n", + "[+] 10.2s\n", + "Downloading (5) 100%\n", + "Extracting (41) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.3s\n", + "Downloading (5) 100%\n", + "Extracting (42) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.4s\n", + "Downloading (5) 100%\n", + "Extracting (42) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gyaml 87.1kB @ ??.?MB/s 0.4s\n", + "libev 108.9kB @ 77.3kB/s 0.8s\n", + "curl 88.8kB @ 80.9kB/s 0.8s\n", + "[+] 10.5s\n", + "Downloading (4) 100%\n", + "Extracting (45) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gwheel 58.7kB @ 79.1kB/s 0.4s\n", + "[+] 10.6s\n", + "Downloading (3) 100%\n", + "Extracting (46) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.7s\n", + "Downloading (3) 100%\n", + "Extracting (46) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibuuid 29.2kB @ 53.0kB/s 0.6s\n", + "[+] 10.8s\n", + "Downloading (2) 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G_libgcc_mutex 3.1kB @ 8.2kB/s 0.4s\n", + "[+] 10.9s\n", + "Downloading (1) 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.0s\n", + "Downloading (1) 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G_openmp_mutex 20.8kB @ 34.4kB/s 0.6s\n", + "[+] 11.1s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.2s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.3s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.4s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.5s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.6s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.7s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.8s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.9s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.0s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.1s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.2s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.3s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.4s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.5s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.6s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.7s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.8s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.9s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.0s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.1s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.2s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.3s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.4s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.5s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.6s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.7s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.8s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.9s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.0s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.1s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.2s\n", + "Downloading 100%\n", + "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.3s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.4s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.5s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.6s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.7s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.8s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.9s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.0s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.1s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.2s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.3s\n", + "Downloading 100%\n", + "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.4s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.5s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.6s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.7s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.8s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.9s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.0s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.1s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.2s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.3s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.4s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.5s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.6s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.7s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.8s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.9s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.0s\n", + "Downloading 100%\n", + "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.1s\n", + "Downloading 100%\n", + "Extracting (44) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.2s\n", + "Downloading 100%\n", + "Extracting (44) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.3s\n", + "Downloading 100%\n", + "Extracting (44) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.4s\n", + "Downloading 100%\n", + "Extracting (40) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.5s\n", + "Downloading 100%\n", + "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.6s\n", + "Downloading 100%\n", + "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.7s\n", + "Downloading 100%\n", + "Extracting (38) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.8s\n", + "Downloading 100%\n", + "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.9s\n", + "Downloading 100%\n", + "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.0s\n", + "Downloading 100%\n", + "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.1s\n", + "Downloading 100%\n", + "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.2s\n", + "Downloading 100%\n", + "Extracting (35) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.3s\n", + "Downloading 100%\n", + "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.4s\n", + "Downloading 100%\n", + "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.5s\n", + "Downloading 100%\n", + "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.6s\n", + "Downloading 100%\n", + "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.7s\n", + "Downloading 100%\n", + "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.8s\n", + "Downloading 100%\n", + "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.9s\n", + "Downloading 100%\n", + "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.0s\n", + "Downloading 100%\n", + "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.1s\n", + "Downloading 100%\n", + "Extracting (28) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.2s\n", + "Downloading 100%\n", + "Extracting (28) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.3s\n", + "Downloading 100%\n", + "Extracting (28) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.4s\n", + "Downloading 100%\n", + "Extracting (27) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.5s\n", + "Downloading 100%\n", + "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.6s\n", + "Downloading 100%\n", + "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.7s\n", + "Downloading 100%\n", + "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.8s\n", + "Downloading 100%\n", + "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.9s\n", + "Downloading 100%\n", + "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.0s\n", + "Downloading 100%\n", + "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.1s\n", + "Downloading 100%\n", + "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.2s\n", + "Downloading 100%\n", + "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.3s\n", + "Downloading 100%\n", + "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.4s\n", + "Downloading 100%\n", + "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.5s\n", + "Downloading 100%\n", + "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.6s\n", + "Downloading 100%\n", + "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.7s\n", + "Downloading 100%\n", + "Extracting (22) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.8s\n", + "Downloading 100%\n", + "Extracting (22) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.9s\n", + "Downloading 100%\n", + "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.0s\n", + "Downloading 100%\n", + "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.1s\n", + "Downloading 100%\n", + "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.2s\n", + "Downloading 100%\n", + "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.3s\n", + "Downloading 100%\n", + "Extracting (20) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.4s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.5s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.6s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.7s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.8s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.9s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.0s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.1s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.2s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.3s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.4s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.5s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.6s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.7s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.8s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.9s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.0s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.1s\n", + "Downloading 100%\n", + "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.2s\n", + "Downloading 100%\n", + "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.4s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.5s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.6s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.7s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.8s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.9s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.0s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.1s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.2s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.3s\n", + "Downloading 100%\n", + "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.4s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.5s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.6s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.7s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.8s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.9s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.0s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.1s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.2s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.3s\n", + "Downloading 100%\n", + "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.4s\n", + "Downloading 100%\n", + "Extracting (15) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.5s\n", + "Downloading 100%\n", + "Extracting (15) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.6s\n", + "Downloading 100%\n", + "Extracting (15) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.7s\n", + "Downloading 100%\n", + "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.8s\n", + "Downloading 100%\n", + "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.9s\n", + "Downloading 100%\n", + "Extracting (12) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.0s\n", + "Downloading 100%\n", + "Extracting (12) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.1s\n", + "Downloading 100%\n", + "Extracting (12) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.2s\n", + "Downloading 100%\n", + "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.3s\n", + "Downloading 100%\n", + "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.4s\n", + "Downloading 100%\n", + "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.5s\n", + "Downloading 100%\n", + "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.6s\n", + "Downloading 100%\n", + "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.7s\n", + "Downloading 100%\n", + "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.8s\n", + "Downloading 100%\n", + "Extracting (10) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.9s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.0s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.1s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.2s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.3s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.4s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.5s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.6s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.7s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.8s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.9s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.0s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.1s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.2s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.3s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.4s\n", + "Downloading 100%\n", + "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.5s\n", + "Downloading 100%\n", + "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.6s\n", + "Downloading 100%\n", + "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.7s\n", + "Downloading 100%\n", + "Extracting (6) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.8s\n", + "Downloading 100%\n", + "Extracting (5) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.9s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.0s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.1s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.2s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.3s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.4s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.5s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.6s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.7s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.8s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.9s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.0s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.1s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.2s\n", + "Downloading 100%\n", + "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.3s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.4s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.5s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.6s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.7s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.8s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.9s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.0s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.1s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.2s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.3s\n", + "Downloading 100%\n", + "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.4s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.5s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.6s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.7s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.8s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.9s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.0s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.1s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.2s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.3s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.4s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.5s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.6s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.7s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.8s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.9s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.0s\n", + "Downloading 100%\n", + "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.1s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.2s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.3s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.4s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.5s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.6s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.7s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.8s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.9s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.0s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.1s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.2s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.3s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.4s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.5s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.6s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.7s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.8s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.9s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.0s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.1s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.2s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.3s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.4s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.5s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.6s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.7s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.8s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.9s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 48.0s\n", + "Downloading 100%\n", + "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G\u001b[?25hLinking _libgcc_mutex-0.1-main\n", + "Linking libstdcxx-ng-11.2.0-h1234567_1\n", + "Linking ld_impl_linux-64-2.40-h12ee557_0\n", + "Linking ca-certificates-2024.9.24-h06a4308_0\n", + "Linking libgomp-11.2.0-h1234567_1\n", + "Linking _openmp_mutex-5.1-1_gnu\n", + "Linking libgcc-ng-11.2.0-h1234567_1\n", + "Linking yaml-0.1.7-had09818_2\n", + "Linking libuuid-1.41.5-h5eee18b_0\n", + "Linking gmp-6.2.1-h295c915_3\n", + "Linking ncurses-6.4-h6a678d5_0\n", + "Linking bzip2-1.0.8-h5eee18b_6\n", + "Linking libev-4.33-h7f8727e_1\n", + "Linking c-ares-1.19.1-h5eee18b_0\n", + "Linking libiconv-1.16-h5eee18b_3\n", + "Linking libffi-3.4.4-h6a678d5_1\n", + "Linking xz-5.4.6-h5eee18b_1\n", + "Linking zlib-1.2.13-h5eee18b_1\n", + "Linking openssl-1.1.1w-h7f8727e_0\n", + "Linking libxcb-1.15-h7f8727e_0\n", + "Linking jpeg-9e-h5eee18b_3\n", + "Linking icu-58.2-he6710b0_3\n", + "Linking expat-2.6.3-h6a678d5_0\n", + "Linking libedit-3.1.20230828-h5eee18b_0\n", + "Linking readline-8.2-h5eee18b_0\n", + "Linking tk-8.6.14-h39e8969_0\n", + "Linking pcre2-10.42-hebb0a14_1\n", + "Linking libpng-1.6.39-h5eee18b_0\n", + "Linking libssh2-1.10.0-h37d81fd_2\n", + "Linking libnghttp2-1.52.0-ha637b67_1\n", + "Linking krb5-1.20.1-h568e23c_1\n", + "Linking sqlite-3.45.3-h5eee18b_0\n", + "Linking ruby-2.5.1-haf1161a_0\n", + "Linking libglib-2.78.4-hdc74915_0\n", + "Linking freetype-2.12.1-h4a9f257_0\n", + "Linking libcurl-8.2.1-h91b91d3_0\n", + "Linking python-3.7.16-h7a1cb2a_0\n", + "Linking wheel-0.38.4-py37h06a4308_0\n", + "Linking glib-tools-2.78.4-h6a678d5_0\n", + "Linking curl-8.2.1-h37d81fd_0\n", + "Linking certifi-2022.12.7-py37h06a4308_0\n", + "Linking libgit2-1.6.4-ha637b67_0\n", + "Linking setuptools-65.6.3-py37h06a4308_0\n", + "Linking pip-22.3.1-py37h06a4308_0\n", + "Linking glib-2.78.4-h6a678d5_0\n", + "Linking gstreamer-1.14.1-h5eee18b_1\n", + "Linking dbus-1.13.18-hb2f20db_0\n", + "Linking gst-plugins-base-1.14.1-h6a678d5_1\n", + "Linking libxml2-2.9.9-20220706_155948\n", + "Linking fontconfig-2.13.0-h9420a91_0\n", + "Linking qt-5.9.7-h5867ecd_1\n", + "Linking klayout-0.28.17_212_gfa14afbbf-20240223_100318_py37\n", + "\n", + "Transaction finished\n", + "\n" + ] + } + ], + "source": [ + "# Setup the environment for the OpenFASOC GDSFactory generator\n", + "# You only need to run this block once!\n", + "\n", + "# Clone OpenFASoC\n", + "!git clone https://github.com/idea-fasoc/OpenFASOC\n", + "# Install python dependencies\n", + "!pip install sky130\n", + "!pip install gf180 prettyprinttree svgutils\n", + "!pip install gdsfactory==7.7.0\n", + "\n", + "import pathlib\n", + "import os\n", + "# Install KLayout (via conda)\n", + "!curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\n", + "conda_prefix_path = pathlib.Path('conda-env')\n", + "CONDA_PREFIX = str(conda_prefix_path.resolve())\n", + "%env CONDA_PREFIX={CONDA_PREFIX}\n", + "\n", + "!bin/micromamba create --yes --prefix $CONDA_PREFIX\n", + "# Install from the litex-hub channel\n", + "!bin/micromamba install --yes --prefix $CONDA_PREFIX \\\n", + " --channel litex-hub \\\n", + " --channel main \\\n", + " klayout" + ] + }, + { + "cell_type": "markdown", + "source": [ + " klayoutバイナリをシステムパスに追加し、GLayoutディレクトリに移動します。\n", + "(カーネルを再起動する度に実行する必要があります。)\n", + "\n", + "\n" + ], + "metadata": { + "id": "zjJ2eUWiaUbR" + } + }, + { + "cell_type": "code", + "source": [ + "# Setup the environment for the OpenFASOC GDSFactory generator\n", + "\n", + "# Adding micro-mamba binary directory to the PATH\n", + "# This directory contains Klayout\n", + "import pathlib\n", + "import os\n", + "conda_prefix_path = pathlib.Path('conda-env')\n", + "CONDA_PREFIX = str(conda_prefix_path.resolve())\n", + "\n", + "%env CONDA_PREFIX={CONDA_PREFIX}\n", + "# Add conda packages to the PATH\n", + "PATH = os.environ['PATH']\n", + "%env PATH={PATH}:{CONDA_PREFIX}/bin\n", + "\n", + "%cd /content/OpenFASOC/openfasoc/generators/glayout\n" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "xMUPna-sakFn", + "outputId": "eb5a0f92-3f32-4664-f938-b1afcf380066" + }, + "execution_count": 5, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "env: CONDA_PREFIX=/content/conda-env\n", + "env: PATH=/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/conda-env/bin:/content/conda-env/bin\n", + "/content/OpenFASOC/openfasoc/generators/glayout\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [], + "metadata": { + "id": "sVWvV2Pwg9Ew" + } + }, + { + "cell_type": "markdown", + "source": [ + "# cell_config.py" + ], + "metadata": { + "id": "471iz7QIa3Iw" + } + }, + { + "cell_type": "code", + "source": [ + "from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict\n", + "#from glayout.flow.pdk.gf180_mapped import gf180\n", + "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", + "from glayout.flow.pdk.mappedpdk import MappedPDK\n", + "from glayout.flow.pdk.util.comp_utils import evaluate_bbox\n", + "from gdsfactory import Component\n", + "from gdsfactory.components import rectangle\n", + "from glayout.flow.primitives.fet import pmos\n", + "from glayout.flow.primitives.fet import nmos\n", + "from glayout.flow.routing.straight_route import straight_route\n", + "from glayout.flow.routing.c_route import c_route\n", + "from glayout.flow.routing.L_route import L_route\n", + "from glayout.flow.routing.smart_route import smart_route\n", + "from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized\n", + "from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized\n", + "from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port\n", + "\n", + "def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ]) -> Component:\n", + "\t'''\n", + " To add external I/O ports onto the cell for LVS\n", + "\n", + "\t@ args:\n", + " \t# pdk: please refer to the glayout library\n", + " \t# comp: please refer to the glayout library\n", + " \t# port_list: tuple[ dict[str, Union[float, str]] ] specifying new port's corresponding pin size, and\n", + "\t\t\t\t\t the name of new port and exiting port managed to align with in the given\n", + "\t\t\t\t\t component, e.g.\n", + "\t\t\t\t\t \t(\n", + "\t\t\t\t\t\t\t{\n", + "\t\t\t\t\t\t\t\t\"new_port\": \"drain_new\",\n", + "\t\t\t\t\t\t\t\t\"new_port_label\": \"drain_new_label\",\n", + "\t\t\t\t\t\t\t\t\"pin_width\": 0.5,\n", + "\t\t\t\t\t\t\t\t\"pin_height\": 0.5,\n", + "\t\t\t\t\t\t\t\t\"ref_port\": \"multiplier_0_drain_E\"\n", + "\t\t\t\t\t\t\t},\n", + "\t\t\t\t\t\t\t{\n", + "\t\t\t\t\t\t\t\t\"new_port\": \"source_new\",\n", + "\t\t\t\t\t\t\t\t\"new_port_label\": \"source_new_label\",\n", + "\t\t\t\t\t\t\t\t\"pin_width\": 1.5,\n", + "\t\t\t\t\t\t\t\t\"pin_height\": 1.5,\n", + "\t\t\t\t\t\t\t\t\"ref_port\": \"multiplier_0_source_E\"\n", + "\t\t\t\t\t\t\t}\n", + "\t\t\t\t\t\t)\n", + "\n", + "\t\t# return: gdsfactory.Component\n", + "\n", + "\t@ Limitations:\n", + "\t\t# So far, only skywater130 process is validated\n", + "\t'''\n", + "\n", + "\t# Add pins and text labels for LVS\n", + "\tpins_labels_info = list() # list that contains all port and component information\n", + "\tprint(f\"port_list: {port_list}\")\n", + "\tfor port in port_list:\n", + "\t\t# To get the layer's data type mapped to the GDS\n", + "\t\tref_port_layer = comp.ports[ port[\"ref_port\"] ].layer[0] # [0]: layer mapping, [1]: pin, drawing, label, net, etc.\n", + "\n", + "\t\t# To create the pin w/ label where the layer[1] is mapped to 16\n", + "\t\tnew_port_pin = rectangle(layer=(ref_port_layer, 16), size=(port[\"pin_width\"], port[\"pin_height\"]),centered=True).copy() # True set rectangle's centroid to the relative (0, 0)\n", + "\t\tnew_port_pin.add_label(text=port[\"new_port_label\"], layer=(ref_port_layer, 5)) # layer[1]=5 mapped to the \"label\" datatype in the GDS\n", + "\n", + "\t\t# To align the new port with the designated port existing in the given component\n", + "\t\talignment = ('c', 'b')\n", + "\t\tcomp_ref = align_comp_to_port(new_port_pin, comp.ports[ port[\"ref_port\"] ], alignment=alignment)\n", + "\t\tcomp.add(comp_ref)\n", + "\n", + "\treturn comp\n", + "\n" + ], + "metadata": { + "id": "fWFYNrTUa_7n" + }, + "execution_count": 6, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# inv_lib.py" + ], + "metadata": { + "id": "s0MLpq3xcaO4" + } + }, + { + "cell_type": "code", + "source": [ + "#from glayout.flow.pdk.gf180_mapped import gf180\n", + "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", + "from glayout.flow.pdk.mappedpdk import MappedPDK\n", + "from glayout.flow.pdk.util.comp_utils import prec_ref_center, movex, movey, evaluate_bbox, align_comp_to_port\n", + "from gdsfactory import Component\n", + "from gdsfactory.components import rectangle\n", + "from glayout.flow.primitives.fet import pmos\n", + "from glayout.flow.primitives.fet import nmos\n", + "from glayout.flow.routing.straight_route import straight_route\n", + "from glayout.flow.routing.c_route import c_route\n", + "from glayout.flow.routing.L_route import L_route\n", + "from glayout.flow.routing.smart_route import smart_route\n", + "\n", + "def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_width, nmos_length, orientation):\n", + "\t# Create a top level component\n", + "\ttop_level = Component(component_name)\n", + "\t# To prepare one PMOS and one NMOS for the subsequent inverter cell construction\n", + "\tpfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length)\n", + "\tnfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length)\n", + "\n", + "\t# Instantiation of above PMOS and NMOS under the top level\n", + "\tpfet_ref = prec_ref_center(pfet)\n", + "\tnfet_ref = prec_ref_center(nfet)\n", + "\ttop_level.add(pfet_ref)\n", + "\ttop_level.add(nfet_ref)\n", + "\n", + "\t# Placement (relative move)\n", + "\tmos_spacing = pdk.util_max_metal_seperation()\n", + "\tif(orientation==\"horizontal\"):\n", + "\t\tpfet_ref.rotate(90)\n", + "\t\tnfet_ref.rotate(90)\n", + "\telse:\n", + "\t\tpass\n", + "\tpfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)\n", + "\n", + "\t# Routing\n", + "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_drain_E\"], nfet_ref.ports[\"multiplier_0_drain_E\"])\n", + "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_gate_W\"], nfet_ref.ports[\"multiplier_0_gate_W\"])\n", + "\n", + "\t# To add the ports\n", + "\ttop_level.add_ports(pfet_ref.get_ports_list(), prefix=\"pmos_\")\n", + "\ttop_level.add_ports(nfet_ref.get_ports_list(), prefix=\"nmos_\")\n", + "\n", + "\treturn top_level" + ], + "metadata": { + "id": "VZoH8lTCcecm" + }, + "execution_count": 7, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# transmission_gate.py" + ], + "metadata": { + "id": "ZQOZALxpcgFc" + } + }, + { + "cell_type": "code", + "source": [ + "from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict\n", + "#from glayout.flow.pdk.gf180_mapped import gf180\n", + "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", + "from glayout.flow.pdk.mappedpdk import MappedPDK\n", + "from glayout.flow.pdk.util.comp_utils import evaluate_bbox\n", + "from gdsfactory import Component\n", + "from gdsfactory.components import rectangle\n", + "from glayout.flow.primitives.fet import pmos\n", + "from glayout.flow.primitives.fet import nmos\n", + "from glayout.flow.routing.straight_route import straight_route\n", + "from glayout.flow.routing.c_route import c_route\n", + "from glayout.flow.routing.L_route import L_route\n", + "from glayout.flow.routing.smart_route import smart_route\n", + "from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized\n", + "from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized\n", + "from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port\n", + "\n", + "# My own cell library\n", + "#from inv_lib import reconfig_inv\n", + "#import cell_config as config\n", + "\n", + "def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_width, pmos_length, nmos_width, nmos_length):\n", + "\t# To prepare all necessary cells to construct a transmission gate, i.e.\n", + "\t# 1) PMOS\n", + "\t# 2) NMOS\n", + "\tpfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=pmos_width, length=pmos_length)\n", + "\tnfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=nmos_width, length=nmos_length)\n", + "\n", + "\t# Placement and adding ports\n", + "\ttop_level = Component(name=\"TG\")\n", + "\tpfet_ref = prec_ref_center(pfet)\n", + "\tnfet_ref = prec_ref_center(nfet)\n", + "\ttop_level.add(pfet_ref)\n", + "\ttop_level.add(nfet_ref)\n", + "\n", + "\t# Placement\n", + "\tmos_spacing = pdk.util_max_metal_seperation()\n", + "\t#mos_spacing = pdk.get_grule(\"met1\")[\"min_width\"])\n", + "\tif flip_config[\"degree\"] != None:\n", + "\t\tpfet_ref.rotate(flip_config[\"degree\"])\n", + "\t\tnfet_ref.rotate(flip_config[\"degree\"])\n", + "\tpfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)\n", + "\n", + "\t# Routing\n", + "\t# To simplify the routing for the parallel-gate transistors, the layout is realised as follow which is expected to be equivalent to a TG\n", + "\t# a) PMOS.source connected to NMOS.source\n", + "\t# b) PMOS.drain connected to NMOS.drain\n", + "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_source_E\"], nfet_ref.ports[\"multiplier_0_source_E\"]) # \"in\" of the TG\n", + "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_drain_W\"], nfet_ref.ports[\"multiplier_0_drain_E\"]) # \"out\" of the TG\n", + "\n", + "\ttop_level.add_ports(pfet_ref.get_ports_list(), prefix=\"pmos_\")\n", + "\ttop_level.add_ports(nfet_ref.get_ports_list(), prefix=\"nmos_\")\n", + "\t#top_level.add_port(\n", + "\t#\tname=\"\", center=[0, width / 2], width=width, orientation=180, layer=layer\n", + "\t#)\n", + "\n", + "\t# Add pins and text labels for LVS\n", + "\tpins_labels_info = list() # list that contains all port and component information\n", + "\t# To define the layers\n", + "\tgds_met1 = pdk.get_glayer(\"met2\")[0]\n", + "\tgds_met2 = gds_met1+1\n", + "\tgds_met3 = gds_met2+1\n", + "\tgds_met4 = gds_met3+1\n", + "\tgds_met5 = gds_met4+1\n", + "\t# To get the respective layers of the underlying TG's PMOS.source port PMOS.drain port\n", + "\ttg_din_portLayer = top_level.ports[\"pmos_multiplier_0_source_W\"].layer[0]\n", + "\ttg_dout_portLayer = top_level.ports[\"pmos_multiplier_0_drain_E\"].layer[0]\n", + "\t# To create the pins w/ labels and append to info list\n", + "\ttg_din_pin = rectangle(layer=(tg_din_portLayer, 16), size=(1, 1),centered=True).copy() # True set rectangle's centroid to the relative (0, 0)\n", + "\ttg_dout_pin = rectangle(layer=(tg_dout_portLayer, 16), size=(1, 1), centered=True).copy()\n", + "\ttg_din_pin.add_label(text=\"Vin\", layer=(tg_din_portLayer, 5))\n", + "\ttg_dout_pin.add_label(text=\"Vout\", layer=(tg_dout_portLayer, 5))\n", + "\tpins_labels_info.append((tg_din_pin, top_level.ports[\"pmos_multiplier_0_source_W\"], None))\n", + "\tpins_labels_info.append((tg_dout_pin, top_level.ports[\"pmos_multiplier_0_drain_E\"], None))\n", + "\n", + "\t#print(top_level.ports[\"pmos_multiplier_0_source_W\"].name)\n", + "\t#top_level.pprint_ports()\n", + "\n", + "\t# Move everythin to position\n", + "\tfor comp, prt, alignment in pins_labels_info:\n", + "\t\talignment = ('c', 'b') if alignment is None else alignment\n", + "\t\tcompref = align_comp_to_port(comp, prt, alignment=alignment)\n", + "\t\t#top_level.add(compref)\n", + "\n", + "\treturn top_level #top_level.flatten()\n", + "\n", + "def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length):\n", + "\t# To prepare all necessary cells to construct a transmission gate, i.e.\n", + "\t# 1) transmission gate\n", + "\t# 2) Inverter\n", + "\ttg = naive_tg_cell(pdk=pdk, flip_config={\"degree\": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length)\n", + "\tinv = reconfig_inv(pdk=pdk, component_name=\"gate_ctrl_inv\", pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation=\"horizontal\")\n", + "\n", + "\t# Instantiation of the essential cells\n", + "\ttop_level = Component(name=\"tg_with_inv\")\n", + "\ttg_ref = prec_ref_center(tg)\n", + "\tinv_ref = prec_ref_center(inv)\n", + "\ttop_level.add(tg_ref)\n", + "\ttop_level.add(inv_ref)\n", + "\n", + "\t# Placement\n", + "\tmos_spacing = pdk.util_max_metal_seperation()\n", + "\tnwell_min_spacing = pdk.get_grule(\"nwell\")[\"min_separation\"]\n", + "\tinv_cell_width = inv_ref.xsize # or = evaluate_bbox(inv)[0]\n", + "\ttg_ref.movex(inv_cell_width + nwell_min_spacing)\n", + "\n", + "\t# Routing\n", + "\t# 1) PMOS of the TG is switched on/off by the inverter's output\n", + "\t# 2) NMOS of the TG is switched on/off by an external control signal connected to inverter's input port as well\n", + "\ttop_level << smart_route(pdk, inv_ref.ports[\"pmos_multiplier_0_drain_E\"], tg_ref.ports[\"pmos_multiplier_0_gate_W\"])\n", + "\ttop_level << smart_route(pdk, inv_ref.ports[\"nmos_multiplier_0_gate_S\"], tg_ref.ports[\"nmos_multiplier_0_gate_S\"])\n", + "\n", + "\t# Adding the ports\n", + "\ttop_level.add_ports(tg_ref.get_ports_list(), prefix=\"tg_\")\n", + "\ttop_level.add_ports(inv_ref.get_ports_list(), prefix=\"inv_\")\n", + "\n", + "\treturn top_level\n" + ], + "metadata": { + "id": "f9zRFCm6cl4N" + }, + "execution_count": 13, + "outputs": [] + }, + { + "cell_type": "markdown", + "source": [ + "# eval.py" + ], + "metadata": { + "id": "VLrreUmkcrg_" + } + }, + { + "cell_type": "code", + "source": [ + "#from glayout.flow.pdk.gf180_mapped import gf180\n", + "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", + "import gdstk\n", + "import svgutils.transform as sg\n", + "import IPython.display\n", + "from IPython.display import clear_output\n", + "\n", + "def display_gds(gds_file, image_filename: str, scale = 3):\n", + " # Generate an SVG image\n", + " top_level_cell = gdstk.read_gds(gds_file).top_level()[0]\n", + " top_level_cell.write_svg(image_filename)\n", + " # Scale the image for displaying\n", + " fig = sg.fromfile(image_filename)\n", + " fig.set_size((str(float(fig.width) * scale), str(float(fig.height) * scale)))\n", + " fig.save(image_filename)\n", + "\n", + " # Display the image\n", + " IPython.display.display(IPython.display.SVG(image_filename))\n", + "\n", + "def main():\n", + " tg_inst = tg_with_inv(pdk=sky130, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15)\n", + " tg_inst = add_port_lvs(\n", + " pdk=sky130,\n", + " comp=tg_inst,\n", + " port_list=[\n", + " {\n", + " \"new_port\": \"tg_ctrl\",\n", + " \"new_port_label\": \"ctrl\",\n", + " \"pin_width\": tg_inst.ports[\"inv_nmos_multiplier_0_gate_S\"].width,\n", + " \"pin_height\": tg_inst.ports[\"inv_nmos_multiplier_0_gate_S\"].width,\n", + " \"ref_port\": \"inv_nmos_multiplier_0_gate_S\"\n", + " },\n", + " {\n", + " \"new_port\": \"tg_din\",\n", + " \"new_port_label\": \"din\",\n", + " \"pin_width\": 0.3,\n", + " \"pin_height\": 0.3,\n", + " \"ref_port\": \"tg_pmos_multiplier_0_source_W\"\n", + " },\n", + " {\n", + " \"new_port\": \"tg_dout\",\n", + " \"new_port_label\": \"dout\",\n", + " \"pin_width\": 0.3,\n", + " \"pin_height\": 0.3,\n", + " \"ref_port\": \"tg_nmos_multiplier_0_drain_N\"\n", + " }\n", + "\t ]\n", + "\t)\n", + " #tg_inst.flatten()\n", + " #tg_inst.show()\n", + " tg_inst.write_gds(\"tg_with_inv.gds\")\n", + " display_gds(gds_file=\"tg_with_inv.gds\", image_filename=\"tg_with_inv.svg\", scale=5)\n", + "\n", + "if __name__ == \"__main__\":\n", + " main()" + ], + "metadata": { + "id": "K3JfrIUWctcI", + "outputId": "b69ca1d4-6318-4a8c-b46c-47f42343f65d", + "colab": { + "base_uri": "https://localhost:8080/", + "height": 1000 + } + }, + "execution_count": 25, + "outputs": [ + { + "output_type": "stream", + "name": "stderr", + "text": [ + ":51: UserWarning: Unnamed cells, 7 in 'tg_with_inv$6'\n", + " tg_inst.write_gds(\"tg_with_inv.gds\")\n", + "\u001b[32m2024-11-14 02:40:11.852\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mgdsfactory.component\u001b[0m:\u001b[36m_write_library\u001b[0m:\u001b[36m1851\u001b[0m - \u001b[1mWrote to 'tg_with_inv.gds'\u001b[0m\n" + ] + }, + { + "output_type": "stream", + "name": "stdout", + "text": [ + "port_list: [{'new_port': 'tg_ctrl', 'new_port_label': 'ctrl', 'pin_width': 0.33, 'pin_height': 0.33, 'ref_port': 'inv_nmos_multiplier_0_gate_S'}, {'new_port': 'tg_din', 'new_port_label': 'din', 'pin_width': 0.3, 'pin_height': 0.3, 'ref_port': 'tg_pmos_multiplier_0_source_W'}, {'new_port': 'tg_dout', 'new_port_label': 'dout', 'pin_width': 0.3, 'pin_height': 0.3, 'ref_port': 'tg_nmos_multiplier_0_drain_N'}]\n" + ] + }, + { + "output_type": "display_data", + "data": { + "text/plain": [ + "" + ], + "image/svg+xml": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndout\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nctrl\n\n\n\ndin\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" + }, + "metadata": {} + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "\n", + "\n", + "---\n", + "\n", + "\n", + "# トランスミッションゲートを表示させます。\n" + ], + "metadata": { + "id": "VTXMiC1nbFTu" + } + }, + { + "cell_type": "markdown", + "source": [ + "Geminiによると・・・\n", + "生成されたGDSファイルに名前のないセルがあるという警告が表示されているようです。この警告はgdsfactoryから発生し、「TG$2」セル内に明示的な名前が割り当てられていないコンポーネントがあることを示しています。\n", + "\n", + "すぐに問題が発生するわけではありませんが、整理とデバッグを改善するために、すべてのコンポーネントに名前を付けることをお勧めします。コンポーネントを作成するときに name 引数を指定することで、コンポーネントに名前を付けることができます。\n", + "\n", + "たとえば、transmissionGate_cell 関数では、pfet および nfet インスタンスに名前を付けることができます。\n", + "\n", + "\n", + "pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=width, length=length, name=\"pmos_instance\")\n", + "nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=width, length=length, name=\"nmos_instance\")\n", + "Use code with caution\n", + "これにより、GDSファイルがより読みやすくなり、扱いやすくなります。\n", + "\n", + "・・・らしいです" + ], + "metadata": { + "id": "xyQej3g8pIMq" + } + } + ] +} \ No newline at end of file From 477ff15663e0edcebde4221a0786e8e570061a2a Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Thu, 14 Nov 2024 17:13:19 +0000 Subject: [PATCH 11/21] Add functions to automatically insert the external I/O ports on the target Pcell --- .../cell_config.py | 77 +++++++++++++++---- .../transmission_gate_saltychip/eval.py | 17 ++-- 2 files changed, 72 insertions(+), 22 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py index 915d85688..06dfedb6c 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py @@ -15,7 +15,25 @@ from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port -def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ]) -> Component: +def add_wire(comp, xsize=2, ysize=1, layer=(68, 20), label="new_wire", center=(0, 0), position_offset=(1.4, 1.4)): + c = Component() + c.add_polygon( + [ + (center[0]-position_offset[0], center[1]-position_offset[1]), + (center[0]+position_offset[0], center[1]-position_offset[1]), + (center[0]+position_offset[0], center[1]-position_offset[1]-ysize), + (center[0]-position_offset[0], center[1]-position_offset[1]-ysize) + ], + layer=layer + ) + comp.add_port(name=f"{label}_W", center=[0, ysize / 2], width=ysize, orientation=0, layer=layer) + comp.add_port(name=f"{label}_E", center=[xsize, ysize / 2], width=ysize, orientation=0, layer=layer) + c.add_label(text=f"{label}_W", position=(c.x-xsize/2, c.y), layer=layer) + c.add_label(text=f"{label}_E", position=(c.x+xsize/2, c.y), layer=layer) + + return c + +def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ], port_feature: dict[str, str]) -> Component: ''' To add external I/O ports onto the cell for LVS @@ -41,27 +59,58 @@ def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Uni "ref_port": "multiplier_0_source_E" } ) + # port_feature: a "dict"-type primitive specifying the feature of the new port, e.g. + {"port_type":"pin", "layer":None} -> To create a rectangle as the new port + {"port_type":"wire", "layer":"met1"} -> To extend the existing port by a wire only # return: gdsfactory.Component @ Limitations: # So far, only skywater130 process is validated ''' + + if port_feature["port_type"] == "pin": + port_type = 0 + elif port_feature["port_type"] == "wire": + new_port_layer = pdk.get_glayer(port_feature["layer"]) + port_type = 1 + wire_width = comp.xsize + wire_height = pdk.get_grule(port_feature["layer"])["min_width"] + new_port_center = comp.center + new_port_position_offset = (comp.xsize/2, comp.ysize/2+pdk.util_max_metal_seperation()) + wire_spacing = pdk.get_grule(port_feature["layer"])["min_separation"]+wire_height + port_cnt = 0 + else: + raise ValueError("The port type must be either pin or wire") + + if port_type == 0: # port of which features pin-added type + # Add pins and text labels for LVS + pins_labels_info = list() # list that contains all port and component information + print(f"port_list: {port_list}") + for port in port_list: + # To get the layer's data type mapped to the GDS + ref_port_layer = comp.ports[ port["ref_port"] ].layer[0] # [0]: layer mapping, [1]: pin, drawing, label, net, etc. - # Add pins and text labels for LVS - pins_labels_info = list() # list that contains all port and component information - print(f"port_list: {port_list}") - for port in port_list: - # To get the layer's data type mapped to the GDS - ref_port_layer = comp.ports[ port["ref_port"] ].layer[0] # [0]: layer mapping, [1]: pin, drawing, label, net, etc. + # To create the pin w/ a label where the layer[1] is mapped to 16 + new_port = rectangle(layer=(ref_port_layer, 16), size=(port["pin_width"], port["pin_height"]),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) + new_port.add_label(text=port["new_port_label"], layer=(ref_port_layer, 5)) # layer[1]=5 mapped to the "label" datatype in the GDS - # To create the pin w/ label where the layer[1] is mapped to 16 - new_port_pin = rectangle(layer=(ref_port_layer, 16), size=(port["pin_width"], port["pin_height"]),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) - new_port_pin.add_label(text=port["new_port_label"], layer=(ref_port_layer, 5)) # layer[1]=5 mapped to the "label" datatype in the GDS + # To align the new port with the designated port existing in the given component + alignment = ('c', 'b') + comp_ref = align_comp_to_port(new_port, comp.ports[ port["ref_port"] ], alignment=alignment) + comp.add(comp_ref) - # To align the new port with the designated port existing in the given component - alignment = ('c', 'b') - comp_ref = align_comp_to_port(new_port_pin, comp.ports[ port["ref_port"] ], alignment=alignment) - comp.add(comp_ref) + else: # port_type=1, i.e. port of which features wire_only + # Add pins and text labels for LVS + pins_labels_info = list() # list that contains all port and component information + print(f"port_list: {port_list}") + for port in port_list: + # To create the pin where the layer[1] is mapped to 16 + new_port = add_wire(comp=comp, xsize=wire_width, ysize=wire_height, layer=new_port_layer, label=port["new_port_label"], center=new_port_center, position_offset=new_port_position_offset) + new_port_ref = comp.add_ref(new_port) + new_port_ref.movey(-wire_spacing*port_cnt) + comp << smart_route(pdk, comp.ports.get(port["ref_port"]), comp.ports.get(port["new_port"]+"_E")) + + port_cnt = port_cnt + 1 # Increment the index indicating the new port return comp \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index 66b15b77c..72a32a73a 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -10,31 +10,32 @@ def main(): comp=tg_inst, port_list=[ { - "new_port": "tg_ctrl", - "new_port_label": "ctrl", + "new_port": "Vctrl", + "new_port_label": "Vctrl", "pin_width": tg_inst.ports["inv_nmos_multiplier_0_gate_S"].width, "pin_height": tg_inst.ports["inv_nmos_multiplier_0_gate_S"].width, "ref_port": "inv_nmos_multiplier_0_gate_S" }, { - "new_port": "tg_din", - "new_port_label": "din", + "new_port": "Vin", + "new_port_label": "Vin", "pin_width": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_source_S"].width, "pin_height": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_source_S"].width, "ref_port": "tg_pmos_multiplier_0_source_W" }, { - "new_port": "tg_dout", - "new_port_label": "dout", + "new_port": "Vout", + "new_port_label": "Vout", "pin_width": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_drain_S"].width, "pin_height": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_drain_S"].width, "ref_port": "tg_nmos_multiplier_0_drain_N" } - ] + ], + port_feature = {"port_type":"wire", "layer":"met2"} # met2 is actually mapped to met1 in sky130 proceess ) #tg_inst.flatten() tg_inst.show() - tg_inst.write_gds("gds/tg_with_inv.gds") + #tg_inst.write_gds("gds/tg_with_inv.gds") if __name__ == "__main__": main() \ No newline at end of file From e034352e3932fe751c3b24edf7668ff8b8e93d8a Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Fri, 15 Nov 2024 14:07:44 +0000 Subject: [PATCH 12/21] Add the ToDo list for the PR draft submission --- .../transmission_gate_saltychip/README.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md index 4049e2a20..22bafe394 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md @@ -8,3 +8,29 @@ | inv_lib.py | Layout generation of inverter for controlling the transmission gate's PMOS and NMOS | | | transmission_gate.py | Layout generation of a transmission gate | The layout is still under construction | | mimcap_array.py | Layout generation of a 8x8 MIM capacitor array | Transmission gate combined with a MIM capacitor array is the aim in this project | + +--- + +Submission of PR Draft (deadline: 24/11/2024) + +- ToDo list +- Transmission gate + - [x] Layout + - [ ] Add ports w/ labels onto the layout (for the subsequent LVS) + - [ ] DRC of the layout w/o error (Magic) + - [ ] DRC of the layout w/o error (Klayout) + - [ ] Create the baseline schematic of the created component + - [ ] LVS w/o error + - [ ] Document about the PCell specification + - [ ] PEX and create the testbench + - [ ] Verification gets passed +- MIMI capacitor array + - [x] Layout + - [ ] Add ports w/ labels onto the layout (for the subsequent LVS) + - [ ] DRC of the layout w/o error (Magic) + - [ ] DRC of the layout w/o error (Klayout) + - [ ] Create the baseline schematic of the created component + - [ ] LVS w/o error + - [ ] Document about the PCell specification + - [ ] PEX and create the testbench + - [ ] Verification gets passed \ No newline at end of file From 94561b630cc44a17f17aa200ee8c374b9bdd1a43 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 17 Nov 2024 08:26:51 +0000 Subject: [PATCH 13/21] Change the route layer inside the transmission gate --- .../cell_config.py | 137 +++++++++++------- .../transmission_gate_saltychip/eval.py | 42 +++--- .../transmission_gate_saltychip/inv_lib.py | 4 +- .../transmission_gate.py | 6 +- 4 files changed, 115 insertions(+), 74 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py index 06dfedb6c..41b1ea28a 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py @@ -7,6 +7,7 @@ from gdsfactory.components import rectangle from glayout.flow.primitives.fet import pmos from glayout.flow.primitives.fet import nmos +from glayout.flow.primitives.via_gen import via_stack from glayout.flow.routing.straight_route import straight_route from glayout.flow.routing.c_route import c_route from glayout.flow.routing.L_route import L_route @@ -15,24 +16,94 @@ from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port -def add_wire(comp, xsize=2, ysize=1, layer=(68, 20), label="new_wire", center=(0, 0), position_offset=(1.4, 1.4)): +# Status: W.I.P. +def add_wire(comp, xsize=2, ysize=1, layer=(68, 20), port_label="new_wire", center=(0, 0), position_offset=(1.4, 1.4)): c = Component() + wire_leftBottom_pos = (center[0]-position_offset[0], center[1]-position_offset[1]) + wire_rightBottom_pos = (center[0]+position_offset[0], center[1]-position_offset[1]) + wire_rightTop_pos = (center[0]+position_offset[0], center[1]-position_offset[1]-ysize) + wire_leftTop_pos = (center[0]-position_offset[0], center[1]-position_offset[1]-ysize) c.add_polygon( [ - (center[0]-position_offset[0], center[1]-position_offset[1]), - (center[0]+position_offset[0], center[1]-position_offset[1]), - (center[0]+position_offset[0], center[1]-position_offset[1]-ysize), - (center[0]-position_offset[0], center[1]-position_offset[1]-ysize) + wire_leftBottom_pos, + wire_rightBottom_pos, + wire_rightTop_pos, + wire_leftTop_pos ], layer=layer ) - comp.add_port(name=f"{label}_W", center=[0, ysize / 2], width=ysize, orientation=0, layer=layer) - comp.add_port(name=f"{label}_E", center=[xsize, ysize / 2], width=ysize, orientation=0, layer=layer) - c.add_label(text=f"{label}_W", position=(c.x-xsize/2, c.y), layer=layer) - c.add_label(text=f"{label}_E", position=(c.x+xsize/2, c.y), layer=layer) - + + port_W_pos = (c.x-xsize/2, c.y) + port_E_pos = (c.x+xsize/2, c.y) + c.add_port(name=f"{port_label}_W", center=port_W_pos, width=ysize, orientation=0, layer=layer) + c.add_port(name=f"{port_label}_E", center=port_E_pos, width=ysize, orientation=0, layer=layer) + c.add_label(text=f"{port_label}_W", position=port_W_pos, layer=layer) + c.add_label(text=f"{port_label}_E", position=port_E_pos, layer=layer) return c +def port_with_pin(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ], port_feature: dict[str, str]) -> Component: + # Add pins and text labels for LVS + pins_labels_info = list() # list that contains all port and component information + for port in port_list: + ref_port_layer = comp.ports[ port["ref_port"] ].layer[0] # To get the layer's data type mapped to the GDS. + # [0]: layer mapping, [1]: pin, drawing, label, net, etc. + print(f"Port: {port}") + + # To create the pin w/ a label + new_port_layer = pdk.get_glayer(port_feature["layer"]) + new_port_layerPin = (new_port_layer[0], 16) # layer[1]=16 mapped to the "pin" datatype in the GDS + new_port_layerLabel = (new_port_layer[0], 5) # layer[1]=5 mapped to the "label" datatype in the GDS + new_port_layerDraw = pdk.get_glayer(port_feature["layer"]) + + new_pin_width = pdk.get_grule(port_feature["layer"])["min_width"] + new_port = rectangle(layer=new_port_layerPin, size=(new_pin_width, new_pin_width),centered=True).copy() # To set rectangle's centroid to the relative (0, 0) + new_port.add_label(text=port["new_port_label"], layer=new_port_layerLabel) + + # To align the new port with the designated port existing in the given component + alignment = port["ref_port_align"] + comp_ref = align_comp_to_port(custom_comp=new_port, align_to=comp.ports[ port["ref_port"] ], alignment=alignment) + comp.add(comp_ref) + comp_ref.movex(port["new_port_move"][0]) + comp_ref.movey(port["new_port_move"][1]) + + if port["new_port_via"] == True: + new_port_via = via_stack(pdk=pdk, glayer1=port["new_port_via_layers"][0], glayer2=port["new_port_via_layers"][1]) + new_port_via_ref = comp.add_ref(new_port_via) + new_port_via_ref.movex(comp_ref.center[0]) + new_port_via_ref.movey(comp_ref.center[1]) + + # To register the new port as an external I/O port of the top-level component + comp.add_port(name=port["new_port"], center=new_port.center, width=new_pin_width, orientation=0, layer=new_port_layerDraw) + + return comp + +def port_with_wire(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ], port_feature: dict[str, str]) -> Component: + new_port_layer = pdk.get_glayer(port_feature["layer"]) + wire_width = comp.xsize + wire_height = pdk.get_grule(port_feature["layer"])["min_width"] + new_port_center = comp.center + new_port_position_offset = (comp.xsize/2, comp.ysize/2+pdk.util_max_metal_seperation()) + wire_spacing = pdk.get_grule(port_feature["layer"])["min_separation"]+wire_height + port_cnt = 0 + + # Add pins and text labels for LVS + pins_labels_info = list() # list that contains all port and component information + print(f"port_list: {port_list}") + for port in port_list: + # To create the pin where the layer[1] is mapped to 16 + connect_pos = port["connect_pos"] if "connect_pos" in port else "W" + new_wire = add_wire(comp=comp, xsize=wire_width, ysize=wire_height, layer=new_port_layer, port_label=port["new_port_label"], center=new_port_center, position_offset=new_port_position_offset) + new_wire_ref = comp.add_ref(new_wire) + new_wire_ref.movey(-wire_spacing*port_cnt) + comp.add_ports(new_wire_ref.get_ports_list()) # To register all the ports in the wire to the underlying component + edge0 = comp.ports.get(port["ref_port"]) + edge1 = comp.ports.get(port["new_port"]+f"_{connect_pos}") + comp << smart_route(pdk, edge0, edge1) + + port_cnt = port_cnt + 1 # Increment the index indicating the new port + + return comp + def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ], port_feature: dict[str, str]) -> Component: ''' To add external I/O ports onto the cell for LVS @@ -47,16 +118,16 @@ def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Uni { "new_port": "drain_new", "new_port_label": "drain_new_label", - "pin_width": 0.5, - "pin_height": 0.5, + "pin_width": 0.5, # -> Only being used when "port_feature": "pin" + "pin_height": 0.5, # -> Only being used when "port_feature": "pin" "ref_port": "multiplier_0_drain_E" }, { "new_port": "source_new", "new_port_label": "source_new_label", - "pin_width": 1.5, - "pin_height": 1.5, - "ref_port": "multiplier_0_source_E" + "ref_port": "multiplier_0_source_E", + "connect_pos": "W" # -> for all connect_pos in {W, E} where the + # connect_pos will be set to "W" if connect_pos=None } ) # port_feature: a "dict"-type primitive specifying the feature of the new port, e.g. @@ -72,45 +143,13 @@ def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Uni if port_feature["port_type"] == "pin": port_type = 0 elif port_feature["port_type"] == "wire": - new_port_layer = pdk.get_glayer(port_feature["layer"]) port_type = 1 - wire_width = comp.xsize - wire_height = pdk.get_grule(port_feature["layer"])["min_width"] - new_port_center = comp.center - new_port_position_offset = (comp.xsize/2, comp.ysize/2+pdk.util_max_metal_seperation()) - wire_spacing = pdk.get_grule(port_feature["layer"])["min_separation"]+wire_height - port_cnt = 0 else: raise ValueError("The port type must be either pin or wire") if port_type == 0: # port of which features pin-added type - # Add pins and text labels for LVS - pins_labels_info = list() # list that contains all port and component information - print(f"port_list: {port_list}") - for port in port_list: - # To get the layer's data type mapped to the GDS - ref_port_layer = comp.ports[ port["ref_port"] ].layer[0] # [0]: layer mapping, [1]: pin, drawing, label, net, etc. - - # To create the pin w/ a label where the layer[1] is mapped to 16 - new_port = rectangle(layer=(ref_port_layer, 16), size=(port["pin_width"], port["pin_height"]),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) - new_port.add_label(text=port["new_port_label"], layer=(ref_port_layer, 5)) # layer[1]=5 mapped to the "label" datatype in the GDS - - # To align the new port with the designated port existing in the given component - alignment = ('c', 'b') - comp_ref = align_comp_to_port(new_port, comp.ports[ port["ref_port"] ], alignment=alignment) - comp.add(comp_ref) - + port_with_pin(pdk=pdk, comp=comp, port_list=port_list, port_feature=port_feature) else: # port_type=1, i.e. port of which features wire_only - # Add pins and text labels for LVS - pins_labels_info = list() # list that contains all port and component information - print(f"port_list: {port_list}") - for port in port_list: - # To create the pin where the layer[1] is mapped to 16 - new_port = add_wire(comp=comp, xsize=wire_width, ysize=wire_height, layer=new_port_layer, label=port["new_port_label"], center=new_port_center, position_offset=new_port_position_offset) - new_port_ref = comp.add_ref(new_port) - new_port_ref.movey(-wire_spacing*port_cnt) - comp << smart_route(pdk, comp.ports.get(port["ref_port"]), comp.ports.get(port["new_port"]+"_E")) - - port_cnt = port_cnt + 1 # Increment the index indicating the new port + port_with_wire(pdk=pdk, comp=comp, port_list=port_list, port_feature=port_feature) return comp \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index 72a32a73a..0576b7653 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -3,8 +3,10 @@ from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 import cell_config as config +TARGET_PDK = sky130 + def main(): - tg_inst = tg.tg_with_inv(pdk=sky130, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15) + tg_inst = tg.tg_with_inv(pdk=TARGET_PDK, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15) tg_inst = config.add_port_lvs( pdk=sky130, comp=tg_inst, @@ -12,26 +14,26 @@ def main(): { "new_port": "Vctrl", "new_port_label": "Vctrl", - "pin_width": tg_inst.ports["inv_nmos_multiplier_0_gate_S"].width, - "pin_height": tg_inst.ports["inv_nmos_multiplier_0_gate_S"].width, - "ref_port": "inv_nmos_multiplier_0_gate_S" - }, - { - "new_port": "Vin", - "new_port_label": "Vin", - "pin_width": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_source_S"].width, - "pin_height": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_source_S"].width, - "ref_port": "tg_pmos_multiplier_0_source_W" - }, - { - "new_port": "Vout", - "new_port_label": "Vout", - "pin_width": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_drain_S"].width, - "pin_height": 0.3,#tg_inst.ports["tg_nmos_multiplier_0_drain_S"].width, - "ref_port": "tg_nmos_multiplier_0_drain_N" - } + "new_port_via": True, + "new_port_via_layers": ("met1", "met2"), + "new_port_move": (0, -TARGET_PDK.get_grule("mcon")["min_separation"]), + "ref_port": "inv_nmos_multiplier_0_gate_E", + "ref_port_align": ("c", "b"), + "connect_pos": "W" # To connce the ref_port to the "west" side of the new port + }#, + #{ + # "new_port": "Vin", + # "new_port_label": "Vin", + # "ref_port": "tg_pmos_multiplier_0_source_W" + #}, + #{ + # "new_port": "Vout", + # "new_port_label": "Vout", + # "ref_port": "tg_nmos_multiplier_0_drain_W", + # "connect_pos": "E" # To connect the ref_port to the "east" side of the new port + #} ], - port_feature = {"port_type":"wire", "layer":"met2"} # met2 is actually mapped to met1 in sky130 proceess + port_feature = {"port_type":"pin", "layer":"met1"} # met1 is actually mapped to li1 in sky130 proceess ) #tg_inst.flatten() tg_inst.show() diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py index 6a1347ced..1692dabbe 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py @@ -34,8 +34,8 @@ def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_w pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) # Routing - top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_E"]) - top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_gate_W"], nfet_ref.ports["multiplier_0_gate_W"]) + top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met1") # connected by li1 + top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_gate_W"], nfet_ref.ports["multiplier_0_gate_W"] , glayer1="met1") # connected by li1 # To add the ports top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index 654e4a93f..06b0313d3 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -129,8 +129,8 @@ def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_ # 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 << smart_route(pdk, pfet_ref.ports["multiplier_0_source_E"], nfet_ref.ports["multiplier_0_source_E"]) # "in" of the TG - top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_drain_E"]) # "out" of the TG + top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_source_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met2") # "in" of the TG + top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_source_E"], glayer1="met1") # "out" of the TG top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") @@ -192,7 +192,7 @@ def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length # 1) PMOS of the TG is switched on/off by the inverter's output # 2) NMOS of the TG is switched on/off by an external control signal connected to inverter's input port as well top_level << smart_route(pdk, inv_ref.ports["pmos_multiplier_0_drain_E"], tg_ref.ports["pmos_multiplier_0_gate_W"]) - top_level << smart_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_S"], tg_ref.ports["nmos_multiplier_0_gate_S"]) + top_level << straight_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_S"], tg_ref.ports["nmos_multiplier_0_gate_S"]) # Adding the ports top_level.add_ports(tg_ref.get_ports_list(), prefix="tg_") From 6d8e8befd101fed744edae19bee0168763320150 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 17 Nov 2024 08:32:09 +0000 Subject: [PATCH 14/21] Add the external pins for the LVS process --- .../blocks/transmission_gate_saltychip/transmission_gate.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index 06b0313d3..5757be092 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -192,7 +192,7 @@ def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length # 1) PMOS of the TG is switched on/off by the inverter's output # 2) NMOS of the TG is switched on/off by an external control signal connected to inverter's input port as well top_level << smart_route(pdk, inv_ref.ports["pmos_multiplier_0_drain_E"], tg_ref.ports["pmos_multiplier_0_gate_W"]) - top_level << straight_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_S"], tg_ref.ports["nmos_multiplier_0_gate_S"]) + top_level << straight_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_S"], tg_ref.ports["nmos_multiplier_0_gate_S"], glayer1="met3") # Adding the ports top_level.add_ports(tg_ref.get_ports_list(), prefix="tg_") From c75a0a5540f14fad6c478eb8c7f1c224d034831e Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 17 Nov 2024 14:45:27 +0000 Subject: [PATCH 15/21] Team: Salty Chip, Chipathon2024 Fix the DRC error by removing the deep N-well on the NMOS of the inv cell which is used as the control component for the underlying transmission gate --- .../cell_config.py | 155 -- .../transmission_gate_saltychip/eval.py | 50 +- .../transmission_gate_saltychip/inv_lib.py | 44 - .../reconfig_inv.py | 76 + .../transmission_gate_saltychip/tg_gen.ipynb | 2326 ----------------- .../transmission_gate.py | 144 +- 6 files changed, 113 insertions(+), 2682 deletions(-) delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py delete mode 100755 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py create mode 100755 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py deleted file mode 100644 index 41b1ea28a..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/cell_config.py +++ /dev/null @@ -1,155 +0,0 @@ -from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict -#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 gdsfactory import Component -from gdsfactory.components import rectangle -from glayout.flow.primitives.fet import pmos -from glayout.flow.primitives.fet import nmos -from glayout.flow.primitives.via_gen import via_stack -from glayout.flow.routing.straight_route import straight_route -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.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port - -# Status: W.I.P. -def add_wire(comp, xsize=2, ysize=1, layer=(68, 20), port_label="new_wire", center=(0, 0), position_offset=(1.4, 1.4)): - c = Component() - wire_leftBottom_pos = (center[0]-position_offset[0], center[1]-position_offset[1]) - wire_rightBottom_pos = (center[0]+position_offset[0], center[1]-position_offset[1]) - wire_rightTop_pos = (center[0]+position_offset[0], center[1]-position_offset[1]-ysize) - wire_leftTop_pos = (center[0]-position_offset[0], center[1]-position_offset[1]-ysize) - c.add_polygon( - [ - wire_leftBottom_pos, - wire_rightBottom_pos, - wire_rightTop_pos, - wire_leftTop_pos - ], - layer=layer - ) - - port_W_pos = (c.x-xsize/2, c.y) - port_E_pos = (c.x+xsize/2, c.y) - c.add_port(name=f"{port_label}_W", center=port_W_pos, width=ysize, orientation=0, layer=layer) - c.add_port(name=f"{port_label}_E", center=port_E_pos, width=ysize, orientation=0, layer=layer) - c.add_label(text=f"{port_label}_W", position=port_W_pos, layer=layer) - c.add_label(text=f"{port_label}_E", position=port_E_pos, layer=layer) - return c - -def port_with_pin(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ], port_feature: dict[str, str]) -> Component: - # Add pins and text labels for LVS - pins_labels_info = list() # list that contains all port and component information - for port in port_list: - ref_port_layer = comp.ports[ port["ref_port"] ].layer[0] # To get the layer's data type mapped to the GDS. - # [0]: layer mapping, [1]: pin, drawing, label, net, etc. - print(f"Port: {port}") - - # To create the pin w/ a label - new_port_layer = pdk.get_glayer(port_feature["layer"]) - new_port_layerPin = (new_port_layer[0], 16) # layer[1]=16 mapped to the "pin" datatype in the GDS - new_port_layerLabel = (new_port_layer[0], 5) # layer[1]=5 mapped to the "label" datatype in the GDS - new_port_layerDraw = pdk.get_glayer(port_feature["layer"]) - - new_pin_width = pdk.get_grule(port_feature["layer"])["min_width"] - new_port = rectangle(layer=new_port_layerPin, size=(new_pin_width, new_pin_width),centered=True).copy() # To set rectangle's centroid to the relative (0, 0) - new_port.add_label(text=port["new_port_label"], layer=new_port_layerLabel) - - # To align the new port with the designated port existing in the given component - alignment = port["ref_port_align"] - comp_ref = align_comp_to_port(custom_comp=new_port, align_to=comp.ports[ port["ref_port"] ], alignment=alignment) - comp.add(comp_ref) - comp_ref.movex(port["new_port_move"][0]) - comp_ref.movey(port["new_port_move"][1]) - - if port["new_port_via"] == True: - new_port_via = via_stack(pdk=pdk, glayer1=port["new_port_via_layers"][0], glayer2=port["new_port_via_layers"][1]) - new_port_via_ref = comp.add_ref(new_port_via) - new_port_via_ref.movex(comp_ref.center[0]) - new_port_via_ref.movey(comp_ref.center[1]) - - # To register the new port as an external I/O port of the top-level component - comp.add_port(name=port["new_port"], center=new_port.center, width=new_pin_width, orientation=0, layer=new_port_layerDraw) - - return comp - -def port_with_wire(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ], port_feature: dict[str, str]) -> Component: - new_port_layer = pdk.get_glayer(port_feature["layer"]) - wire_width = comp.xsize - wire_height = pdk.get_grule(port_feature["layer"])["min_width"] - new_port_center = comp.center - new_port_position_offset = (comp.xsize/2, comp.ysize/2+pdk.util_max_metal_seperation()) - wire_spacing = pdk.get_grule(port_feature["layer"])["min_separation"]+wire_height - port_cnt = 0 - - # Add pins and text labels for LVS - pins_labels_info = list() # list that contains all port and component information - print(f"port_list: {port_list}") - for port in port_list: - # To create the pin where the layer[1] is mapped to 16 - connect_pos = port["connect_pos"] if "connect_pos" in port else "W" - new_wire = add_wire(comp=comp, xsize=wire_width, ysize=wire_height, layer=new_port_layer, port_label=port["new_port_label"], center=new_port_center, position_offset=new_port_position_offset) - new_wire_ref = comp.add_ref(new_wire) - new_wire_ref.movey(-wire_spacing*port_cnt) - comp.add_ports(new_wire_ref.get_ports_list()) # To register all the ports in the wire to the underlying component - edge0 = comp.ports.get(port["ref_port"]) - edge1 = comp.ports.get(port["new_port"]+f"_{connect_pos}") - comp << smart_route(pdk, edge0, edge1) - - port_cnt = port_cnt + 1 # Increment the index indicating the new port - - return comp - -def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ], port_feature: dict[str, str]) -> Component: - ''' - To add external I/O ports onto the cell for LVS - - @ args: - # pdk: please refer to the glayout library - # comp: please refer to the glayout library - # port_list: tuple[ dict[str, Union[float, str]] ] specifying new port's corresponding pin size, and - the name of new port and exiting port managed to align with in the given - component, e.g. - ( - { - "new_port": "drain_new", - "new_port_label": "drain_new_label", - "pin_width": 0.5, # -> Only being used when "port_feature": "pin" - "pin_height": 0.5, # -> Only being used when "port_feature": "pin" - "ref_port": "multiplier_0_drain_E" - }, - { - "new_port": "source_new", - "new_port_label": "source_new_label", - "ref_port": "multiplier_0_source_E", - "connect_pos": "W" # -> for all connect_pos in {W, E} where the - # connect_pos will be set to "W" if connect_pos=None - } - ) - # port_feature: a "dict"-type primitive specifying the feature of the new port, e.g. - {"port_type":"pin", "layer":None} -> To create a rectangle as the new port - {"port_type":"wire", "layer":"met1"} -> To extend the existing port by a wire only - - # return: gdsfactory.Component - - @ Limitations: - # So far, only skywater130 process is validated - ''' - - if port_feature["port_type"] == "pin": - port_type = 0 - elif port_feature["port_type"] == "wire": - port_type = 1 - else: - raise ValueError("The port type must be either pin or wire") - - if port_type == 0: # port of which features pin-added type - port_with_pin(pdk=pdk, comp=comp, port_list=port_list, port_feature=port_feature) - else: # port_type=1, i.e. port of which features wire_only - port_with_wire(pdk=pdk, comp=comp, port_list=port_list, port_feature=port_feature) - - return comp \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index 0576b7653..5720c73ae 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -1,43 +1,29 @@ import transmission_gate as tg #from glayout.flow.pdk.gf180_mapped import gf180 from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 -import cell_config as config +import reconfig_inv as reconfig_inv TARGET_PDK = sky130 def main(): - tg_inst = tg.tg_with_inv(pdk=TARGET_PDK, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15) - tg_inst = config.add_port_lvs( - pdk=sky130, - comp=tg_inst, - port_list=[ - { - "new_port": "Vctrl", - "new_port_label": "Vctrl", - "new_port_via": True, - "new_port_via_layers": ("met1", "met2"), - "new_port_move": (0, -TARGET_PDK.get_grule("mcon")["min_separation"]), - "ref_port": "inv_nmos_multiplier_0_gate_E", - "ref_port_align": ("c", "b"), - "connect_pos": "W" # To connce the ref_port to the "west" side of the new port - }#, - #{ - # "new_port": "Vin", - # "new_port_label": "Vin", - # "ref_port": "tg_pmos_multiplier_0_source_W" - #}, - #{ - # "new_port": "Vout", - # "new_port_label": "Vout", - # "ref_port": "tg_nmos_multiplier_0_drain_W", - # "connect_pos": "E" # To connect the ref_port to the "east" side of the new port - #} - ], - port_feature = {"port_type":"pin", "layer":"met1"} # met1 is actually mapped to li1 in sky130 proceess + gate_ctrl_inv = reconfig_inv.reconfig_inv( + pdk=TARGET_PDK, + component_name="gate_ctrl_inv", + pmos_width=1, + pmos_length=0.15, + nmos_width=1, + nmos_length=0.15, + orientation="horizontal" ) - #tg_inst.flatten() - tg_inst.show() - #tg_inst.write_gds("gds/tg_with_inv.gds") + gate_ctrl_inv.show() + gate_ctrl_inv.write_gds("/home/tsengs0/gate_ctrl_inv.gds") + + magic_drc_result = sky130.drc_magic( + layout=gate_ctrl_inv, + design_name=gate_ctrl_inv.name#, + #output_file=f"{absolute_path}/{gate_ctrl_inv.name}.rpt" + ) + print("Magic DRC result: \n", magic_drc_result) if __name__ == "__main__": main() \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py deleted file mode 100755 index 1692dabbe..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/inv_lib.py +++ /dev/null @@ -1,44 +0,0 @@ -#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 prec_ref_center, movex, movey, evaluate_bbox, align_comp_to_port -from gdsfactory import Component -from gdsfactory.components import rectangle -from glayout.flow.primitives.fet import pmos -from glayout.flow.primitives.fet import nmos -from glayout.flow.routing.straight_route import straight_route -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 - -def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_width, nmos_length, orientation): - # Create a top level component - top_level = Component(component_name) - # To prepare one PMOS and one NMOS for the subsequent inverter cell construction - pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length) - nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length) - - # Instantiation of above PMOS and NMOS under the top level - pfet_ref = prec_ref_center(pfet) - nfet_ref = prec_ref_center(nfet) - top_level.add(pfet_ref) - top_level.add(nfet_ref) - - # Placement (relative move) - mos_spacing = pdk.util_max_metal_seperation() - if(orientation=="horizontal"): - pfet_ref.rotate(90) - nfet_ref.rotate(90) - else: - pass - pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) - - # Routing - top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met1") # connected by li1 - top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_gate_W"], nfet_ref.ports["multiplier_0_gate_W"] , glayer1="met1") # connected by li1 - - # To add the ports - top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") - top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - - return top_level diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py new file mode 100755 index 000000000..93ccdc341 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py @@ -0,0 +1,76 @@ +#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 prec_ref_center, movex, movey, evaluate_bbox, align_comp_to_port +from gdsfactory import Component +from gdsfactory.components import rectangle +from glayout.flow.primitives.fet import pmos +from glayout.flow.primitives.fet import nmos +from glayout.flow.routing.straight_route import straight_route +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 + +#@cell +def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_width, nmos_length, orientation): + # Create a top level component + top_level = Component(component_name) + # To prepare one PMOS and one NMOS for the subsequent inverter cell construction + pfet = pmos(pdk=pdk, gate_rmult=2, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, gate_rmult=2, with_dnwell=False, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length) + pfet.name="pmos" + nfet.name="nmos" + + # Instantiation of above PMOS and NMOS under the top level + pfet_ref = prec_ref_center(pfet) + nfet_ref = prec_ref_center(nfet) + top_level.add(pfet_ref) + top_level.add(nfet_ref) + + # Placement (relative move) + mos_spacing = pdk.util_max_metal_seperation(metal_levels=("met1", "met2", "met3", "met4", "met5")) + if(orientation=="horizontal"): + pfet_ref.rotate(90) + nfet_ref.rotate(90) + else: + pass + pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) + + # Routing + top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met2") # connected by li1 + input_route = top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_gate_W"], nfet_ref.ports["multiplier_0_gate_W"] , glayer1="met2") # connected by li1 + + # To add the ports + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + + # Add pins w/ labels for LVS + top_level.unlock() + pin_info = list() # list that contains all port and component information + met1_pin=(pdk.get_glayer("met1")[0], 20) + met1_label=(pdk.get_glayer("met1")[0], 5) + port_size = (0.24, 0.24) + # --- Port: A, i.e. input of the inverter + 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_gate_E"), None)) + # --- Port: Y, i.e. output of the inverver + 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_E"), None)) + # --- Port: VDD + VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VDD_pin.add_label(text="VDD", layer=met1_label) + pin_info.append((VDD_pin, top_level.ports.get(f"pmos_drain_E"), None)) + # --- Port: VSS + VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VSS_pin.add_label(text="VSS", layer=met1_label) + pin_info.append((VSS_pin, top_level.ports.get(f"nmos_source_W"), ('r', 't'))) + + # Move everythin to position + for comp, prt, alignment in pin_info: + alignment = ('c', 'b') if alignment is None else alignment + comp_ref = align_comp_to_port(comp, prt, alignment=alignment) + top_level.add(comp_ref) + + return top_level diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb deleted file mode 100644 index 45d4fc14b..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/tg_gen.ipynb +++ /dev/null @@ -1,2326 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "provenance": [], - "include_colab_link": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "view-in-github", - "colab_type": "text" - }, - "source": [ - "\"Open" - ] - }, - { - "cell_type": "markdown", - "source": [ - "#Chipathon2024 SaltyChip Group\n", - "##テグさんのトランスミッションゲートをnotebbokで表示されるようにしてみた。\n", - "最初にOpenFASoCをクーロンして、sky130、gf180、gdsfactoryをインストールします。\n", - "micromambaを使ったバイナリ依存klayoutをインストールします。\n", - "\n", - "\n", - "\n", - "* Chipathon2024 GitHub:\n", - "https://github.com/sscs-ose/sscs-ose-chipathon.github.io\n", - "\n", - "\n", - "\n", - "\n", - "\n" - ], - "metadata": { - "id": "o2n-cd6kYdjt" - } - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 1000 - }, - "id": "2fBvSrYFYB1K", - "outputId": "90eb55c6-a4e2-42cf-966d-e79c278aaf28" - }, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Cloning into 'OpenFASOC'...\n", - "remote: Enumerating objects: 16501, done.\u001b[K\n", - "remote: Counting objects: 100% (3739/3739), done.\u001b[K\n", - "remote: Compressing objects: 100% (549/549), done.\u001b[K\n", - "remote: Total 16501 (delta 3311), reused 3398 (delta 3185), pack-reused 12762 (from 1)\u001b[K\n", - "Receiving objects: 100% (16501/16501), 410.32 MiB | 20.14 MiB/s, done.\n", - "Resolving deltas: 100% (10104/10104), done.\n", - "Updating files: 100% (1849/1849), done.\n", - "Collecting sky130\n", - " Downloading sky130-0.12.2-py3-none-any.whl.metadata (1.6 kB)\n", - "Collecting gdsfactory~=8.5.2 (from sky130)\n", - " Downloading gdsfactory-8.5.6-py3-none-any.whl.metadata (11 kB)\n", - "Collecting PySpice (from sky130)\n", - " Downloading PySpice-1.5-py2.py3-none-any.whl.metadata (15 kB)\n", - "Requirement already satisfied: jinja2<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.1.4)\n", - "Collecting loguru<1 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading loguru-0.7.2-py3-none-any.whl.metadata (23 kB)\n", - "Requirement already satisfied: matplotlib<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.8.0)\n", - "Requirement already satisfied: numpy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (1.26.4)\n", - "Collecting omegaconf<3 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading omegaconf-2.3.0-py3-none-any.whl.metadata (3.9 kB)\n", - "Requirement already satisfied: orjson<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.10.11)\n", - "Requirement already satisfied: pandas<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (2.2.2)\n", - "Collecting pydantic<2.9,>=2.8.2 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading pydantic-2.8.2-py3-none-any.whl.metadata (125 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m125.2/125.2 kB\u001b[0m \u001b[31m8.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hCollecting pydantic-settings<3 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading pydantic_settings-2.6.1-py3-none-any.whl.metadata (3.5 kB)\n", - "Collecting pydantic-extra-types<3 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading pydantic_extra_types-2.10.0-py3-none-any.whl.metadata (3.5 kB)\n", - "Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (6.0.2)\n", - "Collecting qrcode (from gdsfactory~=8.5.2->sky130)\n", - " Downloading qrcode-8.0-py3-none-any.whl.metadata (17 kB)\n", - "Collecting rectpack<1 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading rectpack-0.2.2.tar.gz (17 kB)\n", - " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - "Requirement already satisfied: rich<14 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (13.9.4)\n", - "Requirement already satisfied: scipy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (1.13.1)\n", - "Requirement already satisfied: shapely<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (2.0.6)\n", - "Requirement already satisfied: toolz<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (0.12.1)\n", - "Collecting types-PyYAML (from gdsfactory~=8.5.2->sky130)\n", - " Downloading types_PyYAML-6.0.12.20240917-py3-none-any.whl.metadata (1.6 kB)\n", - "Requirement already satisfied: typer<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (0.13.0)\n", - "Collecting watchdog<5 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl.metadata (38 kB)\n", - "Collecting kfactory~=0.18.0 (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", - " Downloading kfactory-0.18.4-py3-none-any.whl.metadata (4.4 kB)\n", - "Collecting freetype-py (from gdsfactory~=8.5.2->sky130)\n", - " Downloading freetype_py-2.5.1-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl.metadata (6.3 kB)\n", - "Collecting mapbox_earcut (from gdsfactory~=8.5.2->sky130)\n", - " Downloading mapbox_earcut-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.1 kB)\n", - "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (3.4.2)\n", - "Requirement already satisfied: scikit-image in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (0.24.0)\n", - "Collecting trimesh<4.5,>=4.4.1 (from gdsfactory~=8.5.2->sky130)\n", - " Downloading trimesh-4.4.9-py3-none-any.whl.metadata (18 kB)\n", - "Requirement already satisfied: ipykernel in /usr/local/lib/python3.10/dist-packages (from gdsfactory~=8.5.2->sky130) (5.5.6)\n", - "Requirement already satisfied: cffi>=1.14 in /usr/local/lib/python3.10/dist-packages (from PySpice->sky130) (1.17.1)\n", - "Collecting ply>=3.11 (from PySpice->sky130)\n", - " Downloading ply-3.11-py2.py3-none-any.whl.metadata (844 bytes)\n", - "Requirement already satisfied: requests>=2.23 in /usr/local/lib/python3.10/dist-packages (from PySpice->sky130) (2.32.3)\n", - "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi>=1.14->PySpice->sky130) (2.22)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2<4->gdsfactory~=8.5.2->sky130) (3.0.2)\n", - "Collecting aenum (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", - " Downloading aenum-3.1.15-py3-none-any.whl.metadata (3.7 kB)\n", - "Requirement already satisfied: cachetools>=5.2.0 in /usr/local/lib/python3.10/dist-packages (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (5.5.0)\n", - "Requirement already satisfied: gitpython in /usr/local/lib/python3.10/dist-packages (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.1.43)\n", - "Collecting klayout>=0.29.3 (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", - " Downloading klayout-0.29.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (782 bytes)\n", - "Collecting rectangle-packer (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", - " Downloading rectangle_packer-2.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (5.4 kB)\n", - "Collecting ruamel.yaml (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", - " Downloading ruamel.yaml-0.18.6-py3-none-any.whl.metadata (23 kB)\n", - "Requirement already satisfied: tomli in /usr/local/lib/python3.10/dist-packages (from kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.0.2)\n", - "\u001b[33mWARNING: kfactory 0.18.4 does not provide the extra 'git'\u001b[0m\u001b[33m\n", - "\u001b[0mRequirement already satisfied: ipython in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (7.34.0)\n", - "Requirement already satisfied: ipywidgets in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (7.7.1)\n", - "Requirement already satisfied: ipytree in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.2)\n", - "Requirement already satisfied: ipyevents in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.0.2)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (1.3.0)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (4.54.1)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (1.4.7)\n", - "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (24.2)\n", - "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (11.0.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (3.2.0)\n", - "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory~=8.5.2->sky130) (2.8.2)\n", - "Collecting antlr4-python3-runtime==4.9.* (from omegaconf<3->gdsfactory~=8.5.2->sky130)\n", - " Downloading antlr4-python3-runtime-4.9.3.tar.gz (117 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m117.0/117.0 kB\u001b[0m \u001b[31m10.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25h Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory~=8.5.2->sky130) (2024.2)\n", - "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory~=8.5.2->sky130) (2024.2)\n", - "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<2.9,>=2.8.2->gdsfactory~=8.5.2->sky130) (0.7.0)\n", - "Collecting pydantic-core==2.20.1 (from pydantic<2.9,>=2.8.2->gdsfactory~=8.5.2->sky130)\n", - " Downloading pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.6 kB)\n", - "Requirement already satisfied: typing-extensions>=4.6.1 in /usr/local/lib/python3.10/dist-packages (from pydantic<2.9,>=2.8.2->gdsfactory~=8.5.2->sky130) (4.12.2)\n", - "Collecting python-dotenv>=0.21.0 (from pydantic-settings<3->gdsfactory~=8.5.2->sky130)\n", - " Downloading python_dotenv-1.0.1-py3-none-any.whl.metadata (23 kB)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (3.4.0)\n", - "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (3.10)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (2.2.3)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests>=2.23->PySpice->sky130) (2024.8.30)\n", - "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory~=8.5.2->sky130) (3.0.0)\n", - "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory~=8.5.2->sky130) (2.18.0)\n", - "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory~=8.5.2->sky130) (8.1.7)\n", - "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory~=8.5.2->sky130) (1.5.4)\n", - "Requirement already satisfied: ipython-genutils in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (0.2.0)\n", - "Requirement already satisfied: traitlets>=4.1.0 in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (5.7.1)\n", - "Requirement already satisfied: jupyter-client in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (6.1.12)\n", - "Requirement already satisfied: tornado>=4.2 in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory~=8.5.2->sky130) (6.3.3)\n", - "Requirement already satisfied: imageio>=2.33 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory~=8.5.2->sky130) (2.36.0)\n", - "Requirement already satisfied: tifffile>=2022.8.12 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory~=8.5.2->sky130) (2024.9.20)\n", - "Requirement already satisfied: lazy-loader>=0.4 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory~=8.5.2->sky130) (0.4)\n", - "Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (75.1.0)\n", - "Collecting jedi>=0.16 (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", - " Downloading jedi-0.19.2-py2.py3-none-any.whl.metadata (22 kB)\n", - "Requirement already satisfied: decorator in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.4.2)\n", - "Requirement already satisfied: pickleshare in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.7.5)\n", - "Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.0.48)\n", - "Requirement already satisfied: backcall in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.0)\n", - "Requirement already satisfied: matplotlib-inline in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.1.7)\n", - "Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.9.0)\n", - "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich<14->gdsfactory~=8.5.2->sky130) (0.1.2)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib<4->gdsfactory~=8.5.2->sky130) (1.16.0)\n", - "Requirement already satisfied: gitdb<5,>=4.0.1 in /usr/local/lib/python3.10/dist-packages (from gitpython->kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.0.11)\n", - "Requirement already satisfied: widgetsnbextension~=3.6.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.6.10)\n", - "Requirement already satisfied: jupyterlab-widgets>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.0.13)\n", - "Requirement already satisfied: jupyter-core>=4.6.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory~=8.5.2->sky130) (5.7.2)\n", - "Requirement already satisfied: pyzmq>=13 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory~=8.5.2->sky130) (24.0.1)\n", - "Collecting ruamel.yaml.clib>=0.2.7 (from ruamel.yaml->kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130)\n", - " Downloading ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (2.7 kB)\n", - "\u001b[33mWARNING: typer 0.13.0 does not provide the extra 'all'\u001b[0m\u001b[33m\n", - "\u001b[0mRequirement already satisfied: smmap<6,>=3.0.1 in /usr/local/lib/python3.10/dist-packages (from gitdb<5,>=4.0.1->gitpython->kfactory~=0.18.0->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (5.0.1)\n", - "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /usr/local/lib/python3.10/dist-packages (from jedi>=0.16->ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.8.4)\n", - "Requirement already satisfied: platformdirs>=2.5 in /usr/local/lib/python3.10/dist-packages (from jupyter-core>=4.6.0->jupyter-client->ipykernel->gdsfactory~=8.5.2->sky130) (4.3.6)\n", - "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.10/dist-packages (from pexpect>4.3->ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.7.0)\n", - "Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/dist-packages (from prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0->ipython->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.13)\n", - "Requirement already satisfied: notebook>=4.4.1 in /usr/local/lib/python3.10/dist-packages (from widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (6.5.5)\n", - "Requirement already satisfied: argon2-cffi in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (23.1.0)\n", - "Requirement already satisfied: nbformat in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (5.10.4)\n", - "Requirement already satisfied: nbconvert>=5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (7.16.4)\n", - "Requirement already satisfied: nest-asyncio>=1.5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.6.0)\n", - "Requirement already satisfied: Send2Trash>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.8.3)\n", - "Requirement already satisfied: terminado>=0.8.3 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.18.1)\n", - "Requirement already satisfied: prometheus-client in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.21.0)\n", - "Requirement already satisfied: nbclassic>=0.4.7 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.1.0)\n", - "Requirement already satisfied: notebook-shim>=0.2.3 in /usr/local/lib/python3.10/dist-packages (from nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.2.4)\n", - "Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.12.3)\n", - "Requirement already satisfied: bleach!=5.0.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (6.2.0)\n", - "Requirement already satisfied: defusedxml in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.7.1)\n", - "Requirement already satisfied: jupyterlab-pygments in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.3.0)\n", - "Requirement already satisfied: mistune<4,>=2.0.3 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.0.2)\n", - "Requirement already satisfied: nbclient>=0.5.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.10.0)\n", - "Requirement already satisfied: pandocfilters>=1.4.1 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.5.1)\n", - "Requirement already satisfied: tinycss2 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.4.0)\n", - "Requirement already satisfied: fastjsonschema>=2.15 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.20.0)\n", - "Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (4.23.0)\n", - "Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.10/dist-packages (from argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (21.2.0)\n", - "Requirement already satisfied: webencodings in /usr/local/lib/python3.10/dist-packages (from bleach!=5.0.0->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.5.1)\n", - "Requirement already satisfied: attrs>=22.2.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (24.2.0)\n", - "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2024.10.1)\n", - "Requirement already satisfied: referencing>=0.28.4 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.35.1)\n", - "Requirement already satisfied: rpds-py>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (0.21.0)\n", - "Requirement already satisfied: jupyter-server<3,>=1.8 in /usr/local/lib/python3.10/dist-packages (from notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.24.0)\n", - "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/dist-packages (from beautifulsoup4->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (2.6)\n", - "Requirement already satisfied: anyio<4,>=3.1.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (3.7.1)\n", - "Requirement already satisfied: websocket-client in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.8.0)\n", - "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.3.1)\n", - "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->kfactory[git,ipy]~=0.18.0->gdsfactory~=8.5.2->sky130) (1.2.2)\n", - "Downloading sky130-0.12.2-py3-none-any.whl (38.2 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m38.2/38.2 MB\u001b[0m \u001b[31m10.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading gdsfactory-8.5.6-py3-none-any.whl (631 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m631.9/631.9 kB\u001b[0m \u001b[31m39.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading PySpice-1.5-py2.py3-none-any.whl (158 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m158.5/158.5 kB\u001b[0m \u001b[31m13.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading kfactory-0.18.4-py3-none-any.whl (147 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m147.2/147.2 kB\u001b[0m \u001b[31m12.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading loguru-0.7.2-py3-none-any.whl (62 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m62.5/62.5 kB\u001b[0m \u001b[31m5.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading omegaconf-2.3.0-py3-none-any.whl (79 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m79.5/79.5 kB\u001b[0m \u001b[31m6.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading ply-3.11-py2.py3-none-any.whl (49 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m49.6/49.6 kB\u001b[0m \u001b[31m3.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading pydantic-2.8.2-py3-none-any.whl (423 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m423.9/423.9 kB\u001b[0m \u001b[31m27.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading pydantic_core-2.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.1 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.1/2.1 MB\u001b[0m \u001b[31m72.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading pydantic_extra_types-2.10.0-py3-none-any.whl (34 kB)\n", - "Downloading pydantic_settings-2.6.1-py3-none-any.whl (28 kB)\n", - "Downloading trimesh-4.4.9-py3-none-any.whl (700 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m700.1/700.1 kB\u001b[0m \u001b[31m42.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading watchdog-4.0.2-py3-none-manylinux2014_x86_64.whl (82 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m82.9/82.9 kB\u001b[0m \u001b[31m6.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading freetype_py-2.5.1-py3-none-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl (1.0 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.0/1.0 MB\u001b[0m \u001b[31m53.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading mapbox_earcut-1.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (110 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m111.0/111.0 kB\u001b[0m \u001b[31m9.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading qrcode-8.0-py3-none-any.whl (45 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m45.7/45.7 kB\u001b[0m \u001b[31m3.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading types_PyYAML-6.0.12.20240917-py3-none-any.whl (15 kB)\n", - "Downloading klayout-0.29.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (23.6 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m23.6/23.6 MB\u001b[0m \u001b[31m70.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading python_dotenv-1.0.1-py3-none-any.whl (19 kB)\n", - "Downloading aenum-3.1.15-py3-none-any.whl (137 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m137.6/137.6 kB\u001b[0m \u001b[31m11.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading rectangle_packer-2.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl (305 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m305.6/305.6 kB\u001b[0m \u001b[31m22.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading ruamel.yaml-0.18.6-py3-none-any.whl (117 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m117.8/117.8 kB\u001b[0m \u001b[31m9.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading jedi-0.19.2-py2.py3-none-any.whl (1.6 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.6/1.6 MB\u001b[0m \u001b[31m54.5 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading ruamel.yaml.clib-0.2.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (722 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m722.2/722.2 kB\u001b[0m \u001b[31m41.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hBuilding wheels for collected packages: antlr4-python3-runtime, rectpack\n", - " Building wheel for antlr4-python3-runtime (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for antlr4-python3-runtime: filename=antlr4_python3_runtime-4.9.3-py3-none-any.whl size=144555 sha256=d1fc8d45a104ab2b00078f5e1b20ce2486c797f67872640d8e1b3fd83820ae66\n", - " Stored in directory: /root/.cache/pip/wheels/12/93/dd/1f6a127edc45659556564c5730f6d4e300888f4bca2d4c5a88\n", - " Building wheel for rectpack (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for rectpack: filename=rectpack-0.2.2-py3-none-any.whl size=19333 sha256=bcb65018a8633671446a0dfe8d0cf57c940086a5715d86235221f459493048b8\n", - " Stored in directory: /root/.cache/pip/wheels/e9/ea/e9/cd0237c0ccb9cb7312bb94cc023689592c4f07e4f3b1b9dd00\n", - "Successfully built antlr4-python3-runtime rectpack\n", - "Installing collected packages: rectpack, rectangle-packer, ply, klayout, antlr4-python3-runtime, aenum, watchdog, types-PyYAML, trimesh, ruamel.yaml.clib, qrcode, python-dotenv, pydantic-core, omegaconf, mapbox_earcut, loguru, jedi, freetype-py, ruamel.yaml, pydantic, PySpice, pydantic-settings, pydantic-extra-types, kfactory, gdsfactory, sky130\n", - " Attempting uninstall: pydantic-core\n", - " Found existing installation: pydantic_core 2.23.4\n", - " Uninstalling pydantic_core-2.23.4:\n", - " Successfully uninstalled pydantic_core-2.23.4\n", - " Attempting uninstall: pydantic\n", - " Found existing installation: pydantic 2.9.2\n", - " Uninstalling pydantic-2.9.2:\n", - " Successfully uninstalled pydantic-2.9.2\n", - "Successfully installed PySpice-1.5 aenum-3.1.15 antlr4-python3-runtime-4.9.3 freetype-py-2.5.1 gdsfactory-8.5.6 jedi-0.19.2 kfactory-0.18.4 klayout-0.29.8 loguru-0.7.2 mapbox_earcut-1.0.2 omegaconf-2.3.0 ply-3.11 pydantic-2.8.2 pydantic-core-2.20.1 pydantic-extra-types-2.10.0 pydantic-settings-2.6.1 python-dotenv-1.0.1 qrcode-8.0 rectangle-packer-2.0.2 rectpack-0.2.2 ruamel.yaml-0.18.6 ruamel.yaml.clib-0.2.12 sky130-0.12.2 trimesh-4.4.9 types-PyYAML-6.0.12.20240917 watchdog-4.0.2\n" - ] - }, - { - "output_type": "display_data", - "data": { - "application/vnd.colab-display-data+json": { - "pip_warning": { - "packages": [ - "pydevd_plugins" - ] - }, - "id": "85f88f72a59f488eb4b4198dbc9cc332" - } - }, - "metadata": {} - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Collecting gf180\n", - " Downloading gf180-0.1.0-py3-none-any.whl.metadata (2.1 kB)\n", - "Collecting prettyprinttree\n", - " Downloading PrettyPrintTree-2.0.1-py3-none-any.whl.metadata (9.6 kB)\n", - "Collecting svgutils\n", - " Downloading svgutils-0.3.4-py3-none-any.whl.metadata (1.1 kB)\n", - "Collecting gdsfactory<7.17,>=7.16.0 (from gf180)\n", - " Downloading gdsfactory-7.16.0-py3-none-any.whl.metadata (11 kB)\n", - "Collecting colorama (from prettyprinttree)\n", - " Downloading colorama-0.4.6-py2.py3-none-any.whl.metadata (17 kB)\n", - "Collecting cmd2 (from prettyprinttree)\n", - " Downloading cmd2-2.5.5-py3-none-any.whl.metadata (13 kB)\n", - "Requirement already satisfied: lxml in /usr/local/lib/python3.10/dist-packages (from svgutils) (5.3.0)\n", - "Collecting flatdict (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading flatdict-4.0.1.tar.gz (8.3 kB)\n", - " Preparing metadata (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - "Collecting gdstk<0.10,>=0.9.49 (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading gdstk-0.9.57-cp310-cp310-manylinux_2_28_x86_64.whl.metadata (8.7 kB)\n", - "Requirement already satisfied: jinja2<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.1.4)\n", - "Requirement already satisfied: loguru<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.7.2)\n", - "Requirement already satisfied: matplotlib<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.8.0)\n", - "Requirement already satisfied: numpy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (1.26.4)\n", - "Requirement already satisfied: omegaconf<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.3.0)\n", - "Requirement already satisfied: orjson<4 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.10.11)\n", - "Requirement already satisfied: pandas<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.2.2)\n", - "Collecting pydantic<2.7,>=2 (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading pydantic-2.6.4-py3-none-any.whl.metadata (85 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m85.1/85.1 kB\u001b[0m \u001b[31m4.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hRequirement already satisfied: pydantic-settings<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.6.1)\n", - "Requirement already satisfied: pydantic-extra-types<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.10.0)\n", - "Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (6.0.2)\n", - "Requirement already satisfied: qrcode in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (8.0)\n", - "Requirement already satisfied: rectpack<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.2.2)\n", - "Requirement already satisfied: rich<14 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (13.9.4)\n", - "Requirement already satisfied: scipy<2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (1.13.1)\n", - "Requirement already satisfied: shapely<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.0.6)\n", - "Requirement already satisfied: toolz<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.12.1)\n", - "Requirement already satisfied: types-PyYAML in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (6.0.12.20240917)\n", - "Requirement already satisfied: typer<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.13.0)\n", - "Requirement already satisfied: watchdog<5 in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (4.0.2)\n", - "Collecting kfactory<0.12,>=0.9.1 (from kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading kfactory-0.11.4-py3-none-any.whl.metadata (4.5 kB)\n", - "Requirement already satisfied: freetype-py in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.5.1)\n", - "Requirement already satisfied: mapbox_earcut in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (1.0.2)\n", - "Requirement already satisfied: networkx in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (3.4.2)\n", - "Collecting pyglet<2 (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading pyglet-1.5.29-py3-none-any.whl.metadata (7.6 kB)\n", - "Requirement already satisfied: scikit-image in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.24.0)\n", - "Collecting trimesh<4.2,>=4 (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading trimesh-4.1.8-py3-none-any.whl.metadata (18 kB)\n", - "Collecting ipycytoscape (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading ipycytoscape-1.3.3-py2.py3-none-any.whl.metadata (7.5 kB)\n", - "Requirement already satisfied: ipyevents in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (2.0.2)\n", - "Requirement already satisfied: ipykernel in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (5.5.6)\n", - "Collecting ipympl (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading ipympl-0.9.4-py3-none-any.whl.metadata (8.7 kB)\n", - "Requirement already satisfied: ipytree in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (0.2.2)\n", - "Requirement already satisfied: ipywidgets in /usr/local/lib/python3.10/dist-packages (from gdsfactory<7.17,>=7.16.0->gf180) (7.7.1)\n", - "Requirement already satisfied: pyperclip in /usr/local/lib/python3.10/dist-packages (from cmd2->prettyprinttree) (1.9.0)\n", - "Requirement already satisfied: wcwidth in /usr/local/lib/python3.10/dist-packages (from cmd2->prettyprinttree) (0.2.13)\n", - "Requirement already satisfied: typing_extensions in /usr/local/lib/python3.10/dist-packages (from gdstk<0.10,>=0.9.49->gdsfactory<7.17,>=7.16.0->gf180) (4.12.2)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2<4->gdsfactory<7.17,>=7.16.0->gf180) (3.0.2)\n", - "Requirement already satisfied: klayout>=0.28.17 in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.29.8)\n", - "Requirement already satisfied: ruamel.yaml in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.18.6)\n", - "Requirement already satisfied: cachetools>=5.2.0 in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (5.5.0)\n", - "Requirement already satisfied: tomli in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2.0.2)\n", - "Requirement already satisfied: requests in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2.32.3)\n", - "Requirement already satisfied: aenum in /usr/local/lib/python3.10/dist-packages (from kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.1.15)\n", - "Requirement already satisfied: ipython in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (7.34.0)\n", - "Requirement already satisfied: gitpython in /usr/local/lib/python3.10/dist-packages (from kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.1.43)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (1.3.0)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (4.54.1)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (1.4.7)\n", - "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (24.2)\n", - "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (11.0.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (3.2.0)\n", - "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (2.8.2)\n", - "Requirement already satisfied: antlr4-python3-runtime==4.9.* in /usr/local/lib/python3.10/dist-packages (from omegaconf<3->gdsfactory<7.17,>=7.16.0->gf180) (4.9.3)\n", - "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory<7.17,>=7.16.0->gf180) (2024.2)\n", - "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas<3->gdsfactory<7.17,>=7.16.0->gf180) (2024.2)\n", - "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<2.7,>=2->gdsfactory<7.17,>=7.16.0->gf180) (0.7.0)\n", - "Collecting pydantic-core==2.16.3 (from pydantic<2.7,>=2->gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.metadata (6.5 kB)\n", - "INFO: pip is looking at multiple versions of pydantic-settings to determine which version is compatible with other requirements. This could take a while.\n", - "Collecting pydantic-settings<3 (from gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading pydantic_settings-2.6.0-py3-none-any.whl.metadata (3.5 kB)\n", - " Downloading pydantic_settings-2.5.2-py3-none-any.whl.metadata (3.5 kB)\n", - " Downloading pydantic_settings-2.5.1-py3-none-any.whl.metadata (3.5 kB)\n", - " Downloading pydantic_settings-2.5.0-py3-none-any.whl.metadata (3.5 kB)\n", - " Downloading pydantic_settings-2.4.0-py3-none-any.whl.metadata (3.5 kB)\n", - " Downloading pydantic_settings-2.3.4-py3-none-any.whl.metadata (3.3 kB)\n", - " Downloading pydantic_settings-2.3.3-py3-none-any.whl.metadata (3.3 kB)\n", - "INFO: pip is still looking at multiple versions of pydantic-settings to determine which version is compatible with other requirements. This could take a while.\n", - " Downloading pydantic_settings-2.3.2-py3-none-any.whl.metadata (3.3 kB)\n", - " Downloading pydantic_settings-2.3.1-py3-none-any.whl.metadata (3.3 kB)\n", - " Downloading pydantic_settings-2.3.0-py3-none-any.whl.metadata (3.3 kB)\n", - " Downloading pydantic_settings-2.2.1-py3-none-any.whl.metadata (3.1 kB)\n", - "Requirement already satisfied: python-dotenv>=0.21.0 in /usr/local/lib/python3.10/dist-packages (from pydantic-settings<3->gdsfactory<7.17,>=7.16.0->gf180) (1.0.1)\n", - "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory<7.17,>=7.16.0->gf180) (3.0.0)\n", - "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich<14->gdsfactory<7.17,>=7.16.0->gf180) (2.18.0)\n", - "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory<7.17,>=7.16.0->gf180) (8.1.7)\n", - "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer<1->gdsfactory<7.17,>=7.16.0->gf180) (1.5.4)\n", - "Collecting spectate>=1.0.0 (from ipycytoscape->gdsfactory<7.17,>=7.16.0->gf180)\n", - " Downloading spectate-1.0.1-py2.py3-none-any.whl.metadata (2.2 kB)\n", - "Requirement already satisfied: ipython-genutils~=0.2.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.2.0)\n", - "Requirement already satisfied: traitlets>=4.3.1 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (5.7.1)\n", - "Requirement already satisfied: widgetsnbextension~=3.6.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.6.10)\n", - "Requirement already satisfied: jupyterlab-widgets>=1.0.0 in /usr/local/lib/python3.10/dist-packages (from ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.0.13)\n", - "Requirement already satisfied: jupyter-client in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (6.1.12)\n", - "Requirement already satisfied: tornado>=4.2 in /usr/local/lib/python3.10/dist-packages (from ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (6.3.3)\n", - "Requirement already satisfied: imageio>=2.33 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory<7.17,>=7.16.0->gf180) (2.36.0)\n", - "Requirement already satisfied: tifffile>=2022.8.12 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory<7.17,>=7.16.0->gf180) (2024.9.20)\n", - "Requirement already satisfied: lazy-loader>=0.4 in /usr/local/lib/python3.10/dist-packages (from scikit-image->gdsfactory<7.17,>=7.16.0->gf180) (0.4)\n", - "Requirement already satisfied: setuptools>=18.5 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (75.1.0)\n", - "Requirement already satisfied: jedi>=0.16 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.19.2)\n", - "Requirement already satisfied: decorator in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (4.4.2)\n", - "Requirement already satisfied: pickleshare in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.7.5)\n", - "Requirement already satisfied: prompt-toolkit!=3.0.0,!=3.0.1,<3.1.0,>=2.0.0 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.0.48)\n", - "Requirement already satisfied: backcall in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.2.0)\n", - "Requirement already satisfied: matplotlib-inline in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.1.7)\n", - "Requirement already satisfied: pexpect>4.3 in /usr/local/lib/python3.10/dist-packages (from ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (4.9.0)\n", - "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich<14->gdsfactory<7.17,>=7.16.0->gf180) (0.1.2)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib<4->gdsfactory<7.17,>=7.16.0->gf180) (1.16.0)\n", - "Requirement already satisfied: notebook>=4.4.1 in /usr/local/lib/python3.10/dist-packages (from widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (6.5.5)\n", - "Requirement already satisfied: gitdb<5,>=4.0.1 in /usr/local/lib/python3.10/dist-packages (from gitpython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (4.0.11)\n", - "Requirement already satisfied: jupyter-core>=4.6.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (5.7.2)\n", - "Requirement already satisfied: pyzmq>=13 in /usr/local/lib/python3.10/dist-packages (from jupyter-client->ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (24.0.1)\n", - "Requirement already satisfied: charset-normalizer<4,>=2 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.4.0)\n", - "Requirement already satisfied: idna<4,>=2.5 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (3.10)\n", - "Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2.2.3)\n", - "Requirement already satisfied: certifi>=2017.4.17 in /usr/local/lib/python3.10/dist-packages (from requests->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (2024.8.30)\n", - "Requirement already satisfied: ruamel.yaml.clib>=0.2.7 in /usr/local/lib/python3.10/dist-packages (from ruamel.yaml->kfactory<0.12,>=0.9.1->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.2.12)\n", - "\u001b[33mWARNING: typer 0.13.0 does not provide the extra 'all'\u001b[0m\u001b[33m\n", - "\u001b[0mRequirement already satisfied: smmap<6,>=3.0.1 in /usr/local/lib/python3.10/dist-packages (from gitdb<5,>=4.0.1->gitpython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (5.0.1)\n", - "Requirement already satisfied: parso<0.9.0,>=0.8.4 in /usr/local/lib/python3.10/dist-packages (from jedi>=0.16->ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.8.4)\n", - "Requirement already satisfied: platformdirs>=2.5 in /usr/local/lib/python3.10/dist-packages (from jupyter-core>=4.6.0->jupyter-client->ipykernel->gdsfactory<7.17,>=7.16.0->gf180) (4.3.6)\n", - "Requirement already satisfied: argon2-cffi in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (23.1.0)\n", - "Requirement already satisfied: nbformat in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (5.10.4)\n", - "Requirement already satisfied: nbconvert>=5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (7.16.4)\n", - "Requirement already satisfied: nest-asyncio>=1.5 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.6.0)\n", - "Requirement already satisfied: Send2Trash>=1.8.0 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.8.3)\n", - "Requirement already satisfied: terminado>=0.8.3 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.18.1)\n", - "Requirement already satisfied: prometheus-client in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.21.0)\n", - "Requirement already satisfied: nbclassic>=0.4.7 in /usr/local/lib/python3.10/dist-packages (from notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.1.0)\n", - "Requirement already satisfied: ptyprocess>=0.5 in /usr/local/lib/python3.10/dist-packages (from pexpect>4.3->ipython->kfactory[git,ipy]<0.12,>=0.9.1->gdsfactory<7.17,>=7.16.0->gf180) (0.7.0)\n", - "Requirement already satisfied: notebook-shim>=0.2.3 in /usr/local/lib/python3.10/dist-packages (from nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.2.4)\n", - "Requirement already satisfied: beautifulsoup4 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (4.12.3)\n", - "Requirement already satisfied: bleach!=5.0.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (6.2.0)\n", - "Requirement already satisfied: defusedxml in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.7.1)\n", - "Requirement already satisfied: jupyterlab-pygments in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.3.0)\n", - "Requirement already satisfied: mistune<4,>=2.0.3 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.0.2)\n", - "Requirement already satisfied: nbclient>=0.5.0 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.10.0)\n", - "Requirement already satisfied: pandocfilters>=1.4.1 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.5.1)\n", - "Requirement already satisfied: tinycss2 in /usr/local/lib/python3.10/dist-packages (from nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.4.0)\n", - "Requirement already satisfied: fastjsonschema>=2.15 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2.20.0)\n", - "Requirement already satisfied: jsonschema>=2.6 in /usr/local/lib/python3.10/dist-packages (from nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (4.23.0)\n", - "Requirement already satisfied: argon2-cffi-bindings in /usr/local/lib/python3.10/dist-packages (from argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (21.2.0)\n", - "Requirement already satisfied: webencodings in /usr/local/lib/python3.10/dist-packages (from bleach!=5.0.0->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.5.1)\n", - "Requirement already satisfied: attrs>=22.2.0 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (24.2.0)\n", - "Requirement already satisfied: jsonschema-specifications>=2023.03.6 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2024.10.1)\n", - "Requirement already satisfied: referencing>=0.28.4 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.35.1)\n", - "Requirement already satisfied: rpds-py>=0.7.1 in /usr/local/lib/python3.10/dist-packages (from jsonschema>=2.6->nbformat->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (0.21.0)\n", - "Requirement already satisfied: jupyter-server<3,>=1.8 in /usr/local/lib/python3.10/dist-packages (from notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.24.0)\n", - "Requirement already satisfied: cffi>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from argon2-cffi-bindings->argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.17.1)\n", - "Requirement already satisfied: soupsieve>1.2 in /usr/local/lib/python3.10/dist-packages (from beautifulsoup4->nbconvert>=5->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2.6)\n", - "Requirement already satisfied: pycparser in /usr/local/lib/python3.10/dist-packages (from cffi>=1.0.1->argon2-cffi-bindings->argon2-cffi->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (2.22)\n", - "Requirement already satisfied: anyio<4,>=3.1.0 in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (3.7.1)\n", - "Requirement already satisfied: websocket-client in /usr/local/lib/python3.10/dist-packages (from jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.8.0)\n", - "Requirement already satisfied: sniffio>=1.1 in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.3.1)\n", - "Requirement already satisfied: exceptiongroup in /usr/local/lib/python3.10/dist-packages (from anyio<4,>=3.1.0->jupyter-server<3,>=1.8->notebook-shim>=0.2.3->nbclassic>=0.4.7->notebook>=4.4.1->widgetsnbextension~=3.6.0->ipywidgets->gdsfactory<7.17,>=7.16.0->gf180) (1.2.2)\n", - "Downloading gf180-0.1.0-py3-none-any.whl (135 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m135.6/135.6 kB\u001b[0m \u001b[31m8.8 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading PrettyPrintTree-2.0.1-py3-none-any.whl (14 kB)\n", - "Downloading svgutils-0.3.4-py3-none-any.whl (10 kB)\n", - "Downloading gdsfactory-7.16.0-py3-none-any.whl (834 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m834.2/834.2 kB\u001b[0m \u001b[31m33.1 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading cmd2-2.5.5-py3-none-any.whl (151 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m151.3/151.3 kB\u001b[0m \u001b[31m12.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading colorama-0.4.6-py2.py3-none-any.whl (25 kB)\n", - "Downloading gdstk-0.9.57-cp310-cp310-manylinux_2_28_x86_64.whl (533 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m533.9/533.9 kB\u001b[0m \u001b[31m35.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading kfactory-0.11.4-py3-none-any.whl (114 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m114.7/114.7 kB\u001b[0m \u001b[31m6.7 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading pydantic-2.6.4-py3-none-any.whl (394 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m394.9/394.9 kB\u001b[0m \u001b[31m27.4 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading pydantic_core-2.16.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (2.2 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m2.2/2.2 MB\u001b[0m \u001b[31m70.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading pydantic_settings-2.2.1-py3-none-any.whl (13 kB)\n", - "Downloading pyglet-1.5.29-py3-none-any.whl (1.1 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m1.1/1.1 MB\u001b[0m \u001b[31m51.6 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading trimesh-4.1.8-py3-none-any.whl (690 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m690.6/690.6 kB\u001b[0m \u001b[31m42.3 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading ipycytoscape-1.3.3-py2.py3-none-any.whl (3.6 MB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m3.6/3.6 MB\u001b[0m \u001b[31m83.2 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading ipympl-0.9.4-py3-none-any.whl (516 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m516.3/516.3 kB\u001b[0m \u001b[31m32.9 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hDownloading spectate-1.0.1-py2.py3-none-any.whl (11 kB)\n", - "Building wheels for collected packages: flatdict\n", - " Building wheel for flatdict (setup.py) ... \u001b[?25l\u001b[?25hdone\n", - " Created wheel for flatdict: filename=flatdict-4.0.1-py3-none-any.whl size=6928 sha256=cbe7b9ecdeb813ed4b936db444d4d7b1e3115b3811fed30a7561ac5da3fd548a\n", - " Stored in directory: /root/.cache/pip/wheels/71/12/62/88c5bf37619c2d7481eedb8abd0dde6674e88dce45a7805a6f\n", - "Successfully built flatdict\n", - "Installing collected packages: pyglet, flatdict, trimesh, svgutils, spectate, pydantic-core, gdstk, colorama, cmd2, pydantic, prettyprinttree, pydantic-settings, kfactory, ipympl, ipycytoscape, gdsfactory, gf180\n", - " Attempting uninstall: trimesh\n", - " Found existing installation: trimesh 4.4.9\n", - " Uninstalling trimesh-4.4.9:\n", - " Successfully uninstalled trimesh-4.4.9\n", - " Attempting uninstall: pydantic-core\n", - " Found existing installation: pydantic_core 2.20.1\n", - " Uninstalling pydantic_core-2.20.1:\n", - " Successfully uninstalled pydantic_core-2.20.1\n", - " Attempting uninstall: pydantic\n", - " Found existing installation: pydantic 2.8.2\n", - " Uninstalling pydantic-2.8.2:\n", - " Successfully uninstalled pydantic-2.8.2\n", - " Attempting uninstall: pydantic-settings\n", - " Found existing installation: pydantic-settings 2.6.1\n", - " Uninstalling pydantic-settings-2.6.1:\n", - " Successfully uninstalled pydantic-settings-2.6.1\n", - " Attempting uninstall: kfactory\n", - " Found existing installation: kfactory 0.18.4\n", - " Uninstalling kfactory-0.18.4:\n", - " Successfully uninstalled kfactory-0.18.4\n", - " Attempting uninstall: gdsfactory\n", - " Found existing installation: gdsfactory 8.5.6\n", - " Uninstalling gdsfactory-8.5.6:\n", - " Successfully uninstalled gdsfactory-8.5.6\n", - "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", - "albumentations 1.4.20 requires pydantic>=2.7.0, but you have pydantic 2.6.4 which is incompatible.\n", - "langchain 0.3.7 requires pydantic<3.0.0,>=2.7.4, but you have pydantic 2.6.4 which is incompatible.\n", - "sky130 0.12.2 requires gdsfactory~=8.5.2, but you have gdsfactory 7.16.0 which is incompatible.\u001b[0m\u001b[31m\n", - "\u001b[0mSuccessfully installed cmd2-2.5.5 colorama-0.4.6 flatdict-4.0.1 gdsfactory-7.16.0 gdstk-0.9.57 gf180-0.1.0 ipycytoscape-1.3.3 ipympl-0.9.4 kfactory-0.11.4 prettyprinttree-2.0.1 pydantic-2.6.4 pydantic-core-2.16.3 pydantic-settings-2.2.1 pyglet-1.5.29 spectate-1.0.1 svgutils-0.3.4 trimesh-4.1.8\n", - "Collecting gdsfactory==7.7.0\n", - " Downloading gdsfactory-7.7.0-py3-none-any.whl.metadata (10 kB)\n", - "Requirement already satisfied: flatdict in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (4.0.1)\n", - "Requirement already satisfied: gdstk<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.9.57)\n", - "Requirement already satisfied: jinja2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (3.1.4)\n", - "Requirement already satisfied: loguru<1 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.7.2)\n", - "Requirement already satisfied: matplotlib in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (3.8.0)\n", - "Requirement already satisfied: numpy in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (1.26.4)\n", - "Requirement already satisfied: omegaconf<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.3.0)\n", - "Requirement already satisfied: orjson in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (3.10.11)\n", - "Requirement already satisfied: pandas in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.2.2)\n", - "Requirement already satisfied: pydantic<3,>=2 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.6.4)\n", - "Requirement already satisfied: pydantic-settings in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.2.1)\n", - "Requirement already satisfied: pydantic-extra-types in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.10.0)\n", - "Requirement already satisfied: pyyaml in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (6.0.2)\n", - "Requirement already satisfied: qrcode in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (8.0)\n", - "Requirement already satisfied: rectpack in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.2.2)\n", - "Requirement already satisfied: rich in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (13.9.4)\n", - "Requirement already satisfied: scipy in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (1.13.1)\n", - "Requirement already satisfied: shapely<3 in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (2.0.6)\n", - "Requirement already satisfied: toolz in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.12.1)\n", - "Requirement already satisfied: tqdm in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (4.66.6)\n", - "Requirement already satisfied: types-PyYAML in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (6.0.12.20240917)\n", - "Requirement already satisfied: typer in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (0.13.0)\n", - "Requirement already satisfied: watchdog in /usr/local/lib/python3.10/dist-packages (from gdsfactory==7.7.0) (4.0.2)\n", - "Requirement already satisfied: typing_extensions in /usr/local/lib/python3.10/dist-packages (from gdstk<1->gdsfactory==7.7.0) (4.12.2)\n", - "Requirement already satisfied: antlr4-python3-runtime==4.9.* in /usr/local/lib/python3.10/dist-packages (from omegaconf<3->gdsfactory==7.7.0) (4.9.3)\n", - "Requirement already satisfied: annotated-types>=0.4.0 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=2->gdsfactory==7.7.0) (0.7.0)\n", - "Requirement already satisfied: pydantic-core==2.16.3 in /usr/local/lib/python3.10/dist-packages (from pydantic<3,>=2->gdsfactory==7.7.0) (2.16.3)\n", - "Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/dist-packages (from jinja2->gdsfactory==7.7.0) (3.0.2)\n", - "Requirement already satisfied: contourpy>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (1.3.0)\n", - "Requirement already satisfied: cycler>=0.10 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (0.12.1)\n", - "Requirement already satisfied: fonttools>=4.22.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (4.54.1)\n", - "Requirement already satisfied: kiwisolver>=1.0.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (1.4.7)\n", - "Requirement already satisfied: packaging>=20.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (24.2)\n", - "Requirement already satisfied: pillow>=6.2.0 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (11.0.0)\n", - "Requirement already satisfied: pyparsing>=2.3.1 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (3.2.0)\n", - "Requirement already satisfied: python-dateutil>=2.7 in /usr/local/lib/python3.10/dist-packages (from matplotlib->gdsfactory==7.7.0) (2.8.2)\n", - "Requirement already satisfied: pytz>=2020.1 in /usr/local/lib/python3.10/dist-packages (from pandas->gdsfactory==7.7.0) (2024.2)\n", - "Requirement already satisfied: tzdata>=2022.7 in /usr/local/lib/python3.10/dist-packages (from pandas->gdsfactory==7.7.0) (2024.2)\n", - "Requirement already satisfied: python-dotenv>=0.21.0 in /usr/local/lib/python3.10/dist-packages (from pydantic-settings->gdsfactory==7.7.0) (1.0.1)\n", - "Requirement already satisfied: markdown-it-py>=2.2.0 in /usr/local/lib/python3.10/dist-packages (from rich->gdsfactory==7.7.0) (3.0.0)\n", - "Requirement already satisfied: pygments<3.0.0,>=2.13.0 in /usr/local/lib/python3.10/dist-packages (from rich->gdsfactory==7.7.0) (2.18.0)\n", - "Requirement already satisfied: click>=8.0.0 in /usr/local/lib/python3.10/dist-packages (from typer->gdsfactory==7.7.0) (8.1.7)\n", - "Requirement already satisfied: shellingham>=1.3.0 in /usr/local/lib/python3.10/dist-packages (from typer->gdsfactory==7.7.0) (1.5.4)\n", - "Requirement already satisfied: mdurl~=0.1 in /usr/local/lib/python3.10/dist-packages (from markdown-it-py>=2.2.0->rich->gdsfactory==7.7.0) (0.1.2)\n", - "Requirement already satisfied: six>=1.5 in /usr/local/lib/python3.10/dist-packages (from python-dateutil>=2.7->matplotlib->gdsfactory==7.7.0) (1.16.0)\n", - "Downloading gdsfactory-7.7.0-py3-none-any.whl (801 kB)\n", - "\u001b[2K \u001b[90m━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\u001b[0m \u001b[32m801.2/801.2 kB\u001b[0m \u001b[31m16.0 MB/s\u001b[0m eta \u001b[36m0:00:00\u001b[0m\n", - "\u001b[?25hInstalling collected packages: gdsfactory\n", - " Attempting uninstall: gdsfactory\n", - " Found existing installation: gdsfactory 7.16.0\n", - " Uninstalling gdsfactory-7.16.0:\n", - " Successfully uninstalled gdsfactory-7.16.0\n", - "\u001b[31mERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts.\n", - "gf180 0.1.0 requires gdsfactory<7.17,>=7.16.0, but you have gdsfactory 7.7.0 which is incompatible.\n", - "sky130 0.12.2 requires gdsfactory~=8.5.2, but you have gdsfactory 7.7.0 which is incompatible.\u001b[0m\u001b[31m\n", - "\u001b[0mSuccessfully installed gdsfactory-7.7.0\n", - "bin/micromamba\n", - "env: CONDA_PREFIX=/content/conda-env\n", - "Empty environment created at prefix: /content/conda-env\n", - "\u001b[?25l\u001b[2K\u001b[0G[+] 0.0s\n", - "\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.1s\n", - "litex-hub/linux-64.. ⣾ \n", - "litex-hub/noarch (.. ⣾ \n", - "main/linux-64 (che.. ⣾ \n", - "main/noarch (check.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.2s\n", - "litex-hub/linux-64.. ⣾ \n", - "litex-hub/noarch (.. ⣾ \n", - "main/linux-64 (che.. ⣾ \n", - "main/noarch (check.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.3s\n", - "litex-hub/linux-64.. ⣾ \n", - "litex-hub/noarch (.. ⣾ \n", - "main/linux-64 (che.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.4s\n", - "litex-hub/noarch (.. ⣾ \n", - "main/linux-64 (che.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.5s\n", - "litex-hub/noarch (.. ⣾ \u001b[2K\u001b[1A\u001b[2K\u001b[0G\u001b[?25h\u001b[?25l\u001b[2K\u001b[0G[+] 0.0s\n", - "\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.1s\n", - "litex-hub/linux-64 | \n", - "litex-hub/noarch ⣾ \n", - "main/linux-64 ⣾ \n", - "main/noarch | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.2s\n", - "litex-hub/linux-64 | \n", - "litex-hub/noarch ⣾ \n", - "main/linux-64 ⣾ \n", - "main/noarch | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.3s\n", - "litex-hub/linux-64 | \n", - "litex-hub/noarch ⣾ \n", - "main/linux-64 ⣾ \n", - "main/noarch | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glitex-hub/noarch \n", - "[+] 0.4s\n", - "litex-hub/linux-64 | \n", - "main/linux-64 ⣾ \n", - "main/noarch 3%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.5s\n", - "litex-hub/linux-64 | \n", - "main/linux-64 2%\n", - "main/noarch 15%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.6s\n", - "litex-hub/linux-64 | \n", - "main/linux-64 9%\n", - "main/noarch 36%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gmain/noarch \n", - "[+] 0.7s\n", - "litex-hub/linux-64 | \n", - "main/linux-64 11%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.8s\n", - "litex-hub/linux-64 3%\n", - "main/linux-64 42%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.9s\n", - "litex-hub/linux-64 27%\n", - "main/linux-64 83%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gmain/linux-64 \n", - "[+] 1.0s\n", - "litex-hub/linux-64 57%\u001b[2K\u001b[1A\u001b[2K\u001b[0Glitex-hub/linux-64 \n", - "\u001b[?25h\n", - "\u001b[31m\u001b[1merror libmamba\u001b[m Could not lock non-existing path '/root/.mamba/pkgs'\n", - "\n", - "Transaction\n", - "\n", - " Prefix: /content/conda-env\n", - "\n", - " Updating specs:\n", - "\n", - " - klayout\n", - "\n", - "\n", - " Package Version Build Channel Size\n", - "─────────────────────────────────────────────────────────────────────────────────────────\n", - " Install:\n", - "─────────────────────────────────────────────────────────────────────────────────────────\n", - "\n", - " \u001b[32m+ _libgcc_mutex \u001b[0m 0.1 main main 3kB\n", - " \u001b[32m+ _openmp_mutex \u001b[0m 5.1 1_gnu main 21kB\n", - " \u001b[32m+ bzip2 \u001b[0m 1.0.8 h5eee18b_6 main 428kB\n", - " \u001b[32m+ c-ares \u001b[0m 1.19.1 h5eee18b_0 main 116kB\n", - " \u001b[32m+ ca-certificates \u001b[0m 2024.9.24 h06a4308_0 main 140kB\n", - " \u001b[32m+ certifi \u001b[0m 2022.12.7 py37h06a4308_0 main 155kB\n", - " \u001b[32m+ curl \u001b[0m 8.2.1 h37d81fd_0 main 89kB\n", - " \u001b[32m+ dbus \u001b[0m 1.13.18 hb2f20db_0 main 600kB\n", - " \u001b[32m+ expat \u001b[0m 2.6.3 h6a678d5_0 main 201kB\n", - " \u001b[32m+ fontconfig \u001b[0m 2.13.0 h9420a91_0 main 298kB\n", - " \u001b[32m+ freetype \u001b[0m 2.12.1 h4a9f257_0 main 972kB\n", - " \u001b[32m+ glib \u001b[0m 2.78.4 h6a678d5_0 main 499kB\n", - " \u001b[32m+ glib-tools \u001b[0m 2.78.4 h6a678d5_0 main 113kB\n", - " \u001b[32m+ gmp \u001b[0m 6.2.1 h295c915_3 main 822kB\n", - " \u001b[32m+ gst-plugins-base\u001b[0m 1.14.1 h6a678d5_1 main 2MB\n", - " \u001b[32m+ gstreamer \u001b[0m 1.14.1 h5eee18b_1 main 2MB\n", - " \u001b[32m+ icu \u001b[0m 58.2 he6710b0_3 main 24MB\n", - " \u001b[32m+ jpeg \u001b[0m 9e h5eee18b_3 main 284kB\n", - " \u001b[32m+ klayout \u001b[0m 0.28.17_212_gfa14afbbf 20240223_100318_py37 litex-hub 27MB\n", - " \u001b[32m+ krb5 \u001b[0m 1.20.1 h568e23c_1 main 1MB\n", - " \u001b[32m+ ld_impl_linux-64\u001b[0m 2.40 h12ee557_0 main 723kB\n", - " \u001b[32m+ libcurl \u001b[0m 8.2.1 h91b91d3_0 main 386kB\n", - " \u001b[32m+ libedit \u001b[0m 3.1.20230828 h5eee18b_0 main 196kB\n", - " \u001b[32m+ libev \u001b[0m 4.33 h7f8727e_1 main 109kB\n", - " \u001b[32m+ libffi \u001b[0m 3.4.4 h6a678d5_1 main 154kB\n", - " \u001b[32m+ libgcc-ng \u001b[0m 11.2.0 h1234567_1 main 9MB\n", - " \u001b[32m+ libgit2 \u001b[0m 1.6.4 ha637b67_0 main 1MB\n", - " \u001b[32m+ libglib \u001b[0m 2.78.4 hdc74915_0 main 2MB\n", - " \u001b[32m+ libgomp \u001b[0m 11.2.0 h1234567_1 main 573kB\n", - " \u001b[32m+ libiconv \u001b[0m 1.16 h5eee18b_3 main 1MB\n", - " \u001b[32m+ libnghttp2 \u001b[0m 1.52.0 ha637b67_1 main 717kB\n", - " \u001b[32m+ libpng \u001b[0m 1.6.39 h5eee18b_0 main 363kB\n", - " \u001b[32m+ libssh2 \u001b[0m 1.10.0 h37d81fd_2 main 312kB\n", - " \u001b[32m+ libstdcxx-ng \u001b[0m 11.2.0 h1234567_1 main 6MB\n", - " \u001b[32m+ libuuid \u001b[0m 1.41.5 h5eee18b_0 main 29kB\n", - " \u001b[32m+ libxcb \u001b[0m 1.15 h7f8727e_0 main 623kB\n", - " \u001b[32m+ libxml2 \u001b[0m 2.9.9 20220706_155948 litex-hub 1MB\n", - " \u001b[32m+ ncurses \u001b[0m 6.4 h6a678d5_0 main 1MB\n", - " \u001b[32m+ openssl \u001b[0m 1.1.1w h7f8727e_0 main 4MB\n", - " \u001b[32m+ pcre2 \u001b[0m 10.42 hebb0a14_1 main 3MB\n", - " \u001b[32m+ pip \u001b[0m 22.3.1 py37h06a4308_0 main 3MB\n", - " \u001b[32m+ python \u001b[0m 3.7.16 h7a1cb2a_0 main 49MB\n", - " \u001b[32m+ qt \u001b[0m 5.9.7 h5867ecd_1 main 90MB\n", - " \u001b[32m+ readline \u001b[0m 8.2 h5eee18b_0 main 468kB\n", - " \u001b[32m+ ruby \u001b[0m 2.5.1 haf1161a_0 main 5MB\n", - " \u001b[32m+ setuptools \u001b[0m 65.6.3 py37h06a4308_0 main 1MB\n", - " \u001b[32m+ sqlite \u001b[0m 3.45.3 h5eee18b_0 main 2MB\n", - " \u001b[32m+ tk \u001b[0m 8.6.14 h39e8969_0 main 4MB\n", - " \u001b[32m+ wheel \u001b[0m 0.38.4 py37h06a4308_0 main 59kB\n", - " \u001b[32m+ xz \u001b[0m 5.4.6 h5eee18b_1 main 717kB\n", - " \u001b[32m+ yaml \u001b[0m 0.1.7 had09818_2 main 87kB\n", - " \u001b[32m+ zlib \u001b[0m 1.2.13 h5eee18b_1 main 127kB\n", - "\n", - " Summary:\n", - "\n", - " Install: 52 packages\n", - "\n", - " Total download: 249MB\n", - "\n", - "─────────────────────────────────────────────────────────────────────────────────────────\n", - "\n", - "\n", - "\n", - "Transaction starting\n", - "\u001b[?25l\u001b[2K\u001b[0G[+] 0.0s\n", - "Downloading 5%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.1s\n", - "Downloading (5) 0%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.2s\n", - "Downloading (5) 0%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.3s\n", - "Downloading (5) 0%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.4s\n", - "Downloading (5) 0%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.5s\n", - "Downloading (5) 0%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.6s\n", - "Downloading (5) 0%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.7s\n", - "Downloading (5) 0%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.8s\n", - "Downloading (5) 1%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 0.9s\n", - "Downloading (5) 1%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.0s\n", - "Downloading (5) 1%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.1s\n", - "Downloading (5) 3%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.2s\n", - "Downloading (5) 6%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibgcc-ng 8.9MB @ 7.4MB/s 1.2s\n", - "[+] 1.3s\n", - "Downloading (5) 10%\n", - "Extracting 0%\u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.4s\n", - "Downloading (5) 13%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.5s\n", - "Downloading (5) 18%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.6s\n", - "Downloading (5) 23%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.7s\n", - "Downloading (5) 31%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 1.8s\n", - "Downloading (5) 39%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gklayout 26.7MB @ 14.3MB/s 1.8s\n", - "[+] 1.9s\n", - "Downloading (5) 43%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.0s\n", - "Downloading (5) 45%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gicu 23.8MB @ 11.7MB/s 2.0s\n", - "[+] 2.1s\n", - "Downloading (5) 47%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.2s\n", - "Downloading (5) 49%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.3s\n", - "Downloading (5) 52%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibstdcxx-ng 6.4MB @ 4.6MB/s 1.2s\n", - "[+] 2.4s\n", - "Downloading (5) 58%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.5s\n", - "Downloading (5) 61%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.6s\n", - "Downloading (5) 65%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.7s\n", - "Downloading (5) 68%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 2.8s\n", - "Downloading (5) 70%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gpython 48.7MB @ 16.5MB/s 2.8s\n", - "[+] 2.9s\n", - "Downloading (5) 72%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.0s\n", - "Downloading (5) 74%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.1s\n", - "Downloading (5) 75%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.2s\n", - "Downloading (5) 78%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.3s\n", - "Downloading (5) 80%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gopenssl 4.0MB @ 2.9MB/s 1.3s\n", - "ruby 5.3MB @ 3.1MB/s 1.4s\n", - "[+] 3.4s\n", - "Downloading (5) 80%\n", - "Extracting (5) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.5s\n", - "Downloading (5) 80%\n", - "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.6s\n", - "Downloading (5) 81%\n", - "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 3.7s\n", - "Downloading (5) 83%\n", - "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gtk 3.6MB @ 2.4MB/s 1.4s\n", - "[+] 3.8s\n", - "Downloading (5) 84%\n", - "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gpcre2 3.3MB @ 3.2MB/s 1.0s\n", - "[+] 3.9s\n", - "Downloading (5) 85%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.0s\n", - "Downloading (5) 86%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.1s\n", - "Downloading (5) 87%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.2s\n", - "Downloading (5) 88%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.3s\n", - "Downloading (5) 88%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.4s\n", - "Downloading (5) 89%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.5s\n", - "Downloading (5) 92%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gpip 2.8MB @ 2.2MB/s 1.2s\n", - "[+] 4.6s\n", - "Downloading (5) 93%\n", - "Extracting (10) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Ggst-plugins-base 2.3MB @ 1.6MB/s 1.3s\n", - "[+] 4.7s\n", - "Downloading (5) 94%\n", - "Extracting (10) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gsqlite 1.7MB @ 1.5MB/s 0.9s\n", - "gstreamer 1.7MB @ 1.8MB/s 0.9s\n", - "[+] 4.8s\n", - "Downloading (5) 96%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 4.9s\n", - "Downloading (5) 96%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.0s\n", - "Downloading (5) 97%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gqt 90.0MB @ 17.8MB/s 5.0s\n", - "[+] 5.1s\n", - "Downloading (5) 97%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.2s\n", - "Downloading (5) 97%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.3s\n", - "Downloading (5) 98%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibglib 1.6MB @ 932.0kB/s 0.9s\n", - "[+] 5.4s\n", - "Downloading (5) 98%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.5s\n", - "Downloading (5) 98%\n", - "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.6s\n", - "Downloading (5) 98%\n", - "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gsetuptools 1.4MB @ 987.1kB/s 1.0s\n", - "libiconv 1.4MB @ 850.5kB/s 1.0s\n", - "krb5 1.4MB @ 849.1kB/s 0.9s\n", - "[+] 5.7s\n", - "Downloading (5) 98%\n", - "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.8s\n", - "Downloading (5) 98%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 5.9s\n", - "Downloading (5) 99%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibxml2 1.4MB @ 834.9kB/s 0.9s\n", - "[+] 6.0s\n", - "Downloading (5) 98%\n", - "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.1s\n", - "Downloading (5) 98%\n", - "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.2s\n", - "Downloading (5) 99%\n", - "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.3s\n", - "Downloading (5) 99%\n", - "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibgit2 1.2MB @ 804.6kB/s 1.0s\n", - "[+] 6.4s\n", - "Downloading (5) 99%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.5s\n", - "Downloading (5) 99%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gncurses 1.2MB @ 937.3kB/s 0.9s\n", - "freetype 972.0kB @ 896.8kB/s 0.9s\n", - "[+] 6.6s\n", - "Downloading (5) 99%\n", - "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.7s\n", - "Downloading (5) 99%\n", - "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 6.8s\n", - "Downloading (5) 99%\n", - "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Ggmp 822.4kB @ 698.3kB/s 1.1s\n", - "[+] 6.9s\n", - "Downloading (5) 99%\n", - "Extracting (22) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gld_impl_linux-64 723.1kB @ 375.9kB/s 1.0s\n", - "[+] 7.0s\n", - "Downloading (5) 99%\n", - "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.1s\n", - "Downloading (5) 99%\n", - "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.2s\n", - "Downloading (5) 99%\n", - "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibxcb 623.5kB @ 577.3kB/s 0.7s\n", - "libnghttp2 716.6kB @ 539.0kB/s 0.8s\n", - "xz 716.9kB @ 446.2kB/s 0.9s\n", - "[+] 7.3s\n", - "Downloading (5) 99%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.4s\n", - "Downloading (5) 99%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.5s\n", - "Downloading (5) 99%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.6s\n", - "Downloading (5) 99%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.7s\n", - "Downloading (5) 99%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 7.8s\n", - "Downloading (5) 100%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibgomp 573.2kB @ 429.0kB/s 0.9s\n", - "[+] 7.9s\n", - "Downloading (5) 100%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gdbus 600.2kB @ 313.4kB/s 1.1s\n", - "[+] 8.0s\n", - "Downloading (5) 100%\n", - "Extracting (27) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.1s\n", - "Downloading (5) 100%\n", - "Extracting (27) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gglib 499.0kB @ 409.8kB/s 0.9s\n", - "readline 467.7kB @ 420.7kB/s 0.9s\n", - "bzip2 427.5kB @ 433.5kB/s 0.9s\n", - "[+] 8.2s\n", - "Downloading (5) 100%\n", - "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.3s\n", - "Downloading (5) 100%\n", - "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.4s\n", - "Downloading (5) 100%\n", - "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.5s\n", - "Downloading (5) 100%\n", - "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 8.6s\n", - "Downloading (5) 100%\n", - "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibssh2 311.8kB @ ??.?MB/s 0.5s\n", - "[+] 8.7s\n", - "Downloading (5) 100%\n", - "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibpng 362.6kB @ 468.9kB/s 0.8s\n", - "[+] 8.8s\n", - "Downloading (5) 100%\n", - "Extracting (31) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gfontconfig 297.6kB @ 429.9kB/s 0.7s\n", - "libcurl 386.4kB @ 406.6kB/s 1.0s\n", - "[+] 8.9s\n", - "Downloading (5) 100%\n", - "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gjpeg 283.5kB @ 240.5kB/s 0.7s\n", - "[+] 9.0s\n", - "Downloading (5) 100%\n", - "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.1s\n", - "Downloading (5) 100%\n", - "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.2s\n", - "Downloading (5) 100%\n", - "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.3s\n", - "Downloading (5) 100%\n", - "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.4s\n", - "Downloading (5) 100%\n", - "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gexpat 200.8kB @ 178.1kB/s 0.8s\n", - "[+] 9.5s\n", - "Downloading (5) 100%\n", - "Extracting (35) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibffi 154.0kB @ 111.1kB/s 0.7s\n", - "libedit 195.8kB @ 243.1kB/s 0.8s\n", - "[+] 9.6s\n", - "Downloading (5) 100%\n", - "Extracting (37) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gcertifi 155.3kB @ 150.2kB/s 0.8s\n", - "ca-certificates 139.9kB @ 91.3kB/s 0.7s\n", - "[+] 9.7s\n", - "Downloading (5) 100%\n", - "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.8s\n", - "Downloading (5) 100%\n", - "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 9.9s\n", - "Downloading (5) 100%\n", - "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gglib-tools 112.6kB @ 275.5kB/s 0.4s\n", - "[+] 10.0s\n", - "Downloading (5) 100%\n", - "Extracting (40) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.1s\n", - "Downloading (5) 100%\n", - "Extracting (40) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gzlib 127.1kB @ 105.1kB/s 0.7s\n", - "c-ares 116.3kB @ 115.3kB/s 0.7s\n", - "[+] 10.2s\n", - "Downloading (5) 100%\n", - "Extracting (41) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.3s\n", - "Downloading (5) 100%\n", - "Extracting (42) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.4s\n", - "Downloading (5) 100%\n", - "Extracting (42) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gyaml 87.1kB @ ??.?MB/s 0.4s\n", - "libev 108.9kB @ 77.3kB/s 0.8s\n", - "curl 88.8kB @ 80.9kB/s 0.8s\n", - "[+] 10.5s\n", - "Downloading (4) 100%\n", - "Extracting (45) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Gwheel 58.7kB @ 79.1kB/s 0.4s\n", - "[+] 10.6s\n", - "Downloading (3) 100%\n", - "Extracting (46) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 10.7s\n", - "Downloading (3) 100%\n", - "Extracting (46) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0Glibuuid 29.2kB @ 53.0kB/s 0.6s\n", - "[+] 10.8s\n", - "Downloading (2) 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G_libgcc_mutex 3.1kB @ 8.2kB/s 0.4s\n", - "[+] 10.9s\n", - "Downloading (1) 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.0s\n", - "Downloading (1) 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G_openmp_mutex 20.8kB @ 34.4kB/s 0.6s\n", - "[+] 11.1s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.2s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.3s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.4s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.5s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.6s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.7s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.8s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 11.9s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.0s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.1s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.2s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.3s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.4s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.5s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.6s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.7s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.8s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 12.9s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.0s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.1s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.2s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.3s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.4s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.5s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.6s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.7s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.8s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 13.9s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.0s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.1s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.2s\n", - "Downloading 100%\n", - "Extracting (49) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.3s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.4s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.5s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.6s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.7s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.8s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 14.9s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.0s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.1s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.2s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.3s\n", - "Downloading 100%\n", - "Extracting (48) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.4s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.5s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.6s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.7s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.8s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 15.9s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.0s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.1s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.2s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.3s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.4s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.5s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.6s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.7s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.8s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 16.9s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.0s\n", - "Downloading 100%\n", - "Extracting (47) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.1s\n", - "Downloading 100%\n", - "Extracting (44) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.2s\n", - "Downloading 100%\n", - "Extracting (44) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.3s\n", - "Downloading 100%\n", - "Extracting (44) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.4s\n", - "Downloading 100%\n", - "Extracting (40) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.5s\n", - "Downloading 100%\n", - "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.6s\n", - "Downloading 100%\n", - "Extracting (39) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.7s\n", - "Downloading 100%\n", - "Extracting (38) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.8s\n", - "Downloading 100%\n", - "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 17.9s\n", - "Downloading 100%\n", - "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.0s\n", - "Downloading 100%\n", - "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.1s\n", - "Downloading 100%\n", - "Extracting (36) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.2s\n", - "Downloading 100%\n", - "Extracting (35) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.3s\n", - "Downloading 100%\n", - "Extracting (34) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.4s\n", - "Downloading 100%\n", - "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.5s\n", - "Downloading 100%\n", - "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.6s\n", - "Downloading 100%\n", - "Extracting (33) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.7s\n", - "Downloading 100%\n", - "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.8s\n", - "Downloading 100%\n", - "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 18.9s\n", - "Downloading 100%\n", - "Extracting (30) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.0s\n", - "Downloading 100%\n", - "Extracting (29) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.1s\n", - "Downloading 100%\n", - "Extracting (28) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.2s\n", - "Downloading 100%\n", - "Extracting (28) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.3s\n", - "Downloading 100%\n", - "Extracting (28) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.4s\n", - "Downloading 100%\n", - "Extracting (27) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.5s\n", - "Downloading 100%\n", - "Extracting (26) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.6s\n", - "Downloading 100%\n", - "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.7s\n", - "Downloading 100%\n", - "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.8s\n", - "Downloading 100%\n", - "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 19.9s\n", - "Downloading 100%\n", - "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.0s\n", - "Downloading 100%\n", - "Extracting (25) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.1s\n", - "Downloading 100%\n", - "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.2s\n", - "Downloading 100%\n", - "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.3s\n", - "Downloading 100%\n", - "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.4s\n", - "Downloading 100%\n", - "Extracting (24) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.5s\n", - "Downloading 100%\n", - "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.6s\n", - "Downloading 100%\n", - "Extracting (23) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.7s\n", - "Downloading 100%\n", - "Extracting (22) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.8s\n", - "Downloading 100%\n", - "Extracting (22) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 20.9s\n", - "Downloading 100%\n", - "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.0s\n", - "Downloading 100%\n", - "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.1s\n", - "Downloading 100%\n", - "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.2s\n", - "Downloading 100%\n", - "Extracting (21) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.3s\n", - "Downloading 100%\n", - "Extracting (20) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.4s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.5s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.6s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.7s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.8s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 21.9s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.0s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.1s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.2s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.3s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.4s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.5s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.6s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.7s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.8s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 22.9s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.0s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.1s\n", - "Downloading 100%\n", - "Extracting (19) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.2s\n", - "Downloading 100%\n", - "Extracting (18) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 23.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 24.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 25.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 26.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 27.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 28.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 29.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 30.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 31.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 32.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 33.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 34.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.4s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.5s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.6s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.7s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.8s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 35.9s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.0s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.1s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.2s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.3s\n", - "Downloading 100%\n", - "Extracting (17) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.4s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.5s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.6s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.7s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.8s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 36.9s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.0s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.1s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.2s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.3s\n", - "Downloading 100%\n", - "Extracting (16) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.4s\n", - "Downloading 100%\n", - "Extracting (15) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.5s\n", - "Downloading 100%\n", - "Extracting (15) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.6s\n", - "Downloading 100%\n", - "Extracting (15) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.7s\n", - "Downloading 100%\n", - "Extracting (14) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.8s\n", - "Downloading 100%\n", - "Extracting (13) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 37.9s\n", - "Downloading 100%\n", - "Extracting (12) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.0s\n", - "Downloading 100%\n", - "Extracting (12) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.1s\n", - "Downloading 100%\n", - "Extracting (12) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.2s\n", - "Downloading 100%\n", - "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.3s\n", - "Downloading 100%\n", - "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.4s\n", - "Downloading 100%\n", - "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.5s\n", - "Downloading 100%\n", - "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.6s\n", - "Downloading 100%\n", - "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.7s\n", - "Downloading 100%\n", - "Extracting (11) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.8s\n", - "Downloading 100%\n", - "Extracting (10) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 38.9s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.0s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.1s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.2s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.3s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.4s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.5s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.6s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.7s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.8s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 39.9s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.0s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.1s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.2s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.3s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.4s\n", - "Downloading 100%\n", - "Extracting (9) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.5s\n", - "Downloading 100%\n", - "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.6s\n", - "Downloading 100%\n", - "Extracting (7) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.7s\n", - "Downloading 100%\n", - "Extracting (6) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.8s\n", - "Downloading 100%\n", - "Extracting (5) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 40.9s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.0s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.1s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.2s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.3s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.4s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.5s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.6s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.7s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.8s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 41.9s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.0s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.1s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.2s\n", - "Downloading 100%\n", - "Extracting (4) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.3s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.4s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.5s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.6s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.7s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.8s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 42.9s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.0s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.1s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.2s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.3s\n", - "Downloading 100%\n", - "Extracting (3) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.4s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.5s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.6s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.7s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.8s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 43.9s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.0s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.1s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.2s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.3s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.4s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.5s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.6s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.7s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.8s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 44.9s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.0s\n", - "Downloading 100%\n", - "Extracting (2) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.1s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.2s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.3s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.4s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.5s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.6s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.7s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.8s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 45.9s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.0s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.1s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.2s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.3s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.4s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.5s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.6s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.7s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.8s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 46.9s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.0s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.1s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.2s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.3s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.4s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.5s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.6s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.7s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.8s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 47.9s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G[+] 48.0s\n", - "Downloading 100%\n", - "Extracting (1) | \u001b[2K\u001b[1A\u001b[2K\u001b[1A\u001b[2K\u001b[0G\u001b[?25hLinking _libgcc_mutex-0.1-main\n", - "Linking libstdcxx-ng-11.2.0-h1234567_1\n", - "Linking ld_impl_linux-64-2.40-h12ee557_0\n", - "Linking ca-certificates-2024.9.24-h06a4308_0\n", - "Linking libgomp-11.2.0-h1234567_1\n", - "Linking _openmp_mutex-5.1-1_gnu\n", - "Linking libgcc-ng-11.2.0-h1234567_1\n", - "Linking yaml-0.1.7-had09818_2\n", - "Linking libuuid-1.41.5-h5eee18b_0\n", - "Linking gmp-6.2.1-h295c915_3\n", - "Linking ncurses-6.4-h6a678d5_0\n", - "Linking bzip2-1.0.8-h5eee18b_6\n", - "Linking libev-4.33-h7f8727e_1\n", - "Linking c-ares-1.19.1-h5eee18b_0\n", - "Linking libiconv-1.16-h5eee18b_3\n", - "Linking libffi-3.4.4-h6a678d5_1\n", - "Linking xz-5.4.6-h5eee18b_1\n", - "Linking zlib-1.2.13-h5eee18b_1\n", - "Linking openssl-1.1.1w-h7f8727e_0\n", - "Linking libxcb-1.15-h7f8727e_0\n", - "Linking jpeg-9e-h5eee18b_3\n", - "Linking icu-58.2-he6710b0_3\n", - "Linking expat-2.6.3-h6a678d5_0\n", - "Linking libedit-3.1.20230828-h5eee18b_0\n", - "Linking readline-8.2-h5eee18b_0\n", - "Linking tk-8.6.14-h39e8969_0\n", - "Linking pcre2-10.42-hebb0a14_1\n", - "Linking libpng-1.6.39-h5eee18b_0\n", - "Linking libssh2-1.10.0-h37d81fd_2\n", - "Linking libnghttp2-1.52.0-ha637b67_1\n", - "Linking krb5-1.20.1-h568e23c_1\n", - "Linking sqlite-3.45.3-h5eee18b_0\n", - "Linking ruby-2.5.1-haf1161a_0\n", - "Linking libglib-2.78.4-hdc74915_0\n", - "Linking freetype-2.12.1-h4a9f257_0\n", - "Linking libcurl-8.2.1-h91b91d3_0\n", - "Linking python-3.7.16-h7a1cb2a_0\n", - "Linking wheel-0.38.4-py37h06a4308_0\n", - "Linking glib-tools-2.78.4-h6a678d5_0\n", - "Linking curl-8.2.1-h37d81fd_0\n", - "Linking certifi-2022.12.7-py37h06a4308_0\n", - "Linking libgit2-1.6.4-ha637b67_0\n", - "Linking setuptools-65.6.3-py37h06a4308_0\n", - "Linking pip-22.3.1-py37h06a4308_0\n", - "Linking glib-2.78.4-h6a678d5_0\n", - "Linking gstreamer-1.14.1-h5eee18b_1\n", - "Linking dbus-1.13.18-hb2f20db_0\n", - "Linking gst-plugins-base-1.14.1-h6a678d5_1\n", - "Linking libxml2-2.9.9-20220706_155948\n", - "Linking fontconfig-2.13.0-h9420a91_0\n", - "Linking qt-5.9.7-h5867ecd_1\n", - "Linking klayout-0.28.17_212_gfa14afbbf-20240223_100318_py37\n", - "\n", - "Transaction finished\n", - "\n" - ] - } - ], - "source": [ - "# Setup the environment for the OpenFASOC GDSFactory generator\n", - "# You only need to run this block once!\n", - "\n", - "# Clone OpenFASoC\n", - "!git clone https://github.com/idea-fasoc/OpenFASOC\n", - "# Install python dependencies\n", - "!pip install sky130\n", - "!pip install gf180 prettyprinttree svgutils\n", - "!pip install gdsfactory==7.7.0\n", - "\n", - "import pathlib\n", - "import os\n", - "# Install KLayout (via conda)\n", - "!curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba\n", - "conda_prefix_path = pathlib.Path('conda-env')\n", - "CONDA_PREFIX = str(conda_prefix_path.resolve())\n", - "%env CONDA_PREFIX={CONDA_PREFIX}\n", - "\n", - "!bin/micromamba create --yes --prefix $CONDA_PREFIX\n", - "# Install from the litex-hub channel\n", - "!bin/micromamba install --yes --prefix $CONDA_PREFIX \\\n", - " --channel litex-hub \\\n", - " --channel main \\\n", - " klayout" - ] - }, - { - "cell_type": "markdown", - "source": [ - " klayoutバイナリをシステムパスに追加し、GLayoutディレクトリに移動します。\n", - "(カーネルを再起動する度に実行する必要があります。)\n", - "\n", - "\n" - ], - "metadata": { - "id": "zjJ2eUWiaUbR" - } - }, - { - "cell_type": "code", - "source": [ - "# Setup the environment for the OpenFASOC GDSFactory generator\n", - "\n", - "# Adding micro-mamba binary directory to the PATH\n", - "# This directory contains Klayout\n", - "import pathlib\n", - "import os\n", - "conda_prefix_path = pathlib.Path('conda-env')\n", - "CONDA_PREFIX = str(conda_prefix_path.resolve())\n", - "\n", - "%env CONDA_PREFIX={CONDA_PREFIX}\n", - "# Add conda packages to the PATH\n", - "PATH = os.environ['PATH']\n", - "%env PATH={PATH}:{CONDA_PREFIX}/bin\n", - "\n", - "%cd /content/OpenFASOC/openfasoc/generators/glayout\n" - ], - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "xMUPna-sakFn", - "outputId": "eb5a0f92-3f32-4664-f938-b1afcf380066" - }, - "execution_count": 5, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "env: CONDA_PREFIX=/content/conda-env\n", - "env: PATH=/opt/bin:/usr/local/nvidia/bin:/usr/local/cuda/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/tools/node/bin:/tools/google-cloud-sdk/bin:/content/conda-env/bin:/content/conda-env/bin\n", - "/content/OpenFASOC/openfasoc/generators/glayout\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "source": [], - "metadata": { - "id": "sVWvV2Pwg9Ew" - } - }, - { - "cell_type": "markdown", - "source": [ - "# cell_config.py" - ], - "metadata": { - "id": "471iz7QIa3Iw" - } - }, - { - "cell_type": "code", - "source": [ - "from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict\n", - "#from glayout.flow.pdk.gf180_mapped import gf180\n", - "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", - "from glayout.flow.pdk.mappedpdk import MappedPDK\n", - "from glayout.flow.pdk.util.comp_utils import evaluate_bbox\n", - "from gdsfactory import Component\n", - "from gdsfactory.components import rectangle\n", - "from glayout.flow.primitives.fet import pmos\n", - "from glayout.flow.primitives.fet import nmos\n", - "from glayout.flow.routing.straight_route import straight_route\n", - "from glayout.flow.routing.c_route import c_route\n", - "from glayout.flow.routing.L_route import L_route\n", - "from glayout.flow.routing.smart_route import smart_route\n", - "from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized\n", - "from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized\n", - "from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port\n", - "\n", - "def add_port_lvs(pdk: MappedPDK, comp: Component, port_list: list[ dict[str, Union[float, str]] ]) -> Component:\n", - "\t'''\n", - " To add external I/O ports onto the cell for LVS\n", - "\n", - "\t@ args:\n", - " \t# pdk: please refer to the glayout library\n", - " \t# comp: please refer to the glayout library\n", - " \t# port_list: tuple[ dict[str, Union[float, str]] ] specifying new port's corresponding pin size, and\n", - "\t\t\t\t\t the name of new port and exiting port managed to align with in the given\n", - "\t\t\t\t\t component, e.g.\n", - "\t\t\t\t\t \t(\n", - "\t\t\t\t\t\t\t{\n", - "\t\t\t\t\t\t\t\t\"new_port\": \"drain_new\",\n", - "\t\t\t\t\t\t\t\t\"new_port_label\": \"drain_new_label\",\n", - "\t\t\t\t\t\t\t\t\"pin_width\": 0.5,\n", - "\t\t\t\t\t\t\t\t\"pin_height\": 0.5,\n", - "\t\t\t\t\t\t\t\t\"ref_port\": \"multiplier_0_drain_E\"\n", - "\t\t\t\t\t\t\t},\n", - "\t\t\t\t\t\t\t{\n", - "\t\t\t\t\t\t\t\t\"new_port\": \"source_new\",\n", - "\t\t\t\t\t\t\t\t\"new_port_label\": \"source_new_label\",\n", - "\t\t\t\t\t\t\t\t\"pin_width\": 1.5,\n", - "\t\t\t\t\t\t\t\t\"pin_height\": 1.5,\n", - "\t\t\t\t\t\t\t\t\"ref_port\": \"multiplier_0_source_E\"\n", - "\t\t\t\t\t\t\t}\n", - "\t\t\t\t\t\t)\n", - "\n", - "\t\t# return: gdsfactory.Component\n", - "\n", - "\t@ Limitations:\n", - "\t\t# So far, only skywater130 process is validated\n", - "\t'''\n", - "\n", - "\t# Add pins and text labels for LVS\n", - "\tpins_labels_info = list() # list that contains all port and component information\n", - "\tprint(f\"port_list: {port_list}\")\n", - "\tfor port in port_list:\n", - "\t\t# To get the layer's data type mapped to the GDS\n", - "\t\tref_port_layer = comp.ports[ port[\"ref_port\"] ].layer[0] # [0]: layer mapping, [1]: pin, drawing, label, net, etc.\n", - "\n", - "\t\t# To create the pin w/ label where the layer[1] is mapped to 16\n", - "\t\tnew_port_pin = rectangle(layer=(ref_port_layer, 16), size=(port[\"pin_width\"], port[\"pin_height\"]),centered=True).copy() # True set rectangle's centroid to the relative (0, 0)\n", - "\t\tnew_port_pin.add_label(text=port[\"new_port_label\"], layer=(ref_port_layer, 5)) # layer[1]=5 mapped to the \"label\" datatype in the GDS\n", - "\n", - "\t\t# To align the new port with the designated port existing in the given component\n", - "\t\talignment = ('c', 'b')\n", - "\t\tcomp_ref = align_comp_to_port(new_port_pin, comp.ports[ port[\"ref_port\"] ], alignment=alignment)\n", - "\t\tcomp.add(comp_ref)\n", - "\n", - "\treturn comp\n", - "\n" - ], - "metadata": { - "id": "fWFYNrTUa_7n" - }, - "execution_count": 6, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# inv_lib.py" - ], - "metadata": { - "id": "s0MLpq3xcaO4" - } - }, - { - "cell_type": "code", - "source": [ - "#from glayout.flow.pdk.gf180_mapped import gf180\n", - "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", - "from glayout.flow.pdk.mappedpdk import MappedPDK\n", - "from glayout.flow.pdk.util.comp_utils import prec_ref_center, movex, movey, evaluate_bbox, align_comp_to_port\n", - "from gdsfactory import Component\n", - "from gdsfactory.components import rectangle\n", - "from glayout.flow.primitives.fet import pmos\n", - "from glayout.flow.primitives.fet import nmos\n", - "from glayout.flow.routing.straight_route import straight_route\n", - "from glayout.flow.routing.c_route import c_route\n", - "from glayout.flow.routing.L_route import L_route\n", - "from glayout.flow.routing.smart_route import smart_route\n", - "\n", - "def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_width, nmos_length, orientation):\n", - "\t# Create a top level component\n", - "\ttop_level = Component(component_name)\n", - "\t# To prepare one PMOS and one NMOS for the subsequent inverter cell construction\n", - "\tpfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length)\n", - "\tnfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length)\n", - "\n", - "\t# Instantiation of above PMOS and NMOS under the top level\n", - "\tpfet_ref = prec_ref_center(pfet)\n", - "\tnfet_ref = prec_ref_center(nfet)\n", - "\ttop_level.add(pfet_ref)\n", - "\ttop_level.add(nfet_ref)\n", - "\n", - "\t# Placement (relative move)\n", - "\tmos_spacing = pdk.util_max_metal_seperation()\n", - "\tif(orientation==\"horizontal\"):\n", - "\t\tpfet_ref.rotate(90)\n", - "\t\tnfet_ref.rotate(90)\n", - "\telse:\n", - "\t\tpass\n", - "\tpfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)\n", - "\n", - "\t# Routing\n", - "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_drain_E\"], nfet_ref.ports[\"multiplier_0_drain_E\"])\n", - "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_gate_W\"], nfet_ref.ports[\"multiplier_0_gate_W\"])\n", - "\n", - "\t# To add the ports\n", - "\ttop_level.add_ports(pfet_ref.get_ports_list(), prefix=\"pmos_\")\n", - "\ttop_level.add_ports(nfet_ref.get_ports_list(), prefix=\"nmos_\")\n", - "\n", - "\treturn top_level" - ], - "metadata": { - "id": "VZoH8lTCcecm" - }, - "execution_count": 7, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# transmission_gate.py" - ], - "metadata": { - "id": "ZQOZALxpcgFc" - } - }, - { - "cell_type": "code", - "source": [ - "from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict\n", - "#from glayout.flow.pdk.gf180_mapped import gf180\n", - "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", - "from glayout.flow.pdk.mappedpdk import MappedPDK\n", - "from glayout.flow.pdk.util.comp_utils import evaluate_bbox\n", - "from gdsfactory import Component\n", - "from gdsfactory.components import rectangle\n", - "from glayout.flow.primitives.fet import pmos\n", - "from glayout.flow.primitives.fet import nmos\n", - "from glayout.flow.routing.straight_route import straight_route\n", - "from glayout.flow.routing.c_route import c_route\n", - "from glayout.flow.routing.L_route import L_route\n", - "from glayout.flow.routing.smart_route import smart_route\n", - "from glayout.flow.placement.two_transistor_interdigitized import two_nfet_interdigitized\n", - "from glayout.flow.placement.two_transistor_interdigitized import two_pfet_interdigitized\n", - "from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port\n", - "\n", - "# My own cell library\n", - "#from inv_lib import reconfig_inv\n", - "#import cell_config as config\n", - "\n", - "def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_width, pmos_length, nmos_width, nmos_length):\n", - "\t# To prepare all necessary cells to construct a transmission gate, i.e.\n", - "\t# 1) PMOS\n", - "\t# 2) NMOS\n", - "\tpfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=pmos_width, length=pmos_length)\n", - "\tnfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=nmos_width, length=nmos_length)\n", - "\n", - "\t# Placement and adding ports\n", - "\ttop_level = Component(name=\"TG\")\n", - "\tpfet_ref = prec_ref_center(pfet)\n", - "\tnfet_ref = prec_ref_center(nfet)\n", - "\ttop_level.add(pfet_ref)\n", - "\ttop_level.add(nfet_ref)\n", - "\n", - "\t# Placement\n", - "\tmos_spacing = pdk.util_max_metal_seperation()\n", - "\t#mos_spacing = pdk.get_grule(\"met1\")[\"min_width\"])\n", - "\tif flip_config[\"degree\"] != None:\n", - "\t\tpfet_ref.rotate(flip_config[\"degree\"])\n", - "\t\tnfet_ref.rotate(flip_config[\"degree\"])\n", - "\tpfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing)\n", - "\n", - "\t# Routing\n", - "\t# To simplify the routing for the parallel-gate transistors, the layout is realised as follow which is expected to be equivalent to a TG\n", - "\t# a) PMOS.source connected to NMOS.source\n", - "\t# b) PMOS.drain connected to NMOS.drain\n", - "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_source_E\"], nfet_ref.ports[\"multiplier_0_source_E\"]) # \"in\" of the TG\n", - "\ttop_level << smart_route(pdk, pfet_ref.ports[\"multiplier_0_drain_W\"], nfet_ref.ports[\"multiplier_0_drain_E\"]) # \"out\" of the TG\n", - "\n", - "\ttop_level.add_ports(pfet_ref.get_ports_list(), prefix=\"pmos_\")\n", - "\ttop_level.add_ports(nfet_ref.get_ports_list(), prefix=\"nmos_\")\n", - "\t#top_level.add_port(\n", - "\t#\tname=\"\", center=[0, width / 2], width=width, orientation=180, layer=layer\n", - "\t#)\n", - "\n", - "\t# Add pins and text labels for LVS\n", - "\tpins_labels_info = list() # list that contains all port and component information\n", - "\t# To define the layers\n", - "\tgds_met1 = pdk.get_glayer(\"met2\")[0]\n", - "\tgds_met2 = gds_met1+1\n", - "\tgds_met3 = gds_met2+1\n", - "\tgds_met4 = gds_met3+1\n", - "\tgds_met5 = gds_met4+1\n", - "\t# To get the respective layers of the underlying TG's PMOS.source port PMOS.drain port\n", - "\ttg_din_portLayer = top_level.ports[\"pmos_multiplier_0_source_W\"].layer[0]\n", - "\ttg_dout_portLayer = top_level.ports[\"pmos_multiplier_0_drain_E\"].layer[0]\n", - "\t# To create the pins w/ labels and append to info list\n", - "\ttg_din_pin = rectangle(layer=(tg_din_portLayer, 16), size=(1, 1),centered=True).copy() # True set rectangle's centroid to the relative (0, 0)\n", - "\ttg_dout_pin = rectangle(layer=(tg_dout_portLayer, 16), size=(1, 1), centered=True).copy()\n", - "\ttg_din_pin.add_label(text=\"Vin\", layer=(tg_din_portLayer, 5))\n", - "\ttg_dout_pin.add_label(text=\"Vout\", layer=(tg_dout_portLayer, 5))\n", - "\tpins_labels_info.append((tg_din_pin, top_level.ports[\"pmos_multiplier_0_source_W\"], None))\n", - "\tpins_labels_info.append((tg_dout_pin, top_level.ports[\"pmos_multiplier_0_drain_E\"], None))\n", - "\n", - "\t#print(top_level.ports[\"pmos_multiplier_0_source_W\"].name)\n", - "\t#top_level.pprint_ports()\n", - "\n", - "\t# Move everythin to position\n", - "\tfor comp, prt, alignment in pins_labels_info:\n", - "\t\talignment = ('c', 'b') if alignment is None else alignment\n", - "\t\tcompref = align_comp_to_port(comp, prt, alignment=alignment)\n", - "\t\t#top_level.add(compref)\n", - "\n", - "\treturn top_level #top_level.flatten()\n", - "\n", - "def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length):\n", - "\t# To prepare all necessary cells to construct a transmission gate, i.e.\n", - "\t# 1) transmission gate\n", - "\t# 2) Inverter\n", - "\ttg = naive_tg_cell(pdk=pdk, flip_config={\"degree\": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length)\n", - "\tinv = reconfig_inv(pdk=pdk, component_name=\"gate_ctrl_inv\", pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation=\"horizontal\")\n", - "\n", - "\t# Instantiation of the essential cells\n", - "\ttop_level = Component(name=\"tg_with_inv\")\n", - "\ttg_ref = prec_ref_center(tg)\n", - "\tinv_ref = prec_ref_center(inv)\n", - "\ttop_level.add(tg_ref)\n", - "\ttop_level.add(inv_ref)\n", - "\n", - "\t# Placement\n", - "\tmos_spacing = pdk.util_max_metal_seperation()\n", - "\tnwell_min_spacing = pdk.get_grule(\"nwell\")[\"min_separation\"]\n", - "\tinv_cell_width = inv_ref.xsize # or = evaluate_bbox(inv)[0]\n", - "\ttg_ref.movex(inv_cell_width + nwell_min_spacing)\n", - "\n", - "\t# Routing\n", - "\t# 1) PMOS of the TG is switched on/off by the inverter's output\n", - "\t# 2) NMOS of the TG is switched on/off by an external control signal connected to inverter's input port as well\n", - "\ttop_level << smart_route(pdk, inv_ref.ports[\"pmos_multiplier_0_drain_E\"], tg_ref.ports[\"pmos_multiplier_0_gate_W\"])\n", - "\ttop_level << smart_route(pdk, inv_ref.ports[\"nmos_multiplier_0_gate_S\"], tg_ref.ports[\"nmos_multiplier_0_gate_S\"])\n", - "\n", - "\t# Adding the ports\n", - "\ttop_level.add_ports(tg_ref.get_ports_list(), prefix=\"tg_\")\n", - "\ttop_level.add_ports(inv_ref.get_ports_list(), prefix=\"inv_\")\n", - "\n", - "\treturn top_level\n" - ], - "metadata": { - "id": "f9zRFCm6cl4N" - }, - "execution_count": 13, - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "# eval.py" - ], - "metadata": { - "id": "VLrreUmkcrg_" - } - }, - { - "cell_type": "code", - "source": [ - "#from glayout.flow.pdk.gf180_mapped import gf180\n", - "from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130\n", - "import gdstk\n", - "import svgutils.transform as sg\n", - "import IPython.display\n", - "from IPython.display import clear_output\n", - "\n", - "def display_gds(gds_file, image_filename: str, scale = 3):\n", - " # Generate an SVG image\n", - " top_level_cell = gdstk.read_gds(gds_file).top_level()[0]\n", - " top_level_cell.write_svg(image_filename)\n", - " # Scale the image for displaying\n", - " fig = sg.fromfile(image_filename)\n", - " fig.set_size((str(float(fig.width) * scale), str(float(fig.height) * scale)))\n", - " fig.save(image_filename)\n", - "\n", - " # Display the image\n", - " IPython.display.display(IPython.display.SVG(image_filename))\n", - "\n", - "def main():\n", - " tg_inst = tg_with_inv(pdk=sky130, pmos_width=1, pmos_length=0.15, nmos_width=1, nmos_length=0.15)\n", - " tg_inst = add_port_lvs(\n", - " pdk=sky130,\n", - " comp=tg_inst,\n", - " port_list=[\n", - " {\n", - " \"new_port\": \"tg_ctrl\",\n", - " \"new_port_label\": \"ctrl\",\n", - " \"pin_width\": tg_inst.ports[\"inv_nmos_multiplier_0_gate_S\"].width,\n", - " \"pin_height\": tg_inst.ports[\"inv_nmos_multiplier_0_gate_S\"].width,\n", - " \"ref_port\": \"inv_nmos_multiplier_0_gate_S\"\n", - " },\n", - " {\n", - " \"new_port\": \"tg_din\",\n", - " \"new_port_label\": \"din\",\n", - " \"pin_width\": 0.3,\n", - " \"pin_height\": 0.3,\n", - " \"ref_port\": \"tg_pmos_multiplier_0_source_W\"\n", - " },\n", - " {\n", - " \"new_port\": \"tg_dout\",\n", - " \"new_port_label\": \"dout\",\n", - " \"pin_width\": 0.3,\n", - " \"pin_height\": 0.3,\n", - " \"ref_port\": \"tg_nmos_multiplier_0_drain_N\"\n", - " }\n", - "\t ]\n", - "\t)\n", - " #tg_inst.flatten()\n", - " #tg_inst.show()\n", - " tg_inst.write_gds(\"tg_with_inv.gds\")\n", - " display_gds(gds_file=\"tg_with_inv.gds\", image_filename=\"tg_with_inv.svg\", scale=5)\n", - "\n", - "if __name__ == \"__main__\":\n", - " main()" - ], - "metadata": { - "id": "K3JfrIUWctcI", - "outputId": "b69ca1d4-6318-4a8c-b46c-47f42343f65d", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 1000 - } - }, - "execution_count": 25, - "outputs": [ - { - "output_type": "stream", - "name": "stderr", - "text": [ - ":51: UserWarning: Unnamed cells, 7 in 'tg_with_inv$6'\n", - " tg_inst.write_gds(\"tg_with_inv.gds\")\n", - "\u001b[32m2024-11-14 02:40:11.852\u001b[0m | \u001b[1mINFO \u001b[0m | \u001b[36mgdsfactory.component\u001b[0m:\u001b[36m_write_library\u001b[0m:\u001b[36m1851\u001b[0m - \u001b[1mWrote to 'tg_with_inv.gds'\u001b[0m\n" - ] - }, - { - "output_type": "stream", - "name": "stdout", - "text": [ - "port_list: [{'new_port': 'tg_ctrl', 'new_port_label': 'ctrl', 'pin_width': 0.33, 'pin_height': 0.33, 'ref_port': 'inv_nmos_multiplier_0_gate_S'}, {'new_port': 'tg_din', 'new_port_label': 'din', 'pin_width': 0.3, 'pin_height': 0.3, 'ref_port': 'tg_pmos_multiplier_0_source_W'}, {'new_port': 'tg_dout', 'new_port_label': 'dout', 'pin_width': 0.3, 'pin_height': 0.3, 'ref_port': 'tg_nmos_multiplier_0_drain_N'}]\n" - ] - }, - { - "output_type": "display_data", - "data": { - "text/plain": [ - "" - ], - "image/svg+xml": "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\ndout\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nctrl\n\n\n\ndin\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" - }, - "metadata": {} - } - ] - }, - { - "cell_type": "markdown", - "source": [ - "\n", - "\n", - "---\n", - "\n", - "\n", - "# トランスミッションゲートを表示させます。\n" - ], - "metadata": { - "id": "VTXMiC1nbFTu" - } - }, - { - "cell_type": "markdown", - "source": [ - "Geminiによると・・・\n", - "生成されたGDSファイルに名前のないセルがあるという警告が表示されているようです。この警告はgdsfactoryから発生し、「TG$2」セル内に明示的な名前が割り当てられていないコンポーネントがあることを示しています。\n", - "\n", - "すぐに問題が発生するわけではありませんが、整理とデバッグを改善するために、すべてのコンポーネントに名前を付けることをお勧めします。コンポーネントを作成するときに name 引数を指定することで、コンポーネントに名前を付けることができます。\n", - "\n", - "たとえば、transmissionGate_cell 関数では、pfet および nfet インスタンスに名前を付けることができます。\n", - "\n", - "\n", - "pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=width, length=length, name=\"pmos_instance\")\n", - "nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=width, length=length, name=\"nmos_instance\")\n", - "Use code with caution\n", - "これにより、GDSファイルがより読みやすくなり、扱いやすくなります。\n", - "\n", - "・・・らしいです" - ], - "metadata": { - "id": "xyQej3g8pIMq" - } - } - ] -} \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index 5757be092..f7e2fbc48 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -16,94 +16,19 @@ from glayout.flow.pdk.util.comp_utils import prec_ref_center, movey, evaluate_bbox, align_comp_to_port # My own cell library -from inv_lib import reconfig_inv -import cell_config as config - -''' -def naive_tg_cell(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): - # To prepare all necessary cells to construct a transmission gate, i.e. - # 1) PMOS - # 2) NMOS - pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) - nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) - - # Placement and adding ports - top_level = Component(name="TG") - pfet_ref = prec_ref_center(pfet) - nfet_ref = prec_ref_center(nfet) - top_level.add(pfet_ref) - top_level.add(nfet_ref) - top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") - top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - - # Placement - mos_spacing = pdk.util_max_metal_seperation() - #mos_spacing = pdk.get_grule("met1")["min_width"]) - pfet_ref.rotate(90) - nfet_ref.rotate(90) - pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) - - # Routing - top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG - top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_source_W"]) # "out" of the TG - - # Add pins and text labels for LVS - pins_labels_info = list() # list that contains all port and component information - # To define the layers - gds_met1 = pdk.get_glayer("met2")[0] - gds_met2 = gds_met1+1 - gds_met3 = gds_met2+1 - gds_met4 = gds_met3+1 - gds_met5 = gds_met4+1 - # To get the respective layers of the underlying TG's PMOS.source port PMOS.drain port - tg_din_portLayer = top_level.ports["pmos_multiplier_0_source_W"].layer[0] - tg_dout_portLayer = top_level.ports["pmos_multiplier_0_drain_E"].layer[0] - # To create the pins w/ labels and append to info list - tg_din_pin = rectangle(layer=(tg_din_portLayer, 16), size=(1, 1),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) - tg_dout_pin = rectangle(layer=(tg_dout_portLayer, 16), size=(1, 1), centered=True).copy() - tg_din_pin.add_label(text="Vin", layer=(tg_din_portLayer, 5)) - tg_dout_pin.add_label(text="Vout", layer=(tg_dout_portLayer, 5)) - pins_labels_info.append((tg_din_pin, top_level.ports["pmos_multiplier_0_source_W"], None)) - pins_labels_info.append((tg_dout_pin, top_level.ports["pmos_multiplier_0_drain_E"], None)) - - #print(top_level.ports["pmos_multiplier_0_source_W"].name) - #top_level.pprint_ports() - - # Move everythin to position - for comp, prt, alignment in pins_labels_info: - alignment = ('c', 'b') if alignment is None else alignment - compref = align_comp_to_port(comp, prt, alignment=alignment) - #top_level.add(compref) - - return top_level #top_level.flatten() - -def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): - # To prepare all necessary cells to construct a transmission gate, i.e. - # 1) transmission gate - # 2) Inverter - tg = naive_tg_cell(pdk=pdk, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length) - inv = reconfig_inv(pdk=pdk, component_name="gate_ctrl_inv", pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation="horizontal") - - # Placement and adding ports - top_level = Component(name="tg_with_inv") - tg_ref = prec_ref_center(tg) - inv_ref = prec_ref_center(inv) - top_level.add(tg_ref) - top_level.add(inv_ref) - top_level.add_ports(tg_ref.get_ports_list(), prefix="tg_") - top_level.add_ports(inv_ref.get_ports_list(), prefix="inv_") - - # Placement - mos_spacing = pdk.util_max_metal_seperation() - tg_ref.movex(evaluate_bbox(inv)[0] + mos_spacing) - - # Routing - #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_source_W"], nfet_ref.ports["multiplier_0_drain_W"]) # "in" of the TG - #top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"]) # "out" of the TG - - return top_level #top_level.flatten() -''' -def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_width, pmos_length, nmos_width, nmos_length): +from reconfig_inv import reconfig_inv + +#@cell +def tg_cell( + pdk: MappedPDK, + flip_config: + dict[str, Union[int, str]], + pmos_width, + pmos_length, + nmos_width, + nmos_length, + **kwargs +) -> Component: # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS # 2) NMOS @@ -111,7 +36,7 @@ def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_ nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=nmos_width, length=nmos_length) # Placement and adding ports - top_level = Component(name="TG") + top_level = Component(name="tg_1b") pfet_ref = prec_ref_center(pfet) nfet_ref = prec_ref_center(nfet) top_level.add(pfet_ref) @@ -119,7 +44,6 @@ def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_ # Placement mos_spacing = pdk.util_max_metal_seperation() - #mos_spacing = pdk.get_grule("met1")["min_width"]) if flip_config["degree"] != None: pfet_ref.rotate(flip_config["degree"]) nfet_ref.rotate(flip_config["degree"]) @@ -130,49 +54,19 @@ def naive_tg_cell(pdk: MappedPDK, flip_config: dict[str, Union[int, str]], pmos_ # 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_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met2") # "in" of the TG - top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_source_E"], glayer1="met1") # "out" of the TG + top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_source_E"], glayer1="met3") # "out" of the TG top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - #top_level.add_port( - # name="", center=[0, width / 2], width=width, orientation=180, layer=layer - #) - - # Add pins and text labels for LVS - pins_labels_info = list() # list that contains all port and component information - # To define the layers - gds_met1 = pdk.get_glayer("met2")[0] - gds_met2 = gds_met1+1 - gds_met3 = gds_met2+1 - gds_met4 = gds_met3+1 - gds_met5 = gds_met4+1 - # To get the respective layers of the underlying TG's PMOS.source port PMOS.drain port - tg_din_portLayer = top_level.ports["pmos_multiplier_0_source_W"].layer[0] - tg_dout_portLayer = top_level.ports["pmos_multiplier_0_drain_E"].layer[0] - # To create the pins w/ labels and append to info list - tg_din_pin = rectangle(layer=(tg_din_portLayer, 16), size=(1, 1),centered=True).copy() # True set rectangle's centroid to the relative (0, 0) - tg_dout_pin = rectangle(layer=(tg_dout_portLayer, 16), size=(1, 1), centered=True).copy() - tg_din_pin.add_label(text="Vin", layer=(tg_din_portLayer, 5)) - tg_dout_pin.add_label(text="Vout", layer=(tg_dout_portLayer, 5)) - pins_labels_info.append((tg_din_pin, top_level.ports["pmos_multiplier_0_source_W"], None)) - pins_labels_info.append((tg_dout_pin, top_level.ports["pmos_multiplier_0_drain_E"], None)) - - #print(top_level.ports["pmos_multiplier_0_source_W"].name) - #top_level.pprint_ports() - # Move everythin to position - for comp, prt, alignment in pins_labels_info: - alignment = ('c', 'b') if alignment is None else alignment - compref = align_comp_to_port(comp, prt, alignment=alignment) - #top_level.add(compref) - - return top_level #top_level.flatten() + return top_level -def tg_with_inv(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): +#@cell +def tg_with_ctrl(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): # To prepare all necessary cells to construct a transmission gate, i.e. # 1) transmission gate # 2) Inverter - tg = naive_tg_cell(pdk=pdk, flip_config={"degree": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length) + tg = tg_cell(pdk=pdk, flip_config={"degree": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length) inv = reconfig_inv(pdk=pdk, component_name="gate_ctrl_inv", pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation="horizontal") # Instantiation of the essential cells From cc695acec0735a37bf259fef6814026dd3747021 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Mon, 18 Nov 2024 15:34:35 +0000 Subject: [PATCH 16/21] Team: Salty Chip, Chipathon2024 Modify the PCell of the transmission gate composed of a basic TG cell and INV cell. The Magis DRC per basic cell and that of the top-level block have been performed w/o error --- .../transmission_gate_saltychip/eval.py | 71 +++++++++-- .../gds/gate_ctrl_inv.gds | Bin 0 -> 33536 bytes .../transmission_gate_saltychip/gds/tg.gds | Bin 0 -> 33566 bytes .../gds/tg_with_ctrl.gds | Bin 0 -> 67638 bytes .../gds/tg_with_inv.gds | Bin 61684 -> 0 bytes .../reconfig_inv.py | 67 ++++++----- .../transmission_gate.py | 111 ++++++++++++++++-- 7 files changed, 203 insertions(+), 46 deletions(-) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg.gds create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_ctrl.gds delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index 5720c73ae..c06f44f8f 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -1,29 +1,82 @@ -import transmission_gate as tg +import subprocess #from glayout.flow.pdk.gf180_mapped import gf180 from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 import reconfig_inv as reconfig_inv +import transmission_gate as tg TARGET_PDK = sky130 +PWD_OUTPUT = subprocess.run(['pwd'], capture_output=True, text=True) +GDS_DIR = PWD_OUTPUT.stdout.strip() + "/gds" -def main(): +pmos_width = 1 +pmos_length = 0.15 +nmos_width = 1 +nmos_length = 0.15 + +def basic_tg_eval(): + tg_dut = tg.tg_cell( + pdk=TARGET_PDK, + component_name="tg", + flip_config={"degree": 270}, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length + ) + + 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( pdk=TARGET_PDK, component_name="gate_ctrl_inv", - pmos_width=1, - pmos_length=0.15, - nmos_width=1, - nmos_length=0.15, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, orientation="horizontal" ) gate_ctrl_inv.show() - gate_ctrl_inv.write_gds("/home/tsengs0/gate_ctrl_inv.gds") - + gate_ctrl_inv.write_gds(f"{GDS_DIR}/{gate_ctrl_inv.name}.gds") magic_drc_result = sky130.drc_magic( layout=gate_ctrl_inv, design_name=gate_ctrl_inv.name#, #output_file=f"{absolute_path}/{gate_ctrl_inv.name}.rpt" ) - print("Magic DRC result: \n", magic_drc_result) + print(f"Magic DRC result ({gate_ctrl_inv.name}): \n", magic_drc_result) + print("--------------------------------------") + +def tg_with_ctrl_eval(): + tg_dut = tg.tg_with_ctrl( + pdk=TARGET_PDK, + component_name="tg_with_ctrl", + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length + ) + 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_dut.name}.rpt" + ) + print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result) + print("--------------------------------------") + +def main(): + basic_tg_eval() + gate_ctrl_inv_eval() + tg_with_ctrl_eval() if __name__ == "__main__": main() \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds new file mode 100644 index 0000000000000000000000000000000000000000..a62f5f98b480ec29d5e7705d6652e9dbb33d63a1 GIT binary patch literal 33536 zcmd^|53C(!na1aoasf+Gu>7g5VY|oz!7gCSpGpW~B^9+nQ>!BCs+wEvSG}S7hw^o`?~JjJUHH+p z6KgkA)to){Jax{e{%6_O=3M^f12=s3e~c4$ovq$}6=C7)m`wyZo+DSAyj-G$O z*t$#CPF#5Y1(%Mmy?8yfk2_)Ul2ykqUR`{8XZ)&(6PBEJ?!<}H$Im%nY~@84O{`hH zYW%!Kt4=z0;)IXZu6sxGsrL+g6mb))CRQD{>cnFe*Y8jM7jZ967q|Gh#S;^YPC9og zZsw<_i(9>9;-uqFI&V=O*FS>KyP%HStLoev2aS!Ld-0l&Ppn%vzWDe>OBR20)uK0? zSk2tKs>Wu|sFqe^`^~84RBx2a{;$38>4%hyb#a%f&L3;vBd-0nvi9VER8?+WMvule(d>VT@ z>HXeg^_ce-zop#b9nbdrJ07X383&uZK91LPpk~rjoxHc+TITncvN!HzS&I9gzzNg3 zSa&SszcKIa&k%nMG2(mRmkL@xCgjJ_vX=Nm$rC5wHws!mv@4&SpXK~7<@`kJ;xzfC z|5?Py|3WDLruA7NKa9BkC&=wir^+poH=eK4(3Y zf7AMkP=Clj@yp1Q|Er+jbG^<<9G6T)*s3YBWnD4_VgFCQNG$(NzDT^r??0PKMi-~4@7bR4K^@mMr>`H!uktlcMC~{E zHm!GzpX8fyny7Ir|EBe>@vFM7Pn;x)|!87V>||dinol_Whrxbur{O_un>RNUNTM+JC0?Z6SYX{1N{^ z?%&JgtAD2T2SR?Fe+aK!$8}BXv3_y>BX<)u?-W^n!m`!0p4dEprsI#;pR*j3`5vx1 zcv+d&TjvjAf538RCgf3zNdSaPhoIi;DBI`ey`33lG-ka7x8OCoMe>V_+0ePav;UfjD=WFzQ{Z)+roaeY* z%YUWy$EW5G>R*T7Rq)Y*U(33=Dr|rBul;ZTrnW=6*|q)7|7`voQOCnzTqV8Sf3d#$ zP2JvW3O4)Lp0DF?IA8S#$7Q2_WB%)L?XL4jPuCw@{|spT;LyKDewaVWPxGfZ{rp*s zU+SGk?eAv(3ZBb*)B1PY>-Uc*{yy@=KfsF%TE8#k7yT!m?<$ku$owN*$9vQIH>Sz= z_0Q=3i}Al(^&9=`AIaz7qyG*T`Zu8UBZL32|J1ksd=~M2Ec9+?f?qksKF$f1w@ z53H|jfX7xRnxi(V~cnZt5f!H;C! zoD=%j$e;Xroj>58>-!aoOT{m;`FPk67kG^;7dR5=MGkd4=9^K@;*qr}7em+Co zVZ@8d(>c_%eptwl`=9T9n*a3uZ!qt99<(0kzvzGT`f>a$rMAY~M8R}Fg!kqLga1&! z`Mr%kKF1vPe8K7Zm%cv{lh6OX$Em0Dh^X_AuLtV&W&eHsvPyS6dylicKt1l|)#UX! z%LWtuR+ei`>zPLsoJ|b%Clh)7LfGzNzv=TFS8zP*=IoGP_bp#H_coDtIPu~#_&`DH zhll)Fe%XM96cj|llMQyM8W~zVn`f|U$()uyq^#}Va*SDW$ z{i1)w9>Fr3MdQTOxRGwQ?muEqWjQ=^8RYnxG_AMpKVlcL%*|W@*RYt@TlXKaue83m z-`lG`XuI8yw7zZp>{k6^|B>(duIKvp)2v_YKaDRI9oIVk%@?w6-a3u{!SP4z{VbbU zo?v;Pp!NGheyqQd_{}WhGc4N*THhS?bzNt7>U;Y|ZLj)ZPR(~6$KS~Hqkq>| z-CgT{(Le2f;5C|RQb<*0#5MWwBEY^h+jnf=FDf{8s3}MTlXLFue83m zU)1)h52pH(*0+tH-Kt;gKYxC%>;2%qo3a1lx(JpJ~17xNj}r={imR^&Le1 zGp$$8h58Num5vwrUjpSn(|Ywx$Zz`JLLUCBCn5d^w7w0jq-`M(>= zziE9uPW8}&IQBeL9t&1UlsQ;|jI6W0={+lRh zJ&xa||C`BU{_N}cxul@=IR7^NZzPZTv;Q>QP|*6uo%q){J(axcp!}QG%0&DtV_v`8Tb{@!RzOTJq#y$Bq1()?XXy zH~r5dPyRm)<=?bEE95u)Pd-K7spR#b{AW%+RqK;+{5JegK0=)Q>$s8sOzV@6g!&Et zlMj<8|8t@IXIh_pIONCrYRT?&QIiZ(#4P;`?sC-hqH*w z@P2SX>s{a9o+Vz}E3P14W5%@J_5JN>;tymI8Sj1d!?b>2@L%^Y-*-yB?Q_@s$NoJ@ zz1b`x`=QS`7|?qB{#*2qxlY^7{e#41>^qHF(|T+F$Wz_9nJdUw|4r+y{Uh&j;t$Mx zKl$@`Z(48dA9{#`@7`Xth~>dOVKclB=r@#>RE->Q2G zTJP%Ldg9e5k-k;;7PQ{gztR22{^?w=K8f^A|86*-^{)OcAYOeE)xV_$t#|cL$C&yg zs()t|wBFS}&6VntsQz*64`{usf1~@4{o99n>XWGcon6p+YyUXjw-V3%k*N9ODc+mb zTl+`+-NZA`C2HRLE$>b1t^Ff@Gx793QS;t&yf>}4_K*0{{TKZs|90vz&n1q-mw0bl z@9N)K#H&xD`gVCi>s|d@PQ3ags&Cg8wBFUfGl*B8MD^|Zg4VnGH@g4WztgCvK8fRS zV?pb&fARePH1YVX&ws=7ch;l-c>ibvG1Sp@N1AulKh3|Q^;kdnPvZzS*f%xzHT6Vv+j;rw6tCtllmb>@%Z2@=rW}_nq$JUI8CxF|8jR z>JRmwIj>KSwqpT{{AXHkzyCojzPZ0q`#%oKf2Q^J`ya$!Oa3!8drP4FXIgK+|3NIi zt1X#NLi|^z_160z#LNF(nZJYhuT1Ol`(va3)otWyJGMjo4`}_io%H`Q^0XZ{LHReW zx8DCCUjEO|yaUR=X+3^_Z2BK3PyX+Q@^4y?-yfReN8?ofS3>zWt;g}(82{B_4rsmg{s-}!h}Sq3uY>Y$T94zm>7VPy+SbHa(F|BV7 z`NjAlPsiLHnS6K9vsgXT`W@5c5AJ^uZ=d#UT95vV{!v$R#;utzQ2!X-o7P+Z{foIy z+kJoL6TH@#HLb_`MgPcC{mq%r@LK&ht+)1%Jnip0GJnhKc`T;&*8Y(>feFHt52f(r*npBy{mtkE7d1a{aaDc zdRPBO_aFPW5B1b1QT;o+p!L@NalCIOo_Qis^M=kPruEkT5q~%F%yWsF_jK%;)?52W zJU!O@m#BH~Io_MrTl+`+=>CiTk$*e&nCB8T@4du((|T9`&LUoY64kfM3tI2$-*V#B zCsBR7wxIQ{{+&U*`Xs7v*B7+j)xXjG$Nrs0J@rXc-!>Ms9{bmE{v&rDi^hhtRD-fQ${vKRlqKa*WN7d?3DeCN+a?>%?yeQ$eP_mj~l zjQnKubWf$9@Yn3X;CcF8>%fW?-5oe_0Bd_-uH-M%?j3#?&_%Psf_PekZSg zXePb+9o2uEyouvle~Y|{lwd=9HU@B>+w5UF-H;m-}J99 zvMeE=pAV>MJ+bV6F-H=sx~{Wp^_%_~a_Mt)oyW^`y(d~<(Kg2tBj3w1ugd;S>&rrZ z)4%KNR(<-TXQ|{v&lRYDiPjT$t$)My-PgGP!guWSOeEin{)V27jQjsXc-MA{jGy#u zr)fQIe;mK>PUEwx-c2s!xB6GpdSZM3N3Y-XukoYLVgDunruDAzE8iNYBI7psH?4P# zU)6OT*EOwo)=%TJuFtql^%Jcp?pps`*PMR;`5J}45vAT=|Jm5){@aER^^xoQwEs-& z+rs=YH2%nWfJOW7WfqM;)A|D;Kh8g@>pHG$T95VXgo&7dSG5@jcwC`{1 zw=s(G&$abm|F;oh|4yTapJWlgz;bRu>#fg*6MG!X1(|vlZ5@kgz4h7XoaZ>_nbu=| z9RH)&Z#)~>Uxkm$Sj?~SdLfJ1`fND+?|I?|K6x!a_)oeS{TIi7k^iRrIih~+LZ54P zg%5YtsflbzeavJf2Qjv=Fi0G z=g(sNQumAW>bsf0g5T!7X}$H?aN<8l{C$~!fZyl6X}$H?aN=(uUeBe9e}s<|v>u-g zj_04z{TJhZx9T_g*FTca!AJickp2y5{m72}NB{cs$rIlP>ED3XTb~Ulp1$=D$<*)U z(Z9ZFz4h5};^o^ucg=sJeC1nUCb}$FSh?Wwto(MwBSdw zZni!fUdQq5cFG^{&sjHHpY5JLzwf%4?azkqR(>&mlK%r1u2-jiQ-;^4*SgvMY&da0 zC!YIiiRATosk}t%@!weE{^xsNn*YS<=D&J<`}Ona_2c;2#D3R!+gk8W-b*)IpA9Fj z@tZbiy8e`IwmuuqT(=)}raS*h*ZD845A%oban|=JnQPNM%Kc1oPG>pCq_108ZZWNA z^7$zqrhAirF!gz%ZrE?VTO2pVN$q!Zlh14Jw|w8FcOP+lze!vOf69B)ddK(H-dCy1 z#j7}}`!4*RiD?}+>*xDkueiRq-`h*y(ssLl_4>bL{czmwM*oZbhu5^f;W^rWH9Zc@ z_WegZ-#aH~WiEtoXECj}?muE*r~OxRatVAdOQ!Yq{YUI8t?%vk_@@s(Zc;z$(dyWam||1sWuJahb~<2%g*wa#(t^-ceS#$jWaQuC=&zWMJ$E8oxzkJ_+lHWq>am|vr9lo9SruEkSNBrxEf4Jt19(=F%Urp=n`;WL+ zTHo96^A>$b+wXp)_0w#BzHhS|^^5(7f7f?C*SDW${o=Y`+s~qZ+Y@hQ(fnsx-_YUz zAmT4%5$|I8KtbylhJ2s*>u19?Z%wd>_poUGGObU9{2~AB|JCGZKVAzpeoX7DLw@Yv zLBy{lPy9UmKtby(L;jF|;+K=BK5v5B52p3yA;0N=0eSMT=VIjFw7wwZH~sHVp8T(X z@^4z-Kjb(4??ayapAF^Tw7yTsZ}?BohvC1{c@X~tKFNFOPlo)4fBhzA^8acm|C!dg zFIvuj4gb|c&T=3>7D`p2ef`&$Zz_; zihTU*yPNzEX#J{?-}J9>D*xQOO8!mjar`#@>pENhb==6mY5nw2zv=%J^5p+Ucuqm< zr-b~be~nZ5Uj)^E(|R1gP5(XeXE{=Z3{{O<+jKao#Kx)}1C{xweJU-P&8 zo7Us_ZTi=FLjHB!$iHblo{2e zuj5AkP3y;p`c3}}$&>#pq5PZH7l!<1|20nK|1c>3ru8^}8~!JMPoDhixRL)%>yy6^ z^&9@vbJ6mDGWqhKX`R0tF6ZBd|MXij_@8`=1^)wT{7R4Gx9NW~G5DW+js^b%THhS% zH~rsEj;vM(0bSR&wKOtPnf=UYAh^afjjyztq=9%_TNL?%f!LSQ&_f7(fW>;r^)yA`{@2- z|Cnpi_f*X}+7FmEtq*;FFZxHX=Mk^_ETZnaXd6uHt^FgOYmIcDMb{j<|8m9@t+#)F zC!T#of9hxIPl3zH&$Qm&KjKICU-XasJ=DLN>AuZM>g)a$wBFUf^ej1jN~CY;S$)%b zNB{J@KI&8YeINbZg~o5D^{)O^U#|Nns&DC8|4j8SuP^7Hdi>_^|GVKo^snNWRi8xl ztby`h_3tR^Yy3g$?cxoyNM9v@S z8GX}wSO2c04rzU;^G5&vDO&IB-{rYaQ0I?yEt{G8m)5tRKX$`^?BBZFC#dsA|Dh?S z{-yPyejI;C5U)Oo>YL_&(|T9`=H>pu)IZI?>Z9gg&`;|_{c!%(Z`q_i!PLLArf9u$ z{EhBE_D|bT>fiXAMzjXA9B5>I_bJi=dD{* zzozw}`oX{MIi)z5^3;FjtN;4kv_AB|*#E@cN6d!Io1y;w# z8`aFTeqpFz_$N-=JCS)0)W5%&)?2S1iNB9!b>_8D_rFc+t3&-E|HQ9k`3lSDS$bEQi7nS}#4~@U-vkh! z<301|fEw5J`Z9mWKk-|MV;ord0 z^DZd=ru8^}oBnm4kbfOF@^4y?=Z~iUOUUCq(0>pz{|{)r_5K&}@~v?yo)6{Uv>wNA z)Bo}0$-j;p`8Tb%-v1(Az87X*3FY6k-g^Iwc=^^i6%T{*Z(5Jzx8a}rTeW{3H}aop zz5V_d@jCxLTeE*Ml>bcY?f1Wk$9MWoA@M2R<9|Sn-+FyH{+j+b6Q}D49Y6RV(0c3r zFXH9@_RN={t{+V6w}<0D)>pp93CEBB{k^93#L|Cb{MOem+>f<{o?pz zoyPp5ncLyhyf>|P{rm5|#6L_PO#kl7STL=3{`>De#hAG_SGy8*Gzx+aEAKF zduYAAf5gmU(LRJT_Jqr)XuZ9E#EC;BI!?pl z$y5KXnPTc6de`{N{%W7Q=0EoDWIkX0gQ;&fOwoFK|2WrZ&S#!WRQ>&VZ(5K0ujn6n zzaXCZPfY!L{S>XY_m4cCvzY(H)V~E&wBFu7@<#Vx^pE_*exaQ~vAq;rbyQzmwyID#7YgQ&jjg+M z?Zk!WUvTO8+Kbm;x_W%o#0g8zJ9pwlD(ziWW3y*e#olAKzLVv1EWe!MOpXNUChL>S iopfQk--qCPSFReyT>saM*R)XSkaDpu4yw+aS^Xb?z6k;V literal 0 HcmV?d00001 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg.gds new file mode 100644 index 0000000000000000000000000000000000000000..fc69a050f6959612b80c74fd6a2eaa4a294ba8db GIT binary patch literal 33566 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 literal 0 HcmV?d00001 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_ctrl.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_ctrl.gds new file mode 100644 index 0000000000000000000000000000000000000000..30152134b389dfbbab417ea9f53f2d42641878ce GIT binary patch literal 67638 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 literal 0 HcmV?d00001 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_inv.gds deleted file mode 100644 index 0e475572f10bbac3c96f480c5c96fe5822d2c0ea..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61684 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 DLAm1N diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py index 93ccdc341..8c9a255ee 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py @@ -12,7 +12,17 @@ from glayout.flow.routing.smart_route import smart_route #@cell -def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_width, nmos_length, orientation): +def reconfig_inv( + pdk: MappedPDK, + component_name, + pmos_width, + pmos_length, + nmos_width, + nmos_length, + orientation, + add_pin: bool = True, # For LVS + **kwargs +) -> Component: # Create a top level component top_level = Component(component_name) # To prepare one PMOS and one NMOS for the subsequent inverter cell construction @@ -44,33 +54,34 @@ def reconfig_inv(pdk: MappedPDK, component_name, pmos_width, pmos_length, nmos_w top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - # Add pins w/ labels for LVS - top_level.unlock() - pin_info = list() # list that contains all port and component information - met1_pin=(pdk.get_glayer("met1")[0], 20) - met1_label=(pdk.get_glayer("met1")[0], 5) - port_size = (0.24, 0.24) - # --- Port: A, i.e. input of the inverter - 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_gate_E"), None)) - # --- Port: Y, i.e. output of the inverver - 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_E"), None)) - # --- Port: VDD - VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VDD_pin.add_label(text="VDD", layer=met1_label) - pin_info.append((VDD_pin, top_level.ports.get(f"pmos_drain_E"), None)) - # --- Port: VSS - VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VSS_pin.add_label(text="VSS", layer=met1_label) - pin_info.append((VSS_pin, top_level.ports.get(f"nmos_source_W"), ('r', 't'))) + if add_pin == True: + # Add pins w/ labels for LVS + top_level.unlock() + pin_info = list() # list that contains all port and component information + met1_pin=(pdk.get_glayer("met1")[0], 20) + met1_label=(pdk.get_glayer("met1")[0], 5) + port_size = (0.24, 0.24) + # --- Port: A, i.e. input of the inverter + 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_gate_E"), None)) + # --- Port: Y, i.e. output of the inverver + 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_E"), None)) + # --- Port: VDD + VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VDD_pin.add_label(text="VDD", layer=met1_label) + pin_info.append((VDD_pin, top_level.ports.get(f"pmos_drain_E"), None)) + # --- Port: VSS + VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VSS_pin.add_label(text="VSS", layer=met1_label) + pin_info.append((VSS_pin, top_level.ports.get(f"nmos_source_W"), ('r', 't'))) - # Move everythin to position - for comp, prt, alignment in pin_info: - alignment = ('c', 'b') if alignment is None else alignment - comp_ref = align_comp_to_port(comp, prt, alignment=alignment) - top_level.add(comp_ref) + # Move everythin to position + for comp, prt, alignment in pin_info: + alignment = ('c', 'b') if alignment is None else alignment + comp_ref = align_comp_to_port(comp, prt, alignment=alignment) + top_level.add(comp_ref) return top_level diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index f7e2fbc48..d77a4a147 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -21,22 +21,24 @@ #@cell def tg_cell( pdk: MappedPDK, + component_name: str, flip_config: dict[str, Union[int, str]], pmos_width, pmos_length, nmos_width, nmos_length, + add_pin: bool = True, # For LVS **kwargs ) -> Component: # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS # 2) NMOS - pfet = pmos(pdk=pdk, with_substrate_tap=False, with_dummy=(True, False), width=pmos_width, length=pmos_length) - nfet = nmos(pdk=pdk, with_substrate_tap=False, with_dummy=(False, True), width=nmos_width, length=nmos_length) + 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) # Placement and adding ports - top_level = Component(name="tg_1b") + top_level = Component(name=component_name) pfet_ref = prec_ref_center(pfet) nfet_ref = prec_ref_center(nfet) top_level.add(pfet_ref) @@ -54,23 +56,81 @@ def tg_cell( # 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_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met2") # "in" of the TG - top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_W"], nfet_ref.ports["multiplier_0_source_E"], glayer1="met3") # "out" of the TG + top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"], glayer1="met2") # "out" of the TG + # Add the ports aligned with the basic PMOS and NMOS top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + if add_pin == True: + # Add pins w/ labels for LVS + top_level.unlock() + pin_info = list() # list that contains all port and component information + met1_pin=(pdk.get_glayer("met1")[0], 20) + met1_label=(pdk.get_glayer("met1")[0], 5) + port_size = (0.24, 0.24) + # --- 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)) + # --- 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"pmos_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) + pin_info.append((C_pin, top_level.ports.get(f"nmos_gate_N"), None)) + # --- Port: CBAR, i.e. gate control to the PMOS + CBAR_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + CBAR_pin.add_label(text="CBAR", layer=met1_label) + pin_info.append((CBAR_pin, top_level.ports.get(f"pmos_gate_N"), None)) + + # Move everythin to position + for comp, prt, alignment in pin_info: + alignment = ('c', 'b') if alignment is None else alignment + comp_ref = align_comp_to_port(comp, prt, alignment=alignment) + top_level.add(comp_ref) + return top_level #@cell -def tg_with_ctrl(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_length): +def tg_with_ctrl( + pdk: MappedPDK, + component_name: str, + pmos_width, + pmos_length, + nmos_width, + nmos_length, + add_pin: bool = True, # For LVS + **kwargs +) -> Component: # To prepare all necessary cells to construct a transmission gate, i.e. # 1) transmission gate # 2) Inverter - tg = tg_cell(pdk=pdk, flip_config={"degree": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length) - inv = reconfig_inv(pdk=pdk, component_name="gate_ctrl_inv", pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, orientation="horizontal") + tg = tg_cell( + pdk=pdk, + component_name="tg", + flip_config={"degree": 270}, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + add_pin=False + ) + inv = reconfig_inv( + pdk=pdk, + component_name="gate_ctrl_inv", + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + orientation="horizontal", + add_pin=False + ) # Instantiation of the essential cells - top_level = Component(name="tg_with_inv") + top_level = Component(name=component_name) tg_ref = prec_ref_center(tg) inv_ref = prec_ref_center(inv) top_level.add(tg_ref) @@ -91,6 +151,39 @@ def tg_with_ctrl(pdk: MappedPDK, pmos_width, pmos_length, nmos_width, nmos_lengt # Adding the ports top_level.add_ports(tg_ref.get_ports_list(), prefix="tg_") top_level.add_ports(inv_ref.get_ports_list(), prefix="inv_") + + if add_pin == True: + # Add pins w/ labels for LVS + top_level.unlock() + pin_info = list() # list that contains all port and component information + met1_pin=(pdk.get_glayer("met1")[0], 20) + met1_label=(pdk.get_glayer("met1")[0], 5) + port_size = (0.24, 0.24) + # --- 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"tg_nmos_drain_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"tg_pmos_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) + pin_info.append((C_pin, top_level.ports.get(f"inv_nmos_gate_N"), None)) + # --- Port: VDD + VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VDD_pin.add_label(text="VDD", layer=met1_label) + pin_info.append((VDD_pin, top_level.ports.get(f"inv_pmos_drain_E"), None)) + # --- Port: VSS + VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VSS_pin.add_label(text="VSS", layer=met1_label) + pin_info.append((VSS_pin, top_level.ports.get(f"inv_nmos_source_W"), ('r', 't'))) - return top_level + # Move everythin to position + for comp, prt, alignment in pin_info: + alignment = ('c', 'b') if alignment is None else alignment + comp_ref = align_comp_to_port(comp, prt, alignment=alignment) + top_level.add(comp_ref) + return top_level From 84b94b38f71bc7e0323f0c6201df421fa8af8518 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Wed, 20 Nov 2024 15:33:43 +0000 Subject: [PATCH 17/21] Team: Salty Chip, Chipathon2024 Modify the layout of both transmission gate and inverter in a interdititized fashion so as to contruct a CDAC switch Status: W.I.P. : --- .../transmission_gate_saltychip/eval.py | 14 +- .../reconfig_inv.py | 117 +++++++++++++++- .../transmission_gate.py | 131 +++++++++++++++++- 3 files changed, 247 insertions(+), 15 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index c06f44f8f..be09ed99e 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -8,20 +8,20 @@ PWD_OUTPUT = subprocess.run(['pwd'], capture_output=True, text=True) GDS_DIR = PWD_OUTPUT.stdout.strip() + "/gds" -pmos_width = 1 +pmos_width = 1.5 pmos_length = 0.15 -nmos_width = 1 +nmos_width = 1.5 nmos_length = 0.15 def basic_tg_eval(): - tg_dut = tg.tg_cell( + tg_dut = tg.reconfig_tg( pdk=TARGET_PDK, component_name="tg", - flip_config={"degree": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, - nmos_length=nmos_length + nmos_length=nmos_length, + add_pin=True ) tg_dut.show() @@ -42,7 +42,7 @@ def gate_ctrl_inv_eval(): pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, - orientation="horizontal" + add_pin=True ) gate_ctrl_inv.show() gate_ctrl_inv.write_gds(f"{GDS_DIR}/{gate_ctrl_inv.name}.gds") @@ -76,7 +76,7 @@ def tg_with_ctrl_eval(): def main(): basic_tg_eval() gate_ctrl_inv_eval() - tg_with_ctrl_eval() + #tg_with_ctrl_eval() if __name__ == "__main__": main() \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py index 8c9a255ee..5d29cb6be 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py @@ -1,3 +1,4 @@ +from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict #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 @@ -11,8 +12,10 @@ from glayout.flow.routing.L_route import L_route from glayout.flow.routing.smart_route import smart_route +LONG_CHANNEL_WIDTH = 1.5 + #@cell -def reconfig_inv( +def short_channel_inv( pdk: MappedPDK, component_name, pmos_width, @@ -85,3 +88,115 @@ def reconfig_inv( top_level.add(comp_ref) return top_level + +#@cell +def long_channel_inv( + pdk: MappedPDK, + component_name, + pmos_width, + pmos_length, + nmos_width, + nmos_length, + orientation_config: dict[str, Union[int, str]], + add_pin: bool = True, # For LVS + **kwargs +) -> Component: + # Create a top level component + top_level = Component(component_name) + # To prepare one PMOS and one NMOS for the subsequent inverter cell construction + pfet = pmos(pdk=pdk, gate_rmult=1, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, gate_rmult=1, with_dnwell=False, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) + pfet.name="pmos" + nfet.name="nmos" + + # Instantiation of above PMOS and NMOS under the top level + pfet_ref = prec_ref_center(pfet) + nfet_ref = prec_ref_center(nfet) + top_level.add(pfet_ref) + top_level.add(nfet_ref) + + # Placement (relative move) + mos_spacing = pdk.util_max_metal_seperation(metal_levels=("met1", "met2", "met3", "met4", "met5")) + 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"]) + pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) + + # Routing + top_level << c_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_W"], cglayer="met3") # connected by li1 + top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_gate_S"], nfet_ref.ports["multiplier_0_gate_S"]) # connected by li1 + + # To add the ports + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + + if add_pin == True: + # Add pins w/ labels for LVS + top_level.unlock() + pin_info = list() # list that contains all port and component information + met1_pin=(pdk.get_glayer("met1")[0], 20) + met1_label=(pdk.get_glayer("met1")[0], 5) + port_size = (0.24, 0.24) + # --- Port: A, i.e. input of the inverter + 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_gate_S"), None)) + # --- Port: Y, i.e. output of the inverver + 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_E"), None)) + # --- Port: VDD + VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VDD_pin.add_label(text="VDD", layer=met1_label) + pin_info.append((VDD_pin, top_level.ports.get(f"pmos_drain_E"), None)) + # --- Port: VSS + VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + VSS_pin.add_label(text="VSS", layer=met1_label) + pin_info.append((VSS_pin, top_level.ports.get(f"nmos_source_W"), ('r', 't'))) + + # Move everythin to position + for comp, prt, alignment in pin_info: + alignment = ('c', 'b') if alignment is None else alignment + comp_ref = align_comp_to_port(comp, prt, alignment=alignment) + top_level.add(comp_ref) + + return top_level + +#@cell +def reconfig_inv( + pdk, + component_name, + pmos_width, + pmos_length, + nmos_width, + nmos_length, + add_pin: bool = True, # For LVS + **kwargs +) -> 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 + inv = long_channel_inv( + pdk=pdk, + component_name=component_name, + orientation_config={"pmos_degree":0, "nmos_degree":180}, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + add_pin=True + ) + else: # Short-channel PMOS and NMOS + inv = short_channel_inv( + pdk=pdk, + component_name=component_name, + orientation="horizontal", + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + add_pin=True + ) + + return inv \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index d77a4a147..41cb97a3a 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -17,12 +17,14 @@ # My own cell library from reconfig_inv import reconfig_inv - + +LONG_CHANNEL_WIDTH = 1.5 + #@cell -def tg_cell( +def short_channel_tg( pdk: MappedPDK, component_name: str, - flip_config: + orientation_config: dict[str, Union[int, str]], pmos_width, pmos_length, @@ -46,9 +48,9 @@ def tg_cell( # Placement mos_spacing = pdk.util_max_metal_seperation() - if flip_config["degree"] != None: - pfet_ref.rotate(flip_config["degree"]) - nfet_ref.rotate(flip_config["degree"]) + if orientation_config["degree"] != None: + pfet_ref.rotate(orientation_config["degree"]) + nfet_ref.rotate(orientation_config["degree"]) pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) # Routing @@ -94,6 +96,83 @@ def tg_cell( return top_level +#@cell +def long_channel_tg( + pdk: MappedPDK, + component_name: str, + orientation_config: + dict[str, Union[int, str]], + pmos_width, + pmos_length, + nmos_width, + nmos_length, + add_pin: bool = True, # For LVS + **kwargs +) -> Component: + # 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) + + # Placement and adding ports + top_level = Component(name=component_name) + pfet_ref = prec_ref_center(pfet) + nfet_ref = prec_ref_center(nfet) + top_level.add(pfet_ref) + top_level.add(nfet_ref) + + # 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"]) + pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) + + # 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 + + # Add the ports aligned with the basic PMOS and NMOS + top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") + top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + + if add_pin == True: + # Add pins w/ labels for LVS + top_level.unlock() + pin_info = list() # list that contains all port and component information + met1_pin=(pdk.get_glayer("met1")[0], 20) + met1_label=(pdk.get_glayer("met1")[0], 5) + port_size = (0.24, 0.24) + # --- 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)) + # --- 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)) + # --- 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) + pin_info.append((C_pin, top_level.ports.get(f"nmos_gate_N"), None)) + # --- Port: CBAR, i.e. gate control to the PMOS + CBAR_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() + CBAR_pin.add_label(text="CBAR", layer=met1_label) + pin_info.append((CBAR_pin, top_level.ports.get(f"pmos_gate_N"), None)) + + # Move everythin to position + for comp, prt, alignment in pin_info: + alignment = ('c', 'b') if alignment is None else alignment + comp_ref = align_comp_to_port(comp, prt, alignment=alignment) + top_level.add(comp_ref) + + return top_level + #@cell def tg_with_ctrl( pdk: MappedPDK, @@ -111,7 +190,7 @@ def tg_with_ctrl( tg = tg_cell( pdk=pdk, component_name="tg", - flip_config={"degree": 270}, + orientation_config={"degree": 270}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, @@ -187,3 +266,41 @@ def tg_with_ctrl( top_level.add(comp_ref) return top_level + +#@cell +def reconfig_tg( + pdk: MappedPDK, + component_name, + pmos_width, + pmos_length, + nmos_width, + nmos_length, + add_pin: bool = True, # For LVS + **kwargs +) -> 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 + tg = long_channel_tg( + pdk=pdk, + component_name=component_name, + orientation_config={"nmos_degree": 180, "pmos_degree": 0}, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + add_pin=True + ) + else: # Short-channel PMOS and NMOS + tg = short_channel_tg( + pdk=pdk, + component_name=component_name, + orientation_config={"degree": 270}, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + add_pin=True + ) + + return tg \ No newline at end of file From 351cbdfe0dff245d07934d4dab28f580491af739 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Thu, 21 Nov 2024 18:21:24 +0000 Subject: [PATCH 18/21] Team: Salty Chip, Chipathon2024 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 --- .../transmission_gate_saltychip/comp_dc.py | 4 + .../transmission_gate_saltychip/eval.py | 12 +- .../gds/gate_ctrl_inv.gds | Bin 33536 -> 28126 bytes .../transmission_gate_saltychip/gds/tg.gds | Bin 33566 -> 0 bytes .../gds/tg_ver1.gds | Bin 0 -> 66472 bytes .../gds/tg_ver2.gds | Bin 0 -> 43572 bytes .../gds/tg_with_ctrl.gds | Bin 67638 -> 67638 bytes .../reconfig_inv.py | 4 +- .../transmission_gate.py | 116 +++++++++++++++--- 9 files changed, 112 insertions(+), 24 deletions(-) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg.gds create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver1.gds create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver2.gds diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py new file mode 100644 index 000000000..2cc659058 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py @@ -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 \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index be09ed99e..69d63a3ab 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -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(): @@ -26,6 +27,7 @@ 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#, @@ -33,6 +35,7 @@ def basic_tg_eval(): ) 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( @@ -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() \ No newline at end of file + comp_dc.initialise() + main() \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds index a62f5f98b480ec29d5e7705d6652e9dbb33d63a1..b3f49cb536c11467fa9864655f081cd3a766a894 100644 GIT binary patch literal 28126 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 N_TkCAnK)@u@xM;s|1bam literal 33536 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 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg.gds deleted file mode 100644 index fc69a050f6959612b80c74fd6a2eaa4a294ba8db..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 33566 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 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver1.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver1.gds new file mode 100644 index 0000000000000000000000000000000000000000..a4ca0e18d850cf45e1340dbd68d3a2a194353ec2 GIT binary patch literal 66472 zcmeI5ai~;hn&wYkJKC8Z+i}uPubUC)k`5ts2irEb$oCrke(*viezVlh&W9qNC*-nxEXP?A`+wtp$Q=qLKB7{L9)_hLvW=h^n@nfs{K9R z`JQvnTi-o(y~*}}Hk|(DKJ~rzKIc8}ck0x4%BpI9H8%F|t3T|GEx20!PPMf9diAa9 zkJ|rT{qETO|G4un{%Z2C4ph}Q=H2$dH~!0q5B-mCJoP6_4*d83{oVieC)FR`)*U;4 z{`~*^MD>;5A@cXOAL|NhnAuYULU=2hu`U;Pi&R~A>p<94i_ zynp5P$yL?-f8G1*YI-ywGmKvQ$3OgwAFcWBq{j^gQ;TLAH@SB5N8ewwV@GS;j+w@N z|Bu&xZ}s-c`#r9z#{TC_AOxd-Dc^!T<5bp8u=%W?j75oIVPT@2~uB zlk*S8s@tmh-|X@K&9NchSC`J8_|pyluG#xP`2E89w^oISbbMyte|u?;$?RU{FP;C` z^zom`$;vO|q&ez0n9PMB#$U$u|s%^aIQD0}l;D}U?VIaAi( z{+yU8>-T=^`^xNh_c!N5&;EbYp8fr;gTal3Rn$x4`zmv~C*Lj?<0ql=+Hds7O>r;aeAJ1M_h$nUc`zwhb zpQiPx>!aiQt8)Cl9B*2uOZ56Nvwv#$Iq}!o?`85oP3yhSL;R3`;y+P-;_g%aXd+*o&8(Kdf;!FQ8)&6@Q*Zvz?e`!=ae)lUL zUQm3C*7t|_q5a4I-t7N)_HSC>8{$j<+q3^u*}rLhdx#&(kKe<}4^Jz9i`Ea1ipT$o z?0<9iZ(3gw;!FR_v;WEL-?YAbR6Kq!DjrTLzD4U7L;TSG6Qlm6|9hNA)c>aSD)w*T zzq+ja#A*J}|EBfo@~HgyeM|Y_HRW&7`dg#oiBX^8zj{;gEm|Mhzl=Xo`>!;A@ZZq- ziI9J2|M5$>>Oa_^_-R`2$MauVfAy*SA7Yb#(|YXRq5O>BLOk`aG;ieJw7wR;`@=8yK@v>yAn%&$I`f6X8HPee<)I7|I?oRoiG&Tm?u?f9ur6|eKJ{F~Ni z>ED6Qb640je^fuydOZIX`#<%+6wmA4j}&iG#-xj3|LgeH>)+Ie#N)rO_j{WEnbxO1 z4DtUqT)$l9`QIZR_7@SqY?{`m-V5>3KY5+Uc}?p>`G@?ozf0vGu9N>3tuGDvhx{{s zq5Q*# zU;00i{lA?3o7Rtn{H6bc+5h?M-?V-(#Fze^$9YZbF@NcQL-xNt`!}s`2>DC@tF!;z z*}rLhb%-zhJCF04)?@y{fAyQ}|IX|`(|YxrkiYO>UCaLO$^J8~SJy&(;oo_BHHjFtA^+#Hf7ANWkiYbQ zh*(~K2bbi(MeBz`eCgkLoY%A-^OycNl2iV7W&fu2jUj*Oe?77Czd!pot*;O9rGMvf zUekKaU;6K5|955oruAOPU-<9;I{ROd{byS5|2o8%{+-8pP3tj#;lF>O_TRr;`)_Fd zLdakGKU4efe^mQ#X#GrxFZ|Cjf9Zcu_J1tOCN|-o5_GxJkxcubI|AUnG7de?#lt>z_GpRi@rID&Dl-x&F!cJ*?O0bpxjL zPkPU^-o5^*yu^P}Gp&EVNc?^L4Xt;te=0A2Co*?H)z7rv`TkvTGPeaw;v>xC855<#DuQ%F{&5Cc)dguBl9#m z`kU4}*N+s(ral$lWW#?$>m&P@@h8}{ADTb%ZCdYKKT;fib^e2C{ge8e*5Qc#Csutb z|A*M*-?Se4xApqNSoz+Psd*#+ruEMCGsaT)!J^ESkou?fPtkf@e=PdHQlHBI2F15% zePsVKUU{@1o7v>wv>x*h?LR&z6c1H5)!(!}^8Cqo^{?und87R{t;hZ?^Q%wgU-L%( z6M3GbCyqG&Jg(!U{QIEto7QJLe(F=j>%6OY)A}s^JJ5Mf_0#-O{Y>le{8#Kh*C%QJ z({&5`Uz0K>J+Zz2b$nX?Bo5zPpCqPrNBo=Chpt~**Pq03jmi3EVp{(^Nxb?7TJK)} ztn)gL^P1L&@(=lEf0ycc;5tbEH?-cl{>k_qj90&i55bcyTJK!{WW4e^&&}m8{P*6i zpC_$*;=iHwcfsQ!$9qxPTHJ@MbrdguCQ&g(p%^7ridOaDjm^SqqnP3uQy@qdsw z>YuKci`F~WKXYE^abDAU%wPJ~d6VOqu4A$2aSnwf}pd{AXJ4UjJk~b#or)HLVZjFa4j* z&+`k2|Fr%oT0c9w{?#eQYCo>9;lH8v&h<~m%D?m6T>jGk&ip*jK>0SU@0`W|He%#o zuNU%fTJK!{WUTxtDOvGVUc&TCqa z`G@@TdilPd2YwFq`fFP6T>oUe)=1tK*%q+Lf1>ro^7Yg2-<8*SoY%A-^OydQl2gxf z4$8l2{phIrGyV{9+K)@{WQ*22*FSS!=W$-sddy$?-xOuP09a_e1$N zt#__}=Dg11yr%V-zx3bB&vO@)f75zzw13t&YyT^t{AXJ4UjNK_oyU1i>oI@fKfT|l zf6}@q{u^GXpP$Fu{X2C1!1yz@|FrIj|Ay8(*FT%*PyO5Ey^Jm&Gv_b;@5#?|EXSGF z_srs7bC>?#j5zt<3gzFl-nssn z^E!|7n$~B@pWY`>tMtBs+SN?&8nuVe)nhUe$7e#Hm!HAUou|)_huf4@^4!2T)$+zd~eS@1?Atg9@l@0 z{!O3X)Nwei{4MJ9OVZ=}_n~<5tYt&i+q#-AWg`=NP*|Ay8(*MAg;Umy-Pu$`Qy_3rgc#>%()R6GRb z-?Se4w|@Qd{VVz2LY%01BmbuL&h;bKZ`!D~d^^yI{ zc;%6Q%^&$Ut;hUB`%lb-;@MQUlPy{wdH!U)KBuWVOtESIP3xWOmyA_j^{MXKupYFf1 z|6@O5Ec;)RGV1f2#LsyB;m>d4JAFyOs;FXK5^rq5}@{v!TQ=XogqruEMC%beGFoY%A-^OycNq4mR}{^@g?@_$eEpJ}~&{j&D&JU5xY^nW%#&o65Km1+I# z==xWuh{Jz%1ycWp);rfP8Bg6R=W$-sddy$?-sd7Rg@9`l#}$Mf?{K>0VVkI&+N332kj3Ch1|y>tCC=XD3bIMn})f16GI7eM(>v@VAIuk-u*PkEi^=JJ>RkMbOPo^x#SZ(2VZ@|XT~ z-8IQ}iS4--t#__pGFEw=$9YZbF@NcQV}71pQ2tHp8)xyqo*4Px&nEw-_0IK6#>&6* zIIn3v<}dyC^7GsU<=?d48|^=RPE-C@u*rX>_3rgc#>&6*IIn3v<}duG_xn6g|1!^o z|ArUp=kH#>`Wf9Zcujz0$F-?YAGmiq4?PWy2Z%D-v7 zbN!O>s+;pTuW3EzFa6(}pXXsH|EBeOXYs#`IQicS<=?d4xqg}RI*;?3)@R9|-Y0PW zOYa*v|JBUzAMiEf`-j%~uYR9E+&b;QIsLw3=>5Z=hkyUIhH-yS+#2Hknse`)rgbsY zZ$pUR%;S2Wvza)3?(`MYx)|bzjvwPWX6ZWqZ1!(je>TJqoqvgcnmE<(HK_WT)}IdX zb^fM){~z+}^@sfP?qL6U|7VV6eQf0GU)z5jKlWPY%>Lv1=j+sWjQrxah+EvE^|7%3 zv3^(ieuIA@9!`CiczWKne&b(4e5~IU;{Ta=ICVeq*%k$8YZW z2vAn@s9ebZ}G3XjZbr)u0PRD9xvmY{w400jK8k&JkR23S|9sm zh>!hum3W;eU^;Iso2K=l^GECW*Lj`iCiA!IM||pg_>ZbnX8Jx8)z6Oy|1tkI)s1n@ zx)*=z{4L##_4~5@@7JFn>ieyFyQtTzyk;LanMcp_H`h=#(YG^hscAj)c#GV3?Cs+3 zL_J^F@78hC^Lbp0&u86yIKA5%X#y~^SAo0dH&Y%%K7c5%-^b?`i1dar=>nI)i<#p zO8ze(>cE*c`;5#i^?>v5te}VB_XC@wndL1yWcOE~+f7$%rfA4QIU+|%Nq{qAZ z=L_X;9X~%mRNkAbf9v?^_~-eo`L8|}U(LE1>pwLA82=RGS3>pemKLo)74|>oznk&9 zi4#x5$6K_%JH)s4Kj(FxFOuK;FKU0i|E@>C#aFX#b{;>*oss`c&D(eQ+qB+!{22cN<9BDChL`!7Q%2Mmi~WA9R7QnKlpEG{ih*+QU9K<*YMxF3i032`q2tEsj_+S4D|7ZQRkiYc*D&ysU0hIql;*&0h_|m`nRQ_Lv@^4y?{agA! zK%D$*-dt(X`hk$Y^uLF=#=`J|Er0Uf6bdKEm~h4 z@|XVaBToK*4CUXneqV?${i{#q|1K#1ruEprh5!Dqh?9TKn=8|_-v3p|U-<8TOq~3$ zgYutgz5j8DFZ}n_r}*z*VZ(nz>#=`J|BA(b|9Xx!t)B_`OaG^c!+-xXHvBiVek#P5 z{?(_-^&Ff0o7Q9hmi~7VBmbH=S6Z~bGvqJ*PZA^l=h)=mv_2W)OaH5hk^il1@^4y? z{agCKn;7|jf=&KS>vxCzrT=Bb$p3CO`8TaE3-N{jDfO@X-@zvTnbxOb{}%pr-!}Qz zypjJ*>qGZ#3;$E^6C?lMW|RL+>r?N~;$Pm`rsSQiq4n6mrGM3)ZA#wR8d`ro#=`J|Bn$T|C%@QZ(4sW3<1v@~?R#|EBdNA%E$AA#w8mIFx_W`oa(&^AnfuukiXE*YT{2 zA->38uhS5}M)^(R-mHC%TE7`^jI{oqcnChl-=_7reihaq2ahnGdL-zb=;oSX)`sv?VXx%)K9vB?sZ_|3b|J3R~uC=I@?ms1R z|409ZME9W*t#{UsaR(T$f9EH1|EW6HqV>-DF@7K8S#wX+HQ;&vHm!HokMVQ&->M(+ zPm=H9OkIOt;&0RXsQQgFUUd>xw}}?5kE-7i#;Z=E>bI#y>!a$onDMHUsJhW}4Xux= z-`xGj`rS@G)k##{e$b-z&ic`>uQ6WpRMfn^(xUaw`Z4}2<26skqwtd!t#{Us@n;yX zc`9oDUT@KQXZ;vIcmJ*W5r2w&nx~@X?Po1okM#@Z-+2C^{$c*`eChlY&cEUOr}O>v zeK*z~mMVWH`Rm6+eDojAKjgnu$0y2vdOXC3^G~|({UP~Q4!CasskzC0gZjSshatYT z|2(e#eYfV+9gvuKVZB* zZ*r~XycLjhhH1U~{sH5;zsCK6#CdDrF1>!%wBCLHfN}DFA(MMw@;_!;zc8x)jMsfn z?Z+n&{|&954)Lx2VZ8jmkohUZ|Cnk0g%Cf~KaAf;oc7}clz-Fuz7RjuKaAf&oczB8 z<=?cvBgB{fw-KlPcm>M8X?uKVZB(eo%8v^GEg1wBCLHfbsJ9Ud^$4pz5D#z5D(F z<5gqzsrVL~YHwPP{ae((_fulDADTC+y=ncYp?*dEdq;`Ueq3c!?M>@PLws3(^{M3=aX z8mn0OH?1!Y`Ah$|6C?jWV3U8-`t2dU@L#Ea@m~!fxf@#lAjB8`xj#@P|C%@QpJ^So zKfh7<=l($L|C><$Gp%>uKVYnUt53y?Q2tHpv42bdM~I{T)msq%4Xq!U#s5!;qyGB7 zEctI}{U;&5tiSqH{`W)qH?7D1E&V@8ocwFv$iHd*!H~bK|9ax&|5+&iruFq9zVyGC zIQd@%<=?a(`?vJpBToJ&p!}QGdm;ajf3DGfL!A6S4CO!3dSbi(hWzum`j_js!F8x> zX487?-y#2ue~mb<;|7{Py5={nzc!2iSBaDV1yKGId77jrj`puUmH(Ha{F~Ne|Cas_ z5GVhdH}Y>-UBD(!cst{_leFZ(5K2TlnYxK$ZM!-pGHZ_3rxzjK??k2WtQ8 zp!{cA@4kP)czpNOr{Wce|Ay9M|CavG5J&y{nm71wX#Gs6Us3=5DdMyrpF#XLw0drTQnI@i2sJxWB-=^pC^v`Pig+(zoGT# z!~PfbpE^#Q_TwXn|Ay9&hxoGo>QniD2Fkx_J@#+u|1sj^U-L%(P3w<^{H6cR#L54Q zQ2tHpn?ro*Uwtb74?+1it;hZ?{VyR-{xxsp-?Y9Ye@8m?yppkMXx@ zJ+8lo{?m8N>+|D@%vXJf{yfuq%->pnWc&ffbG}SG4LSGgbM%SUJL|`|eT=7P63@W% z{B2tAtRLg&?!Q$(;-4fReVh0yyu{z8^-=X3XT0hps%{f4S|3$E=4h&)sJd-xQT3}I zZ_l4F|Ek4|SDi%FZA**RN7Zlc{$u@aC!gvhs%}4M(Rye7=-1a6uRa&m_q>KQwBA`i z#-C-p=BcRp`$>z|JNu9E)GW#=^V z2hW=Pdu$eEN=3=HAHfDCOLczKay5-&W$>Wm+Hk z9i`VfRulA=xPzWr+@ke~(5tQ2O2v_1y(zx0_!h075AkuX%0Kt#b&l(OOg#P@S|9Zt zk5}-!U-9sQ;#;)7Kjbg{?y9+C_gd0KTG~KZ{**! z9zSa^l%Lo|%Fnh^`CGKUXcqs=6;JF2#kXjEWdAZ=c~pPR8~Hb_$NWS4Pwa%^*;F^x z-?TpR{K@#sY}$X#AML+s{c_m#C2x-z(GibNr3>aILHF=D776^Qu3u zA6&<#>lgFgtiK!PPf`Egkv#6@9B*2W_gaejr|&4`IHccJ;DC@tFzDD#LK^Fy>qQP=XD zk>62zm6&VU|2^4%ruC8EQA%Ftxyk&c|Fd-+(r+v2_3IaGqV=<*>tFFXJM~HWZ6)g8 z(0aUAQs-~=Pm{-a&6)F;{&!~o&t%`G^|;nt^iQ=d`#(Xv{F~Odh5ax6JCF04)?@zC z|9JL4k^P(2$3y{M&3- ziDgmX)^E&Hi*vb-NBM8n^=PPHS^tfB+^!sFTHhGrhx&(D)==~vb-G8b@2G2NeSL@@ z>L12CkMo+=WB$^AkLS>S-j)5E)_Wm;;orX{pMG0O{#VrdVSVIxlq#?DIIn3v<}duG z?gT-X%=t_I_h$bOXaA=4dqe)R{^}Xke{1${T3;68 zOaIQ}yr%V8@~7|kyvlX3zAKN{pPF2E>$^YkHRE@DHm{$$KG*&ew@&+SS{H-=`u$gm zXZ)?-nAiGd{T+>Z?Wgx{{l+|Xc#-Sbm*8Y#`~21Fe?88;(d&k&_uVhHXuWg&lkt0a z{=J!6x1s*Geq&yBqz=oW>fgD3q{pfE#mp(i@waKcbN!R?)Svau`Z#FaM)l9M-o5_G zc>J-xS^L!dk?&0F-Rqx>=Ny0QH|A9bHm%!H|AyPM-nstC-Z zCsdcj_W7%|{>bCH#!&x?nm5NSCrp~{LH?4QBe==V6Ih?8c2dbNCJ>LH*&i`DWr2S9VE$n|y%6aQI=F`09H{jdH zzjggd-F8qf^^5or1soXg%g{T|d`x{038sPwS7Ie;Qhk z>yL&1TfZ@%>-REL{mdg-KN60AS^o`r-1Z!ATHg@j%lfY-j{ZsOp7c*c>z(VLIj{3L zuW3EzFZ{E?)A^ww|`5%cMpHdf2Q^B_0Kx5^Z2*rP3uGXOaEu{^ZWvG z{L=cTXuWg&lQGo2I+b|^;{Vof%u@r^ZztQH#P<2Gtp9i(HvtuAS|1@N=lwU(yJa{AI2XdPWy2Qo@~+jp>X`_{B8fvStMYGJ?_B@Pd7a03P3tj#>A#ns=Ps!Fo7Q`weuaP5H|zRq z-BbQEt#_|~=Dg11yr%V-zwn>l_tQUV-4Xu{FVxT9z5ZGIPT%uK|D<(K{5L$)JU+7j z=a|3rzbE@V2Ib$hzGs&DYwpUw=C1sk);rffb6)3hUekKaU;4i{KhMKZ{!Qzh>yM0= zZ@pg^w?g?ht#__}GG52sd7Rg@K1=@eK7m@L_YKspW`6&GukQ8FI=}u+PI>)HT+$QU z{nL8?$6R@m$3gn7ta11(`;%$?)^E&*{x9lx>o?}rKU}vSSO2uQH|wK5zqyU^+ZiXG zg7kkw>v8?3tiL{|Ngv<(jd|*z`Y)`RKEKIv>0ZBN9Ci0^$@{nEP3zt3m$~lxoSW)@ zO?g|iKI-#t@~6*fif<~uMeCzJzbXIvoSUfo?RxDot#_{fC=S0M{TBBI#j|BvANl!B z`BtBbhoJnM)?@$HuV21@CEr_!6E%P2-?ZMj{-wNZi!xV2>VNAu=5rnN`AyZQbN!OX zIR3YOV_tR8bq7q>AEK^1q>JJ8uXX*!SdDHsP{nys@JMojmzgP3tZ_HB% z&L7QhZ7x-P`MY!dvVMGyzwtg)e_k)%Q2im$Z(KIC{>BW)-{&v<%`yK_{}6v9@5jqf zuV1G1BO!n3{~&Sle?I#+tse~W@%$_Q&f~nM^_ai(uh$DbkIwh!oPn@zIRXdpJ}~&{j&By$NZ)Lv-x>`0rmQ8T0c9w z{^|3Z^iOq#c>2HLDgKszD#RE4bL%(esT2KQO+eM(9MAfAs9)JXOLCnzLDk>1-noA1 z=g)LrbLRX*{X?v-7j>QRIoq=>T9508L;e~6Hktfjdq5k1<=efE3rT?Qm zhy0&olYi5CTt6)R>w0yP?GoE_En4qfzhtcPI*;?3)?@zC|Hk}0yP*7=);EUwmHyWg zBmeu^o?}9<0RLwCn5dQa7WfV*DraT{<-xV^Qu#R|G@e0xBMIP{nPC zc{&(^VV<7(^psc?uJ{xG2gy_@MV8v zyMF!g{m*pXpzmJPc_Z^Ily1h~_-?&^F^+pg&2PzTJok=n{l>idmU*n}P)J?d$FEgC z9>31xzpQzazwsWgU#=3b>sOf08_T9?{nl^Hhx+^Vr~A8Rp5~h3ZO%K1)bk)~3ad=( znNPL2l5t$K4}aIpSF39N!m+A#-1K}N*W%MzH&+JVt-fL0!^CaO+y%J~x?x(6*Ud5i z1B_o!oXF=5dIwsx-g(`g^E!|7n$}0<_x_98U)9Z29qY%-d6UmuUts^kdG8CtN%0pHm!FaKgNIA z{N8`>Z!=%;p?ajpXXxL&ZutfBw~n8mA1d$7)xUN8)L(f%^BJKuzr}a5ZqBrBnT{Xh z9%lUU%=3`-mwBf3<6-|}{s$O;ggEhac%Vh=M?!pS|8rjFabDBWVA92p(yr%V-Kl*om=W~AhDf74Lr{holgF5~#zLRyc^Y}6DnEYp+hp+OtX+8Rn z`42Px2yx=;@MkSr?>v4vuk$#sX?;|F@4u-1RUJ&#B|YBNKVK++>-hQkb6y_@*WHZu z51$)I^Z$~3Fn>RUueNCY(g^>YYj3?FF^S>t&jNJLGpi?IPJ%q5dRIW$A5QH`u{O;_#b;0;=iHwAJ5`{3vu$l56Zu3 zJ$~*W&OiB{AWr1kDfu_8PlWuX|8>O4|KCFSH?6M=@n!$0Pvw6llz-ED?BBwFZ$O;< zYu>2-nbv!QkiYQX`;0jG*Y%S8XIk%l7UB#4={M!^-@8UU{u`>VrN{m){a<7p{(G7~ z_-|6&)^~^a(!cst{&zt6H?7D1E&Z<|PX0A-fg|M?BAmP)yu?Df8A%6|Ay9I4*5&}FA|6U>emqe4XwWz;!FSPQ~CcXlz-ED z?BCM=6U52C=8gQD)}ILZOaG4(C;w-m{F~Mv5Amgc^{MO|D3$lzw*Br%73DDF~kq~=kY7V$-m}}{3lu$L;R3` z9{(reN%hxpRJ`c(c8u*tt^J@#+u{~=`!JY^s52{eci)`d6RI|7te*H?7D1E&b0UM*bgUlYi6typX@}KlM2=^8W~%{AXI9 z`aHxJ{-@Nx_@DX}#D7EUv40EyQuDdaExpC?BCZ)cPL%&DwToe%M) zfAy*SpMmmkT95r(`d4oJPig+(zoGS~LjKbKUg8)#rG3YLL+g7(eCc0(D*rp7{F~Ne z|CavO5GVhdH}Y>4}OVl;^CH^+8kE-7| z<5ee7b(?6>`l$LXVZ7=js&1QFv_7hSiy5yviK^R{7Ojt}-`xGj`rS@G)k##{e$b-z z&ic`>uQ6WpRMfn^(xUaw`Z4}2<26r3&D&2}wBA`i#-Cxl=BcRpd%Z>Lo%Lh<-2J!e zNBk-Bt<2Q?{fxg&>#=^}{2R|d)IZE0o{t*RAMNY!c>m_@I={~Q>Av%-7RjIVm_Pd0 zc}G4)&l}Tvj1T9ZbpQGiYc>xP{~>&`MeFhUr?vl#U&r`YGJgdR^0#UIm9YOU|BToE zzLfbJsPl0VVpP0q}VdAL&*qadl4Xqyz@kRZ|eoUP9<6VgVhSq-^;>-GPAx`_T z56Zu3eM^Wh>pwx9{F6KRH?2>E_|iYI$^YL%`8Tbv3-P6Y^{M=?gz|4%kNsQt=l(|R zU-L%w&$Qls|AX<=o%rV^9TP8 ztzQiBMg6(IQTx9Qs{WbQyYGK6UjEgm;%PSdH?7D1E&X%dk^F1k$iHcQ|1AD@6Qkqs zGdBD;w7xsU7yZ*ypUVFZHu*QL$Nnw-E4S*ec_aU(^;IE%S^sYnqp^yWf7AN6Lww<1 zzrU9Jk3;#-wBCLHgR%JL{zmOz^G3Ndt#{x5U@X45zft>N3*|r4diVVg#!~l6eJXwc z@!!yT?BAmP)yu?bKdwRiH?;n8s9#Zkedadp$FCv&E7SUmA-=4?`c(dZ3gzFl9{acS z{{(UJuX!W?ru8R6{?h;B#OXMkh4OD&e>}vO{?&W(|0tAy(|YXR(*Iq=$^Q;0|EBf3 zLjKbKoy5sMxs!j>`kf(u$UoP9>Ru|6n|I@2gM6*C75IT95r()W81> zaoP{fAN)78{!FM}QGeb0O#AU3#DCwk{&a{h>#shQ{{v9|P3y6LOaBiMC;yr^@^4yy zDC95wKR}$0!%-;zru7FxeCc0(D*vmY{F~Ne|Cave5hwqeH}Y>Pig+(zoGS~X7Rt5IQ&n&0rB6^`rZ&<^v{&~RQ`8D z`8Tb{{w@8lAx{1^Z{**!z9!@^>%W3H`Tq%&f7AMk5MTONpUVH;Q2tHpv40Ey+~27E zYu?CzruFXoAB@L0_cv<)>!JK-TJOI9k>j5hS+_W-c$4Q%dg93bt=FH3do0H%68BPm z{+GJy$GM)d`uuhxYkvcJPM_aSv_9hV(*x$ZKEIv#Iy}tZru8Esf2;nC-^h4smiTkX zoSA1@pXuN2H}^jnZ=d#UT95u){YSnH#BxDw~3su z({GfU)<@NEoOsnqRNW?8v_7hSOBk;@iK^SC7Ojt}AJi*6D zekJ*~&ztif>vuc(R3}k&`$3D=JL^ZkzQ%aBFe~NsXr=sTVXDwQf^&4^iq5fh1@O&G2 zzBqqc^OtLdx9j|g9KUoPH_2Z=9`--_59c59b1jqlK%Dvf^XJw4ua8yVsOo=rd6ID- plV{T8y#G9Ze`KO>$JbKRdgf${-(=iL{!Y~M)xH;0)mOe!{Xc_3Fr@$h literal 0 HcmV?d00001 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver2.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver2.gds new file mode 100644 index 0000000000000000000000000000000000000000..9b33569fd4577a511dc8a2626af37be59d7fae0d GIT binary patch literal 43572 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 delta 558 zcmYL{Jxtp`7>0Ak*awLaBBoRoLNJstf$fX`C_^hIP#2^ibwCQa^JOFasFB(-#t|?z z;u|b=>x>YC)ofj=5C|K4Cl*!~s#Zufc8J4vy3_YQ@Av4M4YAn}8^18usI5D88K%4( zCX6thl{NpnjIxkHBZ^53om1OPWkv^5Dd{8({|j(eQ?RP(nqg5JR?)PaH+giFS zW|V83mJGNP3c>KzkHO$%1uw$agb7r4q<^lb{M|_*Y9mCuBSa z6Vq}nPI^ey8^PKGe%ia-{;C=l@fL6QO?+{JD^dBU&8fT96 z{lN7(4Ng0+mf`|(&%3`SMf{CUw^iT&Me7Tkwa5M6gQ)VXquD9I@bx`}SLxvI(a*)F c_{2rr*%vWdfT8+i@2U3 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, diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index 41cb97a3a..58a87c3be 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -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 @@ -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( @@ -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) @@ -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) @@ -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_") @@ -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) @@ -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, From 8bd30da88b77af22d74c3742f51920f8a6685247 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sat, 23 Nov 2024 09:22:20 +0000 Subject: [PATCH 19/21] Final modification of the intergititized layout of the transmission gate PCell --- .../transmission_gate_saltychip/comp_dc.py | 7 +- .../transmission_gate_saltychip/eval.py | 18 +- .../gds/gate_ctrl_inv.gds | Bin 28126 -> 0 bytes .../gds/tg_ver1.gds | Bin 66472 -> 0 bytes .../gds/tg_ver2.gds | Bin 43572 -> 0 bytes .../gds/tg_with_ctrl.gds | Bin 67638 -> 0 bytes .../reconfig_inv.py | 2 +- .../drc/long_width_tg_3f598baa_drc.rpt | 3 + .../lvs/long_width_tg_3f598baa_lvs.rpt | 67 ++++ .../report/figures/tg_with_inv.png | Bin 99588 -> 0 bytes .../transmission_gate.py | 292 ++++++------------ 11 files changed, 188 insertions(+), 201 deletions(-) delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver1.gds delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver2.gds delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_with_ctrl.gds create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/drc/long_width_tg_3f598baa_drc.rpt create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/lvs/long_width_tg_3f598baa_lvs.rpt delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/report/figures/tg_with_inv.png diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py index 2cc659058..5b9a59b20 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py @@ -1,4 +1,5 @@ def initialise(): - global inv_channel_width_base, tg_channel_width_base - inv_channel_width_base = 3.0 - tg_channel_width_base = 3.0 \ No newline at end of file + global inv_fet_width_base, tg_fet_width_base, tg_fet_width_factor + inv_fet_width_base = 3.0 + tg_fet_width_base = 3.0 + tg_fet_width_factor = tg_fet_width_base*4 \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index 69d63a3ab..601503473 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -8,10 +8,12 @@ TARGET_PDK = sky130 PWD_OUTPUT = subprocess.run(['pwd'], capture_output=True, text=True) GDS_DIR = PWD_OUTPUT.stdout.strip() + "/gds" +DRC_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/drc" +LVS_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/lvs" -pmos_width = 6.0*2 +pmos_width = 12.0*1 pmos_length = 0.15 -nmos_width = 6.0*2 +nmos_width = 12.0*1 nmos_length = 0.15 def basic_tg_eval(): @@ -27,15 +29,19 @@ 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" + design_name=tg_dut.name, + output_file=f"{DRC_RPT_DIR}/{tg_dut.name}_drc.rpt" ) print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result) print("--------------------------------------") - ''' + netgen_lvs_result = sky130.lvs_netgen( + layout=tg_dut, + design_name=tg_dut.name, + output_file_path=f"{LVS_RPT_DIR}/{tg_dut.name}_lvs.rpt", + copy_intermediate_files=True + ) def gate_ctrl_inv_eval(): gate_ctrl_inv = reconfig_inv.reconfig_inv( diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/gate_ctrl_inv.gds deleted file mode 100644 index b3f49cb536c11467fa9864655f081cd3a766a894..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28126 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 N_TkCAnK)@u@xM;s|1bam diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver1.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver1.gds deleted file mode 100644 index a4ca0e18d850cf45e1340dbd68d3a2a194353ec2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 66472 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 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver2.gds b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/gds/tg_ver2.gds deleted file mode 100644 index 9b33569fd4577a511dc8a2626af37be59d7fae0d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 43572 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 SD)Dnwr3y$li%Kk9Sp7d@K)$j7 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py index 914c025a2..97ab884af 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py @@ -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 >= comp_dc.inv_channel_width_base: # Long-channel PMOS and NMOS + elif pmos_width >= comp_dc.inv_fet_width_base: # Long-channel PMOS and NMOS inv = long_channel_inv( pdk=pdk, component_name=component_name, diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/drc/long_width_tg_3f598baa_drc.rpt b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/drc/long_width_tg_3f598baa_drc.rpt new file mode 100644 index 000000000..d599f9790 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/drc/long_width_tg_3f598baa_drc.rpt @@ -0,0 +1,3 @@ +long_width_tg_3f598baa count: +---------------------------------------- + diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/lvs/long_width_tg_3f598baa_lvs.rpt b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/lvs/long_width_tg_3f598baa_lvs.rpt new file mode 100644 index 000000000..41ca2a7df --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/regression/lvs/long_width_tg_3f598baa_lvs.rpt @@ -0,0 +1,67 @@ + +Circuit 1 cell sky130_fd_pr__pfet_01v8 and Circuit 2 cell sky130_fd_pr__pfet_01v8 are black boxes. +Warning: Equate pins: cell sky130_fd_pr__pfet_01v8 is a placeholder, treated as a black box. +Warning: Equate pins: cell sky130_fd_pr__pfet_01v8 is a placeholder, treated as a black box. + +Subcircuit pins: +Circuit 1: sky130_fd_pr__pfet_01v8 |Circuit 2: sky130_fd_pr__pfet_01v8 +-------------------------------------------|------------------------------------------- +1 |1 +2 |2 +3 |3 +4 |4 +--------------------------------------------------------------------------------------- +Cell pin lists are equivalent. +Device classes sky130_fd_pr__pfet_01v8 and sky130_fd_pr__pfet_01v8 are equivalent. + +Circuit 1 cell sky130_fd_pr__nfet_01v8 and Circuit 2 cell sky130_fd_pr__nfet_01v8 are black boxes. +Warning: Equate pins: cell sky130_fd_pr__nfet_01v8 is a placeholder, treated as a black box. +Warning: Equate pins: cell sky130_fd_pr__nfet_01v8 is a placeholder, treated as a black box. + +Subcircuit pins: +Circuit 1: sky130_fd_pr__nfet_01v8 |Circuit 2: sky130_fd_pr__nfet_01v8 +-------------------------------------------|------------------------------------------- +1 |1 +2 |2 +3 |3 +4 |4 +--------------------------------------------------------------------------------------- +Cell pin lists are equivalent. +Device classes sky130_fd_pr__nfet_01v8 and sky130_fd_pr__nfet_01v8 are equivalent. +Flattening unmatched subcell PMOS in circuit long_width_tg_3f598baa (1)(2 instances) +Flattening unmatched subcell NMOS in circuit long_width_tg_3f598baa (1)(2 instances) + +Cell long_width_tg_3f598baa (1) disconnected node: VDD +Cell long_width_tg_3f598baa (1) disconnected node: VSS +Class long_width_tg_3f598baa (0): Merged 6 parallel devices. +Class long_width_tg_3f598baa (1): Merged 2 parallel devices. +Cell long_width_tg_3f598baa (1) disconnected node: VDD +Cell long_width_tg_3f598baa (1) disconnected node: VSS +Subcircuit summary: +Circuit 1: long_width_tg_3f598baa |Circuit 2: long_width_tg_3f598baa +-------------------------------------------|------------------------------------------- +sky130_fd_pr__pfet_01v8 (4->1) |sky130_fd_pr__pfet_01v8 (8->1) +sky130_fd_pr__nfet_01v8 (4->1) |sky130_fd_pr__nfet_01v8 (8->1) +Number of devices: 2 |Number of devices: 2 +Number of nets: 6 **Mismatch** |Number of nets: 5 **Mismatch** +--------------------------------------------------------------------------------------- +NET mismatches: Class fragments follow (with fanout counts): +Circuit 1: long_width_tg_3f598baa |Circuit 2: long_width_tg_3f598baa + +--------------------------------------------------------------------------------------- +Net: w_n697_603# |Net: B + sky130_fd_pr__pfet_01v8/4 = 1 | sky130_fd_pr__pfet_01v8/4 = 1 + | sky130_fd_pr__nfet_01v8/4 = 1 + | +Net: (no pins) |(no matching net) + sky130_fd_pr__nfet_01v8/4 = 1 | +--------------------------------------------------------------------------------------- +Netlists do not match. + +Subcircuit pins: +Circuit 1: long_width_tg_3f598baa |Circuit 2: long_width_tg_3f598baa +-------------------------------------------|------------------------------------------- +Cell pin lists are equivalent. +Device classes long_width_tg_3f598baa and long_width_tg_3f598baa are equivalent. + +Final result: Netlists do not match. diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/report/figures/tg_with_inv.png b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/report/figures/tg_with_inv.png deleted file mode 100644 index c6b93bcc349dd5f0aac4becb0b31c526e9ef4848..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 99588 zcma&O3p|tk|3ALcoz9Y^G8C0^mQ%y5yBvxTIpnw^Ig>NPq?1DqA*aHM9OryyGIE&n zD(B;{&2l!3VfbHD_viDyzrX+E_xO1{#&+3t?R~uuuh;YNdN1U@mfGei2eLpQ7Q;jPfg>p+OA^4J!_V#*xq(0@8kvuMvBD>~frISsDi7UnTRAvLg50g) zUbgNwa9bzOeT7Xtz&~#y^d7qFT3Nb-K!*}J+v<2Z1ht?kfMS=bbe7^=tIh zjp)lWBK9(>k@sD{%&}$_mhp<-#>%#-r}fxHJ>5DLpT4NSWt`#asA^>U-aoJ zC6EF6_`KxK`o1cMd506_T~_wiZiOE5z(dSL;p1?XEpUtf$4}A;7HmDZ%=W);e3|Dq zI5Y@$NN(@zntC+r4m?bO&j?CS`9Dtn*Ma!vIt@cL$MX)!UH>_mdE$Q>m;9%J7jbO= zI`MzM82@?JdwM2I^JQLl;{R&Q@9Sks{kbNIzVCmZ47?u4)j3Q2zcl1=w&4HI>Hj@c zmoB;VvsdTiL6iS{;=j9C%lc0@w@_LBIj!S(;%v4i*LsnY$WkQu%+L)Z0BbSFSK_ugs&Rx3qH@tOmlMEGERSHc=u47P`{)k17ZzvK_jPnqF9ji%+N9kI8{CD(9N>kjK%Md%(i<$X8< z48^}X>6i%Zz(4Ig3m)kD?Dc2O{NHDvt^H8vrSI3A3RW5V!UI~B0p0^u<{*%Ja3&0C zv+GDc&Xou{H=aCAw&vfj!UDR<9eRR#5CrPKJ)-NZ%n1TDE`v_p5t>XoJ!;|)8b1P3 zVfp*Qf0xFiXBTh<|4$96O8$7z{n#vb!0pOhzGtFr&%v%O;uj*x`*HwDV8~K+{E+H^=-+1*6>-~p8pe>femsrRD?@bsTa@7=3X-m($1(kHQ#|#aU zr#x-A2F1<|#R?Hh%$`W+Wsmx#m{e$#kzt?tRm=2$n09#RInK-Oc)g1p5<9Ma8o^AWaYZ6kFWb~b55k5En2BSebKp)l} z{t=y;{8{1Z`5UL0p)JR@tuYc8=k=M(a=qem`J*%%%@GiJ+OaMH9gDX>(M@8w9a1< zHzu=qhd0emuw5!Sa`N^0)1wwi4wnTX*CpG#LwLbK(1kAiMczA4IUn75luaQ&_9r?Y zil?!xk@tl;p{6MXbK8!HO=W5Jv~<&}g3Swr3>??yyhjwQ_PcWXhKuXkPG1%Ubb;IN z$S*j+lqAXW}pHf818{a`(~ zFIg*c#>+!di-rL+TYlk4*%;lnzhXZOEw4>_AZfke)0Og7Z~cbntPofqo2Hxjc7k$} zdHyJN8F4cgfR0a1o`}? zH3XTT#lO`e|1mZ0RKJj$?K0y=6{4fBq)Ljj zPt8vF$L)%KeYV+~k@j6>>Aao+M`sA;7*pu5ef$`HO)@brsF=|%X8j?_A@Hv?s=^V@ zHR`ZAA(~opEMa(7*E0;CuEg$_Ft5f9{YuSgwS^$;s5#$)%2s*&)e)SBR zeyow`9?`j^02Sls7{Iap+V^{T$dtRiJ5~nGS+2aE*&^zE25e+q5)GUSP4&p^CWZ?2 zxh;=Ph$tm=usoa@Y%~1`#wNK;ilZ7cExJZllAylX3odhg`ZqQS@8TO(oYv}e@f-kt zNGg3@fH3Ek@nn6v?mXl*7VN#THoQ)uL{c)ZQ`5f8oc< z&dXp6nsX{LULl*jPIU;w zZv_S6b~j+xn?2pk^&@XBP#P4Wy0SF>Y%T;dQ>euL zj7;sh9nI?*B5K7S72(RKR1*ms#chp?tkF?~fP1Sog^FzJP20W#hO}pQ9A}en+>QMH zs9ac;P2AqGwfA-;n+f#EDtDx%`}#3nrpodnJImTk#(V(=Iw!*s@&jOMl=0 zFxK~kiKrVRdccv~#^c85^G(rQ=ub;|kSbW96lmZ}Yphtf3N0Jre1Lv6^mO_zPfV1W zp^87Dm9<)n* zJP>3QBX@IDR?M}8)s><31c2ECUHeXEap|9odUDk~!debln`3P<)|GA*SFvbry7)wQ zETm~hhvG!5&hxrZ!Mio$co{mwBU~IXNpZ4Vb)cB`DjDXFPBF@+BoPVS`TESs>=0j8 zpx!=(p_*bJ_#6DN-B-(r1lip$4YKUsNHl6|rgx0t3SAUbcHuTOG?LwVE&=I@x;&DrT-< zpmC|-6nlvoMhFqTVdNduS_F*sMlvrKdHLomFi2ejAOxR3czy+AjiuVkRy*Qya8johl)R9o<2 zNux`cYv+0DEAZnAPN|jw^bKG$`}^CeZk@Co*FHBT7S8FS)z+sA2Gi(EP;SS&hbTzCe68h22wBHGh8{REzF05P>Mh1bgfi6I^%4>2ISz6o}erMBgO+nksLK!%C``1v@vYjZD)Dxp)u&pK9AMzH=M4XTKV4wDPVIuh~6Y2Hr7Oz zXCKeSl}4h}BH!C1T7FgFg7lz$+Zp^cHWT8{aEA^<#$zZ_mpVtAfrVpQ6p7j$EzVPFCHl>Jp=++=_{c2F_f6{05i3M! zBUXIa|MI1rT!B+z<&d>RV&*owhB8P(LT4bC5z8|iHf4s|ezOrjAE3=7%haUu0yEq zT>_9ko=G!Vf{b_Hc0)rqAB_HkuExY~ncB)6lBppjKb6Cru>O&zy>)ml;d2gT9M^}e zntPEi&JY6V?Htf{tkt^QBzm9E%Z<&EAl_b8z4`4RJ*p|0{Ujv`wV*=EXi0}FgUQNH{m5DZVd!hkg#bzYvVKj_Rd!eKw{ zLNJkP6DsJ7d<%9s7J3kL;gvf4#6XuTIc|PY@<>GfU}MQ_wy*N6RwgciC4c56gxMQ6 zPuqQ^J}7W*y;1b_vQm_GQ&JTL;=86hN*u^TKXc&XvRb}*9Sv%@Www5;-Qe-YVc#9j zo@Peuhd3f6up}fy)`AbF$y>BLpoqVoa(|ubMh?nFjJVQ%$-}Y&+^j>3X0s!E41VTE zE4~UJb%1_I%JV1N8S43RLjT6h?VRbse)VKWn0o3vw$9rXMiT7eQyJ}|0Iuq*<4<8N zW$gR7^ekTiZQRwN8ZY*GSoj*sg|O56VxA^?4%YrWWB@1rhINh9dk2=+guaqVru!b? zyF%4IR-ihQ-C$W=p5W;-WRLX>p(RqPLR03uhm1XOFjfVEDNaMB2U-k%X7c`%y^1UjyzZ5 zcM28yFR1w|;I{dxKV1fr;Ga?9RBrQo_Cq_7Er#4#GgNEkW6j^sfZsD>h+?q%*(NGL z(m^X{=HwZp`sH!{^WPA5aLf_%yw{lBR`T&+p%XXLd+CgTCYtD0HUdnP^5w&lTvMG7 zR*6Nk*(Y-tQ8sI4rW&?adnS8_7^W%!@ZVaJ0>~ujP+AEXR+g*EIjGh*nEON&>Je!( zI=x!@UsB-4u#2NM7nJmwB^qKB{>yWu895Y1JSOkzXg8oXeHhkNS|}a5UP~|a6KdPJ zd{wmqzq(@BUXgi(%rJQ!DZV;9%TMrA5WZErz;+ZgTF2;vFW(Sf7q1|QR=hdQn?Ui| z!7jY5p$Zb;Sd4#y{2{+ftBbpnzdSSif=b42JXYoqkTt?lwqV;U-Pql?@A25Km0jpd zR3OLWmCm1}8&B+rUQWmq$_8zBDMPhQ(NE5Lcq-a3f4P}W4IHFc z{y%TfI9A*BiMRG^q7qIP86<}Uf!=@ijDVwE7v#6vtUSLHQXPa#zSMAe?FP}@z2}Yp zba@PrN~{3b!(=Kc1^)-F6y5GRd|&$HfjGpP(?UXe%E1~F$d*mk$+?}pWLMA)@woYt zkJ$u<+`1Qjq3*ozqikyxw;$Y<=y=s#?fcT8x$wBtjueVjHbsoPGE)5;j$`L!`SaS( zb3_WH{(ATmASk|%-%hq`$)ko=q`ZTxcP%)Z0*?>(llZR1BRum15*Z-u%JNNRa^SJ0 zu4Car^XWgjtTmet3$))4$-zf0A448$ThE1&C{Yzu1!q&e87~khEK(hU)CkP7tC~=j zkpOwm>Cbx0g2%lcs=0$^L}*_Q5?=`&iyf_R#BCmpq+B}wNLzYY0d9I=FO0aUa)NHE z(qqk(tdI4(NJnO+^5;y^qZlZ8@&hG$YnsqqQB;idbLfw*#Uy41WAtdzy4s(3m6VlK z#SBDyvUm_tq|asMA>g3$=`{f&X(tz92jIFpODqQ_b=~7^FKvnF&}!JPodWkaA^ck~ zG0t#62AOvdT#R%wO#0JB-z47c`!nUn7d&w}<41@=pS&8Sc5bZL@X?LO%c@99 z_*;wZ6M!Jt|CcM{dG~&1S9vZgeVRHPm=kC%Yt1Nj}xpW~5!d7Ji>C`~ zBE?4zxi(^2e)WH9i(MOJ5a`n+WUG_vaHDQfBH0fF#BwxDE9=|+K^|`+>)dM=W_wRI zGWpW?<4zIBp=l)bDeAn`wnO`!u6M8i>cG5gA!w};NP@uXlfq!X?smhh>qxe%#<-a2{*;=*Zg+lJ~(_dc_0#W-wSHIc1F`jk* z)r=%^ou6o-Vh+9|8gc@y=(&}UN-nCXJaqbaX&oR)2iX~`N1#|(l{r5P*#Z-y*B}jy z%?Ms>ewlh?na<y2^r?m~m!!t}EOVuW!}DR+3%SMU&5IAQ4erbP zT2gJcVZ)s#9D>w$8DVnBo1)%C{uy~OK)bB-V87R1^))(Hvv0-2ASc1=N%G(+&kFsS zr=u_urgd;TPkk(+r^Ic0+jUEnaepsfq&?q@7kuJ;#aD>0qO7vq@%XakO}&j2T2Kw2 zPcYjs-K@Lv5ED`}ai4)zw)N(S{)mtOcfE@KU6wbvtn!?W5tMhfbxXgi;W^0m2@NQl zgq(5&92TFuz>Osau{!WrqbtBL5t<^?_W;!V3(vZ;`1LN2pUR3RR)c&c zq}!=z9Wh=ZOqx>!-!m(41yRd0_Q1^_T+P~QhM==7VK$RNIaZ)Uj}V9`mxrDkrOyfb zqHH9!GFXNmyf~GA_J!Q@Q4sPV=#v~ko&m(%qVWFD`fsRA8*U2pXMp%ktTUD`KIX&f zn+q4`!+@mw zuRj+n%+yj@^24&^kp9godm7&hTgb$=ox6d2J5uHy3f{FafYW~OMOBz1dV##H-!!wW zQQyArZ<~EU_U+?aMv?##2_${2#@!<;<07s=_RV=-|KVE^1lZgbCf!-!B&UmPCg<^OIgYkP#z1nS`cd$a^>Q9H0YI`vEGUUsnh} z{_IfxS3WMriQofkR1=+VoVS+_7IN3&Z+ZcSLVv)&426fUD-6*GAsVIIE5nrIw>z<2 z%3b-xWoC-mesh(1#wwe8x>b*2FK{RH+c}V z!nt8Xm)~*=W)rRd4uxmA_R|MFZygWNBa87Sq?mv4YY_aha;*PRZ@>-xwGDe09^!WD zNWO>P!MRh8+fC;wUs^VH9}cVh&HHQwUOiQQe@2(xW(yE6>NLZK1izB$DtdRBb`vlM(n9aYYK7@6MqOS~ zq+i52i>`5W3glz~L!z%T3x=Jn4AI#-00fwGfneAL4tZ?hXkW1xw>Btf+^$M~N#Vl5 zX4=p-+~R2>@TQvrbCX_@p8LiR%~d72Q<&1NrWT`e0$EoN%thT*3?Ph`)BHfLS(Q=DLX zeDoK03w8EbT7KxYeXa}#K*W{#-6K-2j5S=A{|hh-1kwryFvVw}_tM4$G@gTD-0~4q z?D~2Kn6VUs+_LOZ`Wpxfs?r@)Zor(&(iARi3f2@B?iDipHvJ}OR@SzyDv!RRL3#>! zAG8V$6`%Yr;P{IO#=@n0y=8fCri{Zl;tC_-hVi);5%7B$q2({VrUJZi<#yBSpU@LJ z99zpPS)(_YQJ5K|9wpNyU$sj|`^RO?Y5LGjlmS>66K0Nj>O_U_52a#su4-i6>ACzv*h@3F6 zPdXG})RXcS)mfEN<2v<{Fd;q65s2a$s|?QBGJA*m8vA2k=t1L0dosT!H6SuCL7er@ z8zF{cYG|&I?T!AW;81Rx$~0uQ=rCm9zSR@}x}kiG$sjdSJc}K~ER5ij^J*S!oQS41 zNA{i*dXcKndZIrQrD3oh4)>cXk$}6KdX3uzbQF`_67x9u=4pl zSibO&tWsZ^w1kv7h{>~3LHdSAw`YCBz{AtkM{~Et-?Oe!W4w&27Es48$qfr{HD0k^ zUzsOzi8B?8PVAg(M(Ze&Yp6n~=jsKP8mZev!N+_sTC1o(Lxg3jZ&3+}^f?GSKo;7+ z;c(q)G0<7K&5TXpHU-)YKR)i@!@OxR&>v4ef=JkJq(E(5j1zSqdYKSFs_4teE6Ep>MLSKWXHbo4$W zpNVq(A7Ao|ICqw#!Vs}@UU7D3Vq!XyFCyTHG6%cmx^p-2sAf{^6^q6(rr3~e^;ylX zE9++n_4NX3x|LSouatW1`SdjTmyiSd`H4`1OTpcB8S^P6ZlYI_78een>ofPI*)@}( z#ki2G9GHNQKolEV-2@-LZzJG+wI|?#f;j)x50wNL-1JodC&14RFfB{LqB03~UrNbm zf?m10koe{qPxQ+NY;11%?g+n&sRh~raaJ^Mi;ZrfUD|BGox8IF6=mE)i$p>G=f~hN zR+CB^DoC$W88br$8gA`MkB;J|mRGK8RffI~A&!X|L7bl@+-o}LFd>J7$F5kT5cia8 zXJ;L~dtQzNI7e36^f-Zg0Ves5$a)CK)s1sR>#3uoPJ|6S+p5B#!J1avOzsh~?+$&)2-p9YyRlVC^J zJ@Rc`!@oGLZQS}TTTk&A86+o%qNM1bQ~k`E;+tZMN78t`b}jj^VU>4QFf%UfSI>j; z-^M|Zcjx--M7IXVQT#HCeMIo|xTSMT7gb|TfkdZ;0sogIzKZ9BsYDP`8-;dntuMhj zORRzrivAH`=A~$uP3EO+0s{$;PV`DQ?H(<6yC8hKse~H_Q_4A{f48CPjT*f^vJYao z(==a(OKsrbi~d%{{S+b^AD#pm5Tmot z=s$DRsG=cdzP175*Sh6?SLuyDn`H%=BFaiT-K$n=cwE3+#45H#VU5aBn?~BQQs(@? zTR{L&8B3jllr(aAjjCbH*}*Bo^0afkJ!_A>W?eNz#Ro_G{M;P5OqK-mrU{lPE$jfm z?VL;0lou1?Jh!_U0k^)v2q&Bu9v~gh`XH7Mv~~QIS)zz)EmSv4rfLZQcm909b|5*LXE}L^VgdoIJ_%fN zukwaDgQbIo`l{*haMuB_M3D&)9X>!9@X+4{_Zc@u68d2Zsm+yW?7E z3S@Tqiyyr9ceirt%!Z@B72PG0;-ZOMhA4r0&j4bkdcyLXyjL(ysF21MVP}K(q+e~V z&}X-Ll^eFr9HSZBZy*RzUVxG~EvKyk3R|E9AY~##X9No0tE3!Tqn0Fx`!n(Zq6-k0 zgq{3Hom}e1oVg^L>?mP2m~wLuqeF!csV^pxnL z9B0P840%}`9zQ%fMW;zAMt?Vn;EO|~Fw2z+dpJ(s2@wJ(eOut;%{|76cVhS%>alO; zZ{NSuMr{}ShSLKZ~6e`%RI6(d&9%fZ+9* zI}Vfs1p|EaT<#1v>_J2U;=|dkdi?SB7?Tu2Z{+W!e4yL)+g7jMTcOJG^brL1gE^UX zfhdSyCvE-p&s07O^fjtrYxMXQ{rHiw#Lv{1{tSNdImUgRd?j)A%PU`KRT^!U%cYj9 zPx^49yMQ_=AXW_|r*Ze+yby4-tdnP#F->0Eh-;`}dyLYYuQ^crpYJ=M-r=;?6+zkzBe)O7__Twpvmo!P~T_Pw3BTsWH6&@GHH3YZLDJwb4(7vTzIZLV2fHnNTa1=DRCb873K1zi z-^PsK&5C&a)ykO?bKH%p9)V%>8}@quF%Y)DZpAUC&D1A7Ryu5Q^Rlj(C07^%Si)qAifEpXO~D?-R|j}|ZxVxueCK{BHx6tMuhPHm!8pJ(Y7=&YO5g1~ zx0e>SrJz+iy#WD#6-z?D*7$GIm*>~hgp2v5zp*W09%jC^1gdg8u6_u<(#89l_-Z!s z4~Sz~82|KL6(FXjyCiIOG8g-4%`!&5>u=d9wKJYYeX61{Jke||9A%GOJv!QNt`pI| zkr_8ERyN0KAG9Qgd{0mL?xslK#*S{E=x$~G)VE$?SL61540flpl?FKo1V5pt$C~32 z=OtRzW8A-0gp(wp5+^-}aRo@`rx-uNlfNj4oAKn>_PsAD-L}h_;xbALjo!AanYX)G zVOo3|y5rA~^@68xK5C1%)Zef`Cn7oR#`Y(=G|b1oXN8^mkst$;P_6Y}vWI9ry)51o zfSgo9`qGnwSW7)+B82{U0L(m9`9&XhnB$1ROj?;e7q9F^KE{_X@8o2S>YploOjo++ zQf%h!D_EsIuDZ**PA%~@`bfPm$s0U~bDn}AOIcxfMVxrX&cDjK$_|_oLUk7dkR2F= z{V{1Bm0J-mt7djJ)RIZi@8PC3FMjuDAnJ6S8PedcQq9N{rkmk#)E`LrKI>ckwYi;% z`nLN%R#G{K{QHqtFE~j|_$-xl;4y@Rt*hvb4tPY!A~CYGwiGXCV*O*50j(;C1XNKC5ae+u#r0-Eps2N5~13PL5x_C^e{ zjg_GgyM=9b!cYWk)NAL{YT;fV3&3Ks!#fsqq6I$I73I zV@2%Nx0}|^Ns^;crvZiKOnZ8slvZ#f(jv3*4aYae68+{POfMy>CaS}5d&!aJstYrH zZJV<>YK1s%6Z(b?`MX;CuX2N1#$M+;MLF~%gsORX`!M6e(Cp=cHq+@#>JF&|?iFMH zc%lAb1$;@Sc8@RN3NCUi;9mF2sr0YA_gCEXs(@l50&pJtua-rvZ+d3KcD7pWGD7DB zYm&}adwH}be8^niX&|x2$eBWr*drz%GtVD&*6`V<-G%MKP)kZV(SqrGvbQqJs?@YdbReZ{aO~21TgMSlY9(D6-VnlKPu90tuR9kYpfaF(=tl9A4helXJO7A4 zVVwAt0yYTpGB^SZn-Tqu_I_N+8Ml!65GIaeIt$65j>@C1exEUm*Rp~zz8F_^)Wdb^ z1MCkqW!Em`%DfT{Y;=S0l8=2bWkk2#Pogi3DL^Ungg#YXPRtD6V_X^il(WD|QX7Hb znv1kM#~J7pbW*T{o3%X#t(}xcxfJ~ASJR?__4K8^OaY+bQPYZYcjV*iFB5~+*U(0* zRsF@*jU1yVA``$cjYN-_PIysnMbRZ3KDJ+woY@6nSe{nJcOqDUg%UlI*XZ@$5C?r} zYtsUm{@~!^4I_efM>LUgUeL_!dIn%dF28A$T84a&B~nDNv&-Q0+nTlg)T`fv2;AlkDoQy!P^x<3fjb}%-<G;P}f>q*2# z|Cp4)5s$CSnUBf@7aOvat^rkA!xQXpmK6A__^;v??-*VCFz-cqlvC?iCXMUqrAIph z<$WtFYCg!094X=I>L-APQsK|2KF_OPKeb_Ku1*F@_pXYGoiF27V^#?Pwdx1X`$29d zb897QWK@c?zRGdmF9C#DdXC^>tO<``|Kh-AA{a$@EWg22`>jm|KUNEQZy_uFvgU%% zz-fv}2k|=!GO1(q>BZI(L!w~>z(}}M8|096AyGAB+fo#MB|Z_#8_TIurwT%U6=~S| zbCm4^6SMq9@%P%w-SZxkf05T?7YsIBmC{0Ne8H+t<%Vk^7va9TUG)U>cxMSkB?-?5 zltnpLpW4mjHFrR6tOWdH$zXn#HHRYvqvN7QF$aYze5mvEz8E2K2fWix=nP{e1La zH$Q1>9R-{dYe0BI$o0pHa%GO}QUd{E!P$H=?RaEJ+zz{sSI(EwqP)Bjr4bU{>irfU z@84JfyJ%uO$;(W#_pT%7hojIf(Z$W+U_jJs3X91XGmKaaRKl7lk%rKX7(p9Npa~SPEMfiBgP(Cr21*H# ztUW3d^v9*7^P@@}Ki)W7x`n@AZ$Kbzzakd+waKh##S*0_5|0fPlSI8fXU-y@n{JvR zOqJiDUZ4VnB;p?KGX${JztAVSBIz6^fN0-Lr&erns1y$4wb#i7yzoY^Z9$7mwVcU1 z02w?w3hR!Ug^R-Z_t^n1n$OlMl{~ztX81(K=2ZbwO}X(3?`1&PxN&e>tZ#bq;a|bG zI72f+NOp`6c6MVNjf$)Swt=f-6**Y?Ng$xivtsK3Gg^TAR89+F88MxVd0) zE$O%BY3gs@Hhy;{1T6qv*nuCaX{X-jXIuI_<<-hm&w81>`}_Xib>{kUh$EgR*5wXc zN=@%YbyT!srIYNvU&SMa76t{tu>*I+up<*!9p_(u_(%8w#5WD72~+;Zmq-3rq(H!F zrPpHvI`_NPJl24EW&y03%Y5dpZ?nq786PHZZqU`f`AHKHBv)71vfu1CH{zGexqoRmi{DvG_Kbe&9DdCABiOu1DMbm}^%8|! zRHs+%(WB?H{0VVxzL$kR=28^Wj%Y5ls13EnGB~z6;tDZ&x^lBSN6Ev!Uy!vm+VLdI zhcpRKpkUI|1X<0?EDKbjvCr!_9OBh5A~W|-u&K>ZP2;!8YbKTLi~QTn%>*O!Ugo^P zHh(fLk$fAV&Qap;m5_1!N~X4~dMI}QV}mK>X(+cU+WIdhG?#TOxxN6P zNc?Qn&y!x(A#XvS4zTPIx#O-3JI0e&6F^iw&y(!dpioN%RE+c~Ky(RfQL0i0tZu9P zUOPtdk8gUN6PrN2#lv1XTZt5@e1KQ2t&97mAsrLu611)I7h2_Y8RZ@F#?T_r_rWXN!SK;%y zdbDh=*&_}ylQrih^G6eMOg-Wv*mCVRj5`bewNR~DK4yZ4nT&Mh+eauOwXs6Dv3KnH zrE3bxoB+oiF|8jcj5B01+*7VuT)bw8dwsf>@A)(sd_!gM#-?vO?=ld@vjV;YH34Sy z`hpLHrX@FJX0-ue#Q~PY7eF$*ZkBC&%5+bH;wy`U-$S-M6{|w}ABZb%iK$mYmY1+C z?V0X-euKqiv;mLcy{n3xFzcn;Dpi|v@9Sfxy5nd4w9VnsDX%swxA*`zW4Biun4Yya zdj7r1uF91md;UhfQLorsbJmn;@%>-65%MK6KeHYPs&#VYN)?nvWIHp2_+kfa46a*G z{qlqL!#89)0G(=rC}{OcZe5`}KZsRY>tyav&i-Wm`FR=DhN+*wtPH%8L|m}psa6|+ zZk zY&N;NXzLe(?&;;|HgNixN=4m1c8CEx;6Vn7-e$LokI#DX_VjF@5Tx$>?)gbTY}7^u zE8+?=vy=e&Yhx0E+@|v|U9vrP%q|hCUvC;`c4ntIOOrzJo~tMM)O_aE-w1>t#m350 z9$-&6g?;UDkOfh@@veTtIUO`3R7nCOhdlK z?{+9$$9=r**W2AVz=m|{S;d@1Mr1{Um_7`YAhf_Z=$4gn%@*Qm0@O{cLUKZV)C^v{ z9V$?*q87~mObgW9j$L^`I3aSzo7JGve*~cHBChO_YKr*1VIuPMTRcRiMWkU`$K$;)BheQpRswcGXUb z5sC!FiWJHy-AA^&YTc*{|JZjA$giqj_l3i z(h#A_8wFqvePzA7IgjWQL3~L11TH|i&0h_*9wPqHO|=H7=)Px4uXjG@;NPfnWNDlg z&>!=_u<~M)2}az78wNL@-Mc24UiUsghD?g)wnDdFS@sZQIaeTIWu6$ai@qpFd2jpe;URf$faOlv2vxe%Axu{L~6Df#A9N2jvdfk*(OI_jH1{SO3 z*IdSq$0#eTdod#H?dkD)Ho#}wLm0E3Cv3NRS1Te>u0(75wxBSba`u;}+y=-UK0D1q z0>hUzLOlRu#;w+s<>YpA<8FG3La%^H4(y{N;3~Ur2y$0xL~7KA7)R$D=J=&hT2{!S zBQ8oNTMyRLbgTRa3iOXupud%bYS+3HY2_PoRt=S^I29)8YmX16A8wi__MXG?iU1kkD@Mx2#%VKdL`AD%?~#?;?q?zTB7z2T@*E+m{(S_ z;2{!^78voY{nc5#E}N5Nug~+?Qf^g5h~$D7dZ*Uvc-k>#(I3_^6A?o@_h=jSWwWu} zaC;M`vJ8Zq#;cB`b&ZqNOeW zFO#mWr7m|KlI!9^R;;~TP@8r|6S6&T<5O?(uIKLeQK?!_OzPzk{05h{)6CYc@gtLt zjg3i^1OE8k;Tsn-a)Gd*13}{AM=O_J60Q$y2LChSd(P^tt~Se9UXtkCm4yRU_Jf>d zVi+m}In@6(WHsTY0!(Wm%;Uz9{x{j{cUJsX2Jb4Q7>f-7`_@(z?SI6+bB>fD;R?uZ zNzM_^R67>D8t0T^`Qs7yurZ$2Z=62qry!yo=5&a3$!^j(K5d!0{B1-KC{f92*XH-GW2& zx9+`a3stHuT(9_YT{EfYiiI-A%CR3eV{KAZ{z_A6PgPg!|AGBU4EXG|61f}8+q)8S zR^Wq;MdPbG=vW6V8Xir8|Jq4RF{RkA_h)Lm?>?OgRJ^SO{o3<2VxEj9u(KD1Xgcs0 z(+%&7`NeJVd`$8rz!)#5-Qy5r=F=OqKenYpP4AcP`o*xtu5c-Z@vvQUjY$=l;UKV~ zkye%B%kWj)VPVuRH#8AZxwY~p!81_tp0;>?z;$Ok%R25?@20%WfDkyjA1FjpRi5`} z^g)cNCoY!NbX_sFF1JAIxurbRf=Q{AIEgze4f9vzhZ^CnhobWIxo4UGfph0JIaBeILHr8j|1JneOBFWrc!oIm{z-Q_wPbJ6fy)wLZ}<++{k zv#lFBUzSs~YjG_&`OC6+tX4Z3R-P!dCBC{-uxhhqx#FiPt!XjU>7pbjXF|?jky|!I zNISxZpxb z>1J~K!d6hgug`p>%d^YXr(1oxudgcZP`ws6ICkM(MLtC30F~yAcl@(4!(y&0g=9Z& z6q@3^s&}(P)2-d|#r8d=V{H^TI*@o z0$pD+GDK2HPhYZExMV8xj!F_y#1`>M%8HT$Hk!6*W-*(4&x76*X9)2AcC!`^-&=)ZlNvp{48 z)!FJWFPYHjG^MVy{WSVvx_*;v-0|ik*zabM{+MALo)Lb*Yd!LuhR69d!&uxRF;kUu zWU+E&(mvD=qxxP18BYgdG$0?P)&OeSm-m3Kv@D&KXayMb*8RIToVY%6(LveY>Kc3Yr-3Y$`%Yk9y z2{6S0@-F=XF7qLKDLq-FsJ>LhcKUQkG%bOnZY! z?BbwUTbnkKNVu}A@I!gsIqXj7;fWpE@ccRo1^a*$Brp3-D*5g2Jm_ zCTZJ5FS&1--q4~?bA0?Y-TkfT1yjfSvrSi1d3E(Jxgo*D!q)KCu7r!mqbqDd^bsYN zv)(G4#~XPI$>G`}z&28*#;BVJ6O;FlGyncaM=c$|MUtoJ?5&*az)(i*NVT!}M80f` z0c@!a9yf}Mk-tG>pC@Jjw+Qk9?DR{7=CBw*z$N)k{0-C#oE7WZIxmCDQ;zUwT%Y9c zTr7+PzJjCo86YQUig0rY+dPg5b~)>~d)GdIb3QK~ddrA1UX+=K%mUnmiGI!ck zN$jIPWt6}cl*Os8$M*boiNyHV`b}RX$;PX>>_71pGe#~^&Yfvy`Xs9T*f(FnLs$X+ z!~m0Z#liSWL?n)@inJ~;^UNt0%F^8wX;F;U%1w%y+)V# z;>t8$Tyw>kt&b^s?iB22cIaO*iB|w~^$=Vec8$1hYjAqo{}t0TDrp zf`}ABK&2B4MMOY)2c>r;)KG#Q>C!t<5Rk6)9;u;6nslOsA~l2>NCNK!eV%*o`>yqU ze{{)OfSEaS=A3=@-b3LfdE94V|j)iqhL&O_F%(vT*XRw0CTVFD9+2An_J4%*^u!H*}`Bjsigf;Nfm=;l)1p z$0CPj+8BsZe_pYQEC4jMiv8Ns#VM?BJ&67gp6#==+u1EBu`c(Di2dpDg|*vfZ% z@LHXU^-ATW;J+p=gWc*{Yx#zN%BElA(@`@9%sbvctE&_F;o5kVX&c|^sAo=QIzoV@ z+0Y?|j+)aAuYv!>m%$K8p8Uf?;bZ^Y&tFDvDn^11wRz}+u&->8@F75z%Z5unpFpar z3u_kSUA2xqmw%-Fo$46xovV8=qGj7Vg*KB8o%J242XrHr1KC#t+dDclNURE|l5Ax8 zx=pwL1YeV_&gjK9frG>MB7$D`G|JvBKQ7BXaQfW=i0EQFyZeFD~e{bcfaTkEI8{<}cvy($|duyfCiT zr=?`x0`mL&^%>*u_$?nH@kJllh=ff+m#PS}QHihZC7?pGnYH8d>v>d#rKhKgij2or zY-W%tQL{>INR{rm@tq3p=*jLJO?w;zw3le2dY@#Rq1)2#SRJ~DuVOUcW+MQKykta?#*A<^B$&&hDe~aT4hAO z(3q#6-~vQNW6n@KMalA9>Rf?hbiQRu8#Y(6N)CT*&K@oK1p49l2$8^k?r+=N3+05E zsA)hQv^4-ltUN8`JHJ;dE^_fX+nUeX=6Q}8FV{UQgq}48UV7o5_mZ~h&atkZuAldp zO%8R=*(fg5gk(N0M(E$^=^%^$A3Y58q9z)^2R6dA(mHy)VAAh90;sLEM$;F>O zu4crX%bI%I@OJgLr`r=c*S9(G%Xdt8gBzyye!98O0Vx{!Vhn%`19sdXz5 zR10BBqOeopoE%>~QVKo+GEUQAC;A_7(DTgmZ`Yqn)1cyCj*y!mGGzSrOvtLaQee~? zK%cjQl0JDj#J;>$@gnh}*rym4Hk#o>ABEk4mWrTDI0UF+Tu@_n4nBM7mDPYYp**v= zqHc6@(yP1|Y9OpWS7Qc4{}8;~CI3G!B`cyT_h)^A&M_?|si$xAUIfLuv*Xs6~6lxKQmp`6ICT z?-?26@K8+9y%tw<6A#@N2pvfQpa`+JKlwNf><{e}*UyKKhY~u9b@btlX#q#eL;_|y z@ME?=9nE!WzFf>ma%;c$FOwL|LMS!(L9I!Bl*9)e4Ty6x~Cwb)9jKXilt}6;^yydx5=qN!y4&CHUA_x+c`FI*M+9|!+mv?BL;J106E*Q zmYjHY>$`BREB)YRO~+q0@d3)ga~)OEBL{MY*6e5gxPpr14YGZxr%3u+7OXK)8xbE(=Qh(BWFFm26 z;lj`Uq+DWZGQ#F->iz$lhY{78pm1ypXxb=D+Sr)?d?aw~v|Alv{Kf&c68J74RWIk9 zDm=ytzWj{^pAG!gLJuk4q_6wBT`@locLtxgTJn=VO`VM z!V3^{+`62RfUHWBASNvqOJ`@oBp5z}oUu~0^an~0Cdsvxjv1O|Y=x3BxX1tHNaoHF za!@I?^xU~^IZ>SX`Ad0BR0H??!VzE;fc3K1{A` znE+R7$LCSfkjn{WE3n6BKdL(G{w1bf|3kK&H7rZ#p6@(lg((7}3vq`8F$1Q5hdOFn%c*H1u?M6VlOb6M5+Q2`DLw47^=rDFlEniC=*5 zap>DI*dOy26Y_y{;)yiP0dr?*&k0Bq%=`O!)9rjdjgg6e+nhMi=Gfp|80mrZfn$4z zO}umWq4(I6sgo1Q3lKiJ{{CK_-*kPrG&wvw`x+^nxD*bjS)wanA>A!qb841=!S^cD z_BZT$E4Jfje5dUN?)=m>j{U}rpie8q-ravJF_>%yy;Fom)qPaB^a zf5)3y#qK@q)4sMrLreO^k(!E)|H{fK3CB_#9YMUks63Ynj%M+QDjH%y+hZ*b=Y-tv zDc88C4&yfaJ!vD?^kU6v{F%G|RwVBVR*6UBO&03l9{RAkk_rcO59AMaRf-O# zi28+mQOM#g;VBzg`N@`m>vWR-tL-n=GS#bd)UU$;yGG@*tWY1R(C5$O?BG}f6OM~R zONM4IPa?OIK?_kUJee{IF(LG-8H9&g}o|(H0)Z# z07}}q2ZchYYfaSUtS`FPi)v#!(76~5W8<5DmEQUbw8y8_cm<-YgzOP)$nS+eM1D)T zSPr!JG8mVr-y^OU!n5m}>|(IYqq+JtK(ELZlD@e=pnKRRU#fp{69xrXcDDmG_8g{+o9AB5j6ds2`2l)H(fItX ziAg!7;qF3YE<$ptdYZ@ca$xNP=S^v@^s%|aNNzbglYZRu>T9gLClgiG5roZ&Ri{;Q z)2#nmI%-Q>CkUYfidX4Jz##V?Ij!@bI3Nc-? z6{yi~*dxIGA;AsU2sKr1!}r3?VybqZ1M|;ZiV2#hl6ckcJ&M&B4E) z-$|XHCPPV6xzkERl$fbUo5FabBBY)!p{lm<{ge^v=RdqhXzwjOqo+}Wzeuo3KkdUf zCr;!$e%j|0@4+v-0pLakg!Mk>7#VQwWIPR6**h3~eT~4}`a`=0QjM}?VLH&ONOZ5< z0mMu&KZ&*A-r0Fesl06uPZM}3V+^Gy(3tsYNLTMzPKMeAA`mh@2QpfonQ~(%g@kW3 za#A<=UvU3Nr^>g7`#M8Tkgf^v{vsN)BgB>E2&93yQJN>EA)xYrUP`!DYpLwo1UxAw zhPJ=(e3@^`a=l-%M8A8lV#;eb+Q>dJhW8KySDr~kzumGuo6f10Z+G2#>EJ7QCC`eD zL7h@Hvz%LU0p7FR%2s$@5}q93bhyMMp-PPY%4)QayKVGE#pYR7{GZ2aRjvlQ?k6vtZ*Uk_7V+!ND;6CXhWPIvAM-K`?+ zgjl^hQ8UI5TPzB>K;OG8CL3V2T`}YPR{jdo>4M2Iesdq6%f)6WVfTH%k6Pz|i4Rzrgja#5ANJTkF4hV1UKO^UU~r{bojaXse{Q{rr@Ug zlVq$OwxYIcRlC+P$Hs1xKpvBc6Y#Pt%tT@l>rp0tIoZ@c;bw0%Q0J|7%iiTP#QBtq z4qZhRxt9X^UZq@%iY#MC^1bafGpuR%UCnT_)Q6&L1Lsv_ z(UcvaWC86k{(-?X9;*gNIjKUtEAyr)&!e}U(B3yOS{s;Sol7Stns(RM-OM}2Tx8;Y zYvc5Pt+QY7$b8R<*JuIUeh+z?58d{p#$w6{8vjJ`a!v}%_xMXI4MiM4Ar7;b4BsCt zyp1zMeotMDM7uN;uLXWOKVDZ2N;)x=GMJvPP+Sy%SRoZCc`35hov+Y3U7PfTV$%IZ zjh&$*sSjb&F8l~;Ju>|c6%V@R4kn~e zH}^q(ltK)O?ciz9ndG(4>=_iw@x;!2YHJ^M;WdEJM-vHeHfxC2htX?x4Fe@x>dl*L zzeO_6VmvA)yP7?k|DREIly}^It|+LZ^%D`BNzo2w^=>Oz=BB^}NlRS7vNF1JA1=2& zuN*Dbx1u#l&Rf$&JGUx#08aO+7!bBxVpynF|8Lm=Ag5kDo$@o^p4rnvo@q|-%{_Iu zfy9Dlwa0^^o&m`%H1XnATy8>cbxlEHWulOV%?b{q+ck06T;vZnrv;L$y`*z};&$$0 z6kb190B!&2_W#eoTh8I1PN&-GQ~h3Ek>Fkm{a3Qm#M}H(MlQmQDYjWS8qvJZA!|p% z)wu23aXm+F#7bdH5~b z4d*4|asK+v6*K#AjM;v90^!X{?dlLx#6WlErg1pupFT_Yz()9)?r%~fVf)R_P~Zsp z;@6j=y}L)JpHDE{*ioJSW9+zBT%XYtlF~UI!#vm_M4vM=MBIM9_n6Ze-R_9x_1wQL zTc5v%3Va}oMsr&Ezq>YDO;dFKn=2eiz4hF+?kfDL0KhVLOC4zjty69|1->nXdL7?d zpG~G$tP|J6xo4Y(sL<04Xzy8B6*-z*nSByTBW{1utc_nifI}Lda&tra zFoc@w@ljBajtLmpS(V6{_GsvINf$#?DAXC<$p?)@0pGN=MD&MgJ^dcKwjcl-FL-Sy z^P_#0P{UzgjkbvQGo8B()R#@bIKF)G+Byfe5O)bmtowi6EjH~6>`gyg{Yi1|j65)7 zWzY4QlP`SN>+g}fv|)YHQmxJx_r!N(w&3wMIVySF3Obf!H`pM1@S;)AGlAjJXF1F9 zHM)SUdd}isMFdcNo@Us>pDfUd;BzbRd>N7(bu7b#6^oKnBFos69MQMS<|O=@2~7pW<&~eG3jV=w&NZcNQ-WE&kFXGnjX@ z#H1lJ?N|LEItWpPt#ztXx+1$-Wxc|+;D~f1Z@Pr;-&T>;smgCM+i!iBK;nhdXTxv9-e@mNl_|M zc-3wA{u9bGUC--}1kMm7f7pKZ>!FodgfnZ|^xh+<@gNqb89(@~MyvbSha+SH-w~QF z1Je@VJRl3|l+TCDjS4k3rL+Ph;bw?E$HD#0d35cRDwH%CkUtk9Y9T(d6_hqlMx_CT zyWgZr0}J_##1ZKkLfIi{8Lzw}7daeau}UXFEpH*-U8Lje0-%_xfcCfQ>WICqcrUxo zQ9a{5#9nh=WQPKKcyubIIXn618ZwCY$y(NHA~gRHRnqw?NKp{8s?_`lS}5JtyRu-t zq*WRtzT*+MP7MW~VrGpGFMCD{ywN7->|8F4y@!XL?Brn_`U*VpXhRn50iGQ$1F4O` zto#8P^cM_zQz-QIYeKG@A|X#N{bJG8;mk0jxX!Izc|Z|J0*d*c}KLQ2}TTQ6X) z0~B?@K3D`8uL$WIjG*|#o;ijiI`(ztgcGYmK9|g-@x=Q?=~n}{D5%j7Hsp9_8f>P^ zwa+Nr>>t+Ce>Jup0?8V028Ey`uFgoO(tvJ-eMQihY`tdt1?W8g_Oygc4$)Y>WQ6!F z49HoDhx}>Jbm6sNV=Z$dI6CeHLBr3O5>Y5g-l``OTM>cLIbbliQhbM=T?Kev(`Cve zXCo_LDS(0txC|B7EXBQ`SCz-`@ytE-nVMm~T8z7`q`a|4YF^{5ia=;VjE2bS5pkj} zDKYz=0m1eeZPbZras^WJZ{7vTesJE{!|v?NwXq>H<>U)}oEJ|?+=#;*D)?Dv$|%Br z;i6CCgH_&>BL#)pVo*@ed_)eGa?TYW3?axIf6FV^+`$PLMl6n9bm0Ic1*YSER zU&dMrBdHu$(|8jHNtn+bB86qJvqF}%*h8>zo z_ceku(T~Fy2>+bI0=hQ&;y~{hFuA9Gfw#k%^T&F@?lOgO-@HPfiM#+Wcbt1aT4)>k zugjQ*EJ|1?yHm%MWt>%~S+|`o3~zz3Y=Z`hMVwF)Snd$?-3;7)9II4tu5XjACIWMe z*=%9{IYam2(6uVZpmXbhkqIJC15h;I-kDRH>m`ISUZUfADKJ|3pJ2O>GU)cs3TD*SVh>$_JtaJ+21x31~Y9a0B0y zTs3rUj^7#M0;P?op8GBlTqpRdvLc64%`S4>Hi+}N4SJ49R-JREA&s^i2PD{A;(E!P zy501f?aPY&4>cvlK12kL2>nk@cmANJn`&X-@92cW{SwVNN$IU`%Nd5D_YSAe&hne| zgG~Z8^?&n4^7nvLCrlX9AQ!=uh`35i(dzuJrEe)*CL8Ii1=sfblk(@p7RUFKDj0q1 zWPJKsUu{}nEwlh%uZ|4_Gow}EJmWe=5+|D{HBpz3wrPv;IdJ$*>TB3;2$0d;#^2k~sBdbOb$#nYKMepTx8g!0wrApUP{Vw0Hn8JTtiaTx{3LgGcDNyC zJNGt12+*%??|ky6mF#YQqj-BVYry+E5pfYhHgWSO>(<%X$9I+9tQ!V=B-;3lW;3`T zy1OS@uMu2R+)0D}}S+qh(G_Jg>pYm4Jg7mSNj7Tmg<-guUk{~VBn z$8lfW_+4-5J4*mk)@!Y%v6wC8;u|RRf>$1PdYAp=4B<^VzhbzVn45tMX=C4bk|_cA zj0;J!^sOi<{ygZc9FBOFXzx61emk%U$cP%JY+D>hayU@3dA~f*q?^TZ?{uoVk!0ZU z6f8!eRiOIPHUh$ASX&V1(5defErKDC7Osz2%OwoQl&&wWqXW(d)YLb87_;%& zGiOO}Tq%Dzxx2`vDDO^ugf<%?J58|1UMq7npAZvQ$u`>=*1sC$G=v8N1+i0bV0#0|N*sJC20IW=;XqR_f5CcA%Nf@VTvq?EJjM!Rq z+vS0v3yE#c#k#WaRj6u$)T<%gzrnv6I7c zF|>x<7V|nXJoRpU5u@05Egx8*A;Y#b*G|1GP%-tCdBLtfXVn+FKBwPafv-{|k#3>% z>ruAhT%1ez(?)cDM&yJagjy)wuGZHDb&7_`cBu0B!J8vr__rUHmwtXJrtPPF8SQdT zM`Cnv;mqZ(nMJQ|7GWs1o(OECi1@_ma=Gz21%!vUpt@Ga!=D4ts48Py4TW+{q^(O3 zCiQhrb@^c5c(ZW6{z&qwRXpIO!0JWI`(J)v@?_e5vRL%ArPQI*;;4+|z7(z%{f8h_ z_-v9myEF7%QsiAVTFUWO;}zOl6sM8s4iZU*U*y2_5zODueyPW+j}^66xfnr@xrLDJ z1)*6bHtl&jmy`F>Zf1DQp)dD|n^|S%<3vPQW?BxsA~qy5?KPm!9?A@K|=lVAV@WKo49Yj;RsKHAW_Q?E{sIxA!8m9UIxga+t+vfOOjv zIAT}-(EyqOf@Sa;Td6QjTh*`O?JJAM#iDdx#PJVl47u>xFN;w_y%1VStkvaxe%%w- z_q*10w3!%HLw{H3nWxM28p`F2_nS`g-j`8lauwIKWh(pAB%S!*rn(SIc zj9lef!6+k>_bWEQ#9N!cY~P3o>=btzAci6FC6hRF98$;@=A*prN;bdUu^$7E=lE~! zT>H$=0gD(8t6>AUS zKydCvnd9UsZx%7HaJi?Cc9cx5>mj2tsodTEh6^o^6uaz6u(UF}cX6)02WV{Azx8Xc z1P})u)Nj*)i*f7*g>E#WxRAa?suQm*ZRZ25GE9KB~l7N zQko+2iVdPr#y3}@EyS_-#^qu=`?5l~*=0y_MeO+hpx`~gvz{2bGd(nhim+Sr;DmIZ z4&J_4pcuDCNiO!KmTeW=PU=X7&H``}lu|;#MtSY~lcHvF(fkw9wJxzS6h}Xb8_%=N z!kOLK_4TQ*KEF*95&lGi!p;Y%+)xIPRJYM(LVqw~bYnW{e=X5;lGS4K*cH!Lt*OW1 zo6iS<);qavJmY=|U*KM-9Y!-bAl1r%*lPF+>SpxN*J{#a zYX*o5%HQpdqR_OzyhiG;b^=y-)Uz{L3uC}5?4=FB8x<_xUa@PLTJP+i z=+Gd4n839H&950J2i+1QbJ)Ys1Bw`B9yUI2sZiXdkRu5Pyv2gf6$L0sFyIH8mrkD}_fBV?=?XKf$VB}lHe zDqOiZYVlVu_E*N`_yZN6Z{}6xu&wQFl=<3^;p&FKX8cT_AJwcZh6}imSFMdqb6ywk z;#iZ)?d;xS5aAFXp6+t3S5Xi3OU8QnW`1IWTt~i(3^ngxPhF~5y-)7xq^1u$EP7yW zRqJ=HE^k3X#k1l zmvxmrd|5K8Lo4)^aX3p*?R!UunUkmO@Q;VWVp_<-IEI1YP6GRyKo>r_EW%5S%ZIoj zf_{3RyS56G=qW4n!S&^n*uu({e0!H75!T!Bio$Nk@@}goL}G15fq=1XrMi&~GDrh! z+PMfJogqb5mPNvmT7`S%g1Fd)2X3K=VUrlPa&0$S3mx|9a>lr%p*8S^Q;-vDax*n+ zo_zUN((A$jPo2b!fy41iWf3*M>91rgtug4__=BlZrt4e44G_IGry zZC!+!%#_?paUSL=d+(vo>#oeL!tOf~1}8$NkE<7{Q-y)ocW9m-#!;L%nvOU#_-l?h ze1jYMjTDUseP;LK-!Yl_>$p?!`DLkb#%Uv-*qw7OtJcshHi%N9|Hm2ucfvg{hw)3> zx>8@qf8-Q%ZUwArfp?Q|Y*U?3D!|#Km;_PGT6c48>b(4SmlPHK4?mkB%P9Ar&a=Z4YP<-wtRmS7~O~%ye3T zbBe%vi3_k)V6oe4D_(aLn~pQ!-}K9p82ROAq*2IF*$e4>Wwz(9EB<6YKsO(w7Z5K4 zURsbPB!cPQGr=umwd!?BvoQZutdmTG^o|I}pj^a}>)Of=df3nA6xTE$2Q304{V#IL6Tds~A%bYbwCft3;&AJl zq{2Z&ykL>6gd{4CxA2JjvlyUEehOXRT6C+iFRro*69#JOxG zuJbU?(%2dIS4T-^(e7&M!t>kiz$8z)@D%Bkd)OaKK|lg>7N|8ljb$_fgshfg4-O%J zBu)o_B` z({%7u6dQQX&HD@vi~78q@by%zJN&j42(RIFaj4rh>$wr@Hs-_I)BdN4{b}8yL}sn& zF_|t8k3w;?(M;sMnUX@^0Xg^}xyN0~5SLuDj1~Xaz(q0k2*cf8;N?jN3PW98%Kh~5 zih37xdiQ>n_%Aoj!lMFx85{rwH{Z`pTWbq|S@E^!wS%C#`Gj3V;Z!6x{>Z!%Q@}{9 zvckLkKU15%I2VR}-;Garyct9zwau>Cu@wq?|L=4vW=6_|0g z(^2Lrd&#do>tWfnu_MgY>qyP%Qdy)Tq^9#xbO_Not!J~G)vcb|SB^j*Nq@pJUJOec z9tseuu^kH3`8Y70h5jqBotxieVQHX2cBCYB%;n5T?CB}JgzZn!!TGiuoJNYwSmHFK zm`*!p$k66UuRJqg{%ap}Oyg+(9KBda?r1*$&QmBzLIKg=)wISGc1=(klRXX{bKlC0 z8rNUCx|O=FcN;$qPb;nJ%EaV9?Wd=M4|cY<0d{#A=5nqCRoUz;8xB_7nKwJV8+z)0 z5T$^b9)%9F3YgLPb8f_UXTY{MVwnoL>)yW|@CT11{n54FIr+x}+CYoDZ!2$PNla_E zM4ritD9^Gy`q*a1pEOXUAnX)085j%_(~;hO!}>aVa??3kAcWbjzhk(OwP-*@WkS>< zSl$q}`1)L|lWS{0%#9d#v7Y@D!8pe51B7!vS1HCYz}Tx3$Wco@f!}mGc;10x?R161 zRd7G@XYl7;`ON2OkDbc}01AJK)0x!kS-HAP!Fw)XrP@@ELR8`6xJCx^cwm;O6);WkprGcIaXcV&4JMdP8&0=uG!}m@Ho0BDbzFSzSnmCv_g2&2^TAaU~)uYC?(OUE@u248CpVK7`R>BXVqUe4y=+{Dw&TdHE_?`bj^AD^ND6)nKI;E0@PIl+a(6%ayyV^-bGf6)`XAv? zLh=5ihp^skoF2B^=x{k8&(&^_NO(`;gqHOphx~@mK2Tk?0n8^+;LP^r{_Xvs&(wAM z@8^n$$9u(s>LM=G^b#Y!aHNA-VzJygaSlx>Pfp8-umRVoV|kd!aRh%S?wuL;C<^yn z_K9&(keU8T$fr2wVU%R6^4YI@*QQ1MYQ~k0#H(#M&a6L>{j^Hk;(9X3=EgdhEcO4` zy|!J`27Qe5fm>cQdREqn`+bu#aQkactlZg-K}8Hm@@K^`!7TTlCn289RBrgEdrqQU z4Eh6nc^>L#a<9|90`qR779ykDS1B9KQnah0d%|fk$IPn?LN|_5&wDg4p|Pjj<^Y&e z^LtkDVtpW5g+P}5_HQOUc>>b4o+1L*-81fB*|ZaY+(z7}jWA1xWEB(+4cY2bW`r@# zyyHbjb9)h_FGmTtw4y7+MBt_{cDi=bP~ zjY84XYrd=SGJrM0xqUwPEuW{7kdWcjJ|o(@=(R8^;~uM_E<Qy9h)kLF?38dLs? z3N+}`k-D+7m-Vn+>JLnHirdwr z+2X5Rbnes}jB3DuDK%-s@6|4mz?0AaRJ=;_!5|`ubIOo!8m;1PR#XlW>bKCtGog$_ zs#1k=K}13U*}y$)K=;#%QRbEZauu)UPtb-xIB;~G&+Fk|U$2@O+{UZaD9W$xRud@k znZ%nvk=;eqYlN5Iu2SEJ-m^B9bqbQ&t){5jbcG`kw~%=p|6ylSQs!$hVA_@~z3CE9 zl`at=nBD`hNHkE}n*cmYnrSa!Yx4a_6q^C#M*mjZOFtRLN4Im|o-`eGKa+RlexR_O zzEydEc{=>t`$Mz z8!3xUtA?8hz1dK{+#V4ghHpa0Pp`-6Tz-pY#m>n%><2l7BJO>Z;NU3Utk=kHjWM4Jo#hm z2jPAlO4!@fABWHA>lJm=lD>=N-_G9UKxWy*EO}M==0V?RYCkFLGA8C!qUiXiP`dCt zcsSFZv7`wOZ`3g#VRkGt9!2C?wkW=S5w~p;i-=o7Q{$A?@(2U?{Vbj)S0 zjhK@pZbu%)vIrl3mHyQtmNaf<`srN3?-wUIP3p9JAMdMA>)g!y=I|oZp}osMp@)a& zZq>a)=9KP>=dg1>f}|I24BcAx{i%DsYEv&0KF4DsvpONJ6 zG4`M>XvsFFhu?5_V)XGLNC;Pa3e+P_$2j;!$%t}6w+88P^***p^hQUBkCV{ zvSPFK8&3B2`jWWjKl-EGw1w0;1fZ77or>^qMq79cuN0zXJ>qVit-bBl1-!b`~A|2wc?z= zv1B*m9kP8%50{Gqdi?7z_(V_+&1Gj+>=2>9*Bff0)x7gGARX-WiH-d9ER0(W41m;Y*)*P@qQ zpuJO9727dZ%RhwM_&j%L#3LLp5bt14D%@=|SCX}`oo@eVWvr-I?-q)=srq}cv>xM1 zFo^I;6DUe8DS^?BKTVeqHw}1B7tn1li$UUr!tU~kotCv0HCYMpCEC@TER;V+wNBdg z-fm9{gE3S$zdhugkC1r7cM*=lPuiTL6|6X?NjQb({526?uU!%L+W1uQn`pB0qC^?l zxqhF23|E;Nj^aOYKKI%vxhN6Gcz@eZE_W=5d`f?yz2XG|9d^@T!ZX3;6nI$a5|y(2 zU2XXPo!E{$~l%iz?-TuYxaV# zhS;aJGUh$D3D=P<&ZeIpUvqwWMg-0P@qDW>r^%Y7ssEPY(f)7{#KTH{ z`Z90A$WT@3JsYN%zZtPZqlTx-jTg|dk-V!X0~CMO6E=VLDHax9SxE0EFhE$~)|I9A z_;yyo_mP@mJPAM|ZCaTxhpw!$W^LKAZ_&di{h>pCtjFls`@^ zaWR!1dMZ~GR~~848>L`GH1RMiS%V(V{fIfe+NOrkLodZCIn?_fdVU^mn$$)eoYkr4 zZ+Q#0+%jAPk7KG=<7j~Mb=@Q%p(1vLD7x$<4SgJ$_c#;G#9lA?}^1j)4xBdu)G({WJ)IN|hFx4AAIq1ZFnfX-!0By)>@zHe82f{gbzKPB6 z%#^Rs8i9B0>-)6J!e3EB#^p>c*~UurtI1O|QnMrl*+_;weR@@*Ptdx;F3EQG#I#+~ zgONe;psAm+1&t4Hq}B3Ei0%p~ovAaQ>)aKPajCS=6VORmv_y$YVFgC4zp%MLaia&DkzmuYds%CZBTO;$;?ReOU_Ghpgf;mMrTbFU zFpfK-x9~Okc^5H>8D0F&5m9dPky=M)clNqPPv2T>?xnhL_JLAWw2)2%=Zh0oULKEG zYd9Tb4uwlB7!2K(smjS2J};++?01u=d9K=v&$g&8W29aq`8i*E5qL)!o?5w)AR;R% z{4$Mv#(algL7Ohc3+I*M#}s@`3Z9oeWoavg+Sj-1__i34Jf0wg%RX9; z3qP{6!Let%n=pTUx!FWvWoqslS?zL2>sEh8>ie-P7Mo_Oocwh$5d1~MBWfw8Act&z zAmvvwZOH)etang_={f@zym=adAh&hYiml{OUm#`3->q6ud!;YwCin>-$&`AoT3ai0 zZg6wsoQ}{dxsP|RCY=COwH15@vG?`VeRHW8Hm6^-2e*=waoI@!NNh@L1XWpU($@QE zmObOm$TzTMHC^5|0pAGBZO(TKp8_Wi!?V^pLgz(p;PCeoL)tW4vOx_KVI3@Ir^Ut( z(rEt$NK3F=4?k2WGm`bi1?bGBhSzW3y{?3XnjJx*XEVNAS>J7Y?4Iq}H?A#2!?SvJ zC>*cib8DgY0XXR2Gty4bUzof3GGQDu_Yem8w6am7wYzfRTB~rl*p_t5<=?$(H)kb- zdkJo#8lBbn|}LO_n0(~b!E6O+wa;X zW$mZ*t6y*9F@c_q$+I$fHao73vh%ZSa)gDw;rwO7+c~hFgz&bI#tU94&WLpQwF4Jd zg{bbs_|5dfw`yLis8yZK+xV7wK_Z#GNL1{clTij~k2){sV14;sL=)&I3sv9z?6NbQ zqjr{x(u#h;1s3^bb^Eil^qP$tTb)P!8%>aX<{!166Vq}18N$&MJqlW~G&20_J2397fR>Ir=E&sq&yY`I^XUpuw`!)9H|0I9`xxDKW6 zDzUQlgQf!=eCVSHJj2H8k!j1^#7s|7bjgXG%H#3m&Z){C288EeWzF8q==VOg-}F97 zS0(pp7QAwx%GlgfUEPJHsZ{QEyyY)25-ZMgP>**tAz5DUcm;!NI#DV$Ki9;V)Y~?Y zS(xi0@S0V(nM#8?18$&WAf^4g?awJ?GT6b;c~B2ZaBqCh zPNx!4gYDtNkcvm?ZY<9y`X&D=JbA`dR9@t`;pp3E(pBIoare6`6Y9087ZmGH990B~ z>-j&4i~CP;cHPsy0q0{pLj5YImumvp35aH}aqXzb})%!{et9DSkZ1lpr8B1dsBwtuAGx1_k0z8&#yG zPp8DifH8xOR}~$*einO-^OAB){WzcQkaH(mRKbyGfzB*^n3B1s4^it-RaF4zi3%)d z<*|QbY6xUF7O?RrXx{~>RF3c_^el1GeUP9v9BnmSp3Wz$eTDdxGMXILib)rb4{sd= zaq{cKkYs4ugz_4{^;f%Hy9xt^Pkr3nR=BNS}XN*XfQ5XJYsC7%Xdgc?lgR9#~z>l5L_uj`(y^Pr9V`+_m{CHMQO!)IZOuUfMjz42o;n0dWc zcB&kg%_UKywy5@vUzEx;Tr!LE27oPeEk9xway~rvn##fitaz1W`t6wWX);`Ia({eN$RQCdt|QTn><$Hz3ZCYBR;ioEezS zRjrSY$B%P$w#)vAI!$mFe%tDyWHMbZ!#Wh9e6r;`*a#}9G<svru+o{~N=}Fg zp(F(=aNQbHb9`-s&L>#x9-{2E!g)%6-s^5^eABr(tCMIaVk+}IDzI0k=e-^XY5}a6w$G6F{0aC9XGIYy|M9iAlq1nu-R2Lw3DWKP;Q#!dt7n6! z-Bm8SJ;Dv(G$#)#R_e+*xq?Sm%LSHp^z7r-^)7f=AEM&0#!4u&bghRFB5s|0(zWi8 zGu|#hW|^~be!=9_6n!zdV=RCi9~wQeYjTusl`nI2Dd?To%@Y4nW#Ql-h(&UjY9?d+ zDCW$qEU!hc!%Ht*MGB=O#gr0t#yReZz-M=khFW>DuzV9NUYbi$DR8N)?L)iD`Ig$u zqwC3qZ)t)J6dGP0QP{R0lQpV@o6c)R6*ZzoP#Y6Fk|^qy{Pf4y3Xd1>(*&JNmdAd8 z-^o7$YGh~FNLEp&>Gk=G9_2*7UlDhzUtpIne1s~G*eTO+_oo%4@&|wu`f0;x)Jcl{ zN00&w-3Rwno#R~jk8*twI81Y%$!A%b`I4DmgvT(CZyP_htQoeLkLJ7BuQTNbEV`+} z90)9ZGSB;C(_KP;dxck6fb(+u{C1ba+*0-2<}S4#!QplhfB|uEqO5u2b6A3l83(Rj z993PZGGtBYbtaLZ_i$pOV%im>??_w0b_oVch zRty_vxU6}e+I9)@d^Z#Ub80Owwcn3dWA1Mt_na@9M{Ocrrh#Xr?`7lX0xHPSah#4y zX^4n9ox5@|#cr24JBD57Xftb*u$oP!_d6RBg!GZ zgzU2K48|D7m>Iu&^!|K5@9*>cj^p{q!En#Guj_hk=Xt(fH=cg2tw<3MJg#9OTf{c9 z4rQ#W^eOcq+~h;1#%`yrUxMHAHQ8{Vpsc6C8t*lgF3poz&kZ$Jf>}k62lqrwQRcio z-SXE{)aVweiihdHE{)E_hzz*4PfHxHob!uICAoDH_3l@GS;;(DS}sT}T`_aG?Ajcp5M8qu@OYSG4mY&%Rkj|NFxhuk z=%v{y;X6Z;(|x|xHiTT4hPc38m69R3cby3a$XN7lQr2{+Si&~Q2XaW{p=#Z2Gl@sv ziE=}KHing}SK;Y&B%@?P+Pgo6_M~fy z?7AD4XB_d{*xA&mx69IPF-$9(RbXpD6;;7?5Q>fkMa85Q4ni8wMT)emX2LH#uF`xa zS#R{V0hQuL%8S=>IBQhs*AX$bQZy1hZlX)}{aJep5?<6Tjg>7PGnMgQes;H5l2kwO z{8khpqW!<8L&^DFhm(9+mdUOa*YrS7?Si`AO&mZ5U6w=06pPsDBGl8&4)5G+>v|a= zVXI?HT?&Yx=xa(oO20RAP60KjeccQZNP7-&TMxlXs2sY&WbXM#{_=B*(*Co>kWQ5p zTqM}pDQ|-f{yZ=BV~@x14Xj4N39eFM1iu8Ok#>3Ibry}iJuED^ON#x)?_mK%%?11n zi8Sy|ITiQz<7fR)rh2$~WxFLs< z;IjW4NVSDX$8V?42!Ze8Tp`r3)B&YNvk60AT7C45WOZI!2>$kq-XGTwi3%2;>eBA- zmY9qYlr8r?O8iu6+u@|d{?f5IaiB!-iuLmfSRMyX)&LHNm2HL!G7Vz=qXh?7uDiUr zkMoK>!Z=Vv2vZQblI(JIEDg0ra7s3*Q!0{}eChaUgSkOtf7^~p$L5Z`@~7UzoXk$e z)X>96_<_@PH6$e4acZ5o=-c;EdZzCk|6w@yS@QZx$ldkxF=lt4j;kkV)nlPuomZ1( zlU!$}R8tY!i59kTrY;lLfN;h`1RAtjpfsy}0tWUXG^Ng0fm-F0$|FRq_g`QY?&kQH>bbMJAY zV1D~sr+4Y>6Qz#_%3aP!jHC~^2Co1h*zfs4LLT=Jp{HEM2Wc5A*g%5v*?aKcSZ;=Z zbn`CAYX9<*e1__iLjb2{+uTk*Fih{X3hLycB!oo%-W9#A zyHviO%O!jj&)c9PemW4c)frNcdYoz-&9;(RbyXjv;O4gWpu6mW$TT9vJ_&C0CMtg4 zyKP4k8YF!!uas$rHuHWnF{YZyfez2w4^9^TS+&jHXf4Kn`60TpzWtKVFRdVTDKJxDm$hl5oGAwi`r7CKcN3$rWNIuPQ*{gKgv#sinFL}i->E1V*& z9D*+Dmy5M6^&OG!eGc2QNCHL&=6w+WITjuP6{$^@o*;iJ+UoUhcIzBie%(atl95#_ zY9TT#_+f>8{X>$BWkZUe8@l4F=0zI|~(dlCF_;qW!&Pu|*D4_wggok}^G2KLU$`k{>PGA1n*<4?>T zAY3nvOEl73CdcFuGZZUP!5FzD%gh_%ONO6uMX{2KwtcF2?*7s7=m(Y8A*Va!|$xQZ=v08B$V?1xX;5O>A_5ZLhqn+aza z0EpFLa<|DINHZH;R1@lAi5s##1E4q;)ezZjfQtc+YSC1I9HJ|yVQ6GX`=Y{uAq)0L zNd;*1e4BTw;5SbXjOdbbF~WI-shqYsMtDrzpjdmMRMi)4^(BS}yC<Yw=}Ez z7du;rnewQU4L*g1LCMcg7xx8Wc7>RZ?BK-twkWwI#^-R!D&(5IavV-G@?Y74*(Dy}x zN0#zOqh&0E1<700+X8B!ae710CnWImV`4P&D9DQ+HgeRJBW26>hvFP}4J~>^+%-0A zi@IgCccHt>qn1dqcC0=48=8RNIR`@We*9(-mtYMWBZhli+K)D!PQ;o^&A7~Uso#Sl zJKs4A%hp8-$`61hMqY|Sv}~WInML7HBloqpu0iZaMBw~Pm@UTuY@*< z+#WLD>$j3tYcpsKynj>WSwq(L-S>oog21ofzHM@RcJ*xV^G9abgO#_m1gri`ms7uf zr&-feWZWpHsR4YDKQpI%xe4iUsaGLU<OJ&RsfhgiawPmn-5 zm)Cq&F-J7M`@VQz0F)0gX>tey6~i>ip83wVhHe45TQ2-Y!x&L2-^BekR770C6|Ah3 zFxRx%B`1K8T;Q8F8+XuvBWs3+x)LF+A6MT!y5k-UoMa7jQbo zJSHqZAmbz~}f!Q55pX2M49_kS^))T?~Zl9b_xAnuKOg^UYG!5C7 z^V9;kBH>L?7=SCj=E=D486(W#oMva=lG&guM_1FQcBilSCWB!Z=Wu@JD?^F{YWTb$ zr!=~nQS;!-&S=n{^`M9LP`;XTezN*nI(wb)JBZ?HAhpA z-|1!x7X61+x=YZq7_!oHdM~!@E-;igo8NM+Y!$Vkezls;W3pD6P@Ys;|A1m~a(W6FIC!ZCCKdev+Xx^;5@8)}#cWN{z3k zncPN117$06I)I&+8WP4RmQz>(Ou-D+BZv6li91t(G^51Lpw_)QLxi!6T;!G~DfZ=az@ALfW0;tDBB>gNSQ~G&R#$ zJ;TCPI^vUNphseSl_}zxPn$@;;`N#Zdi{+RI&tqNnKi5cP=@0`du#S<$5>ET2AAzW z2z%R$R0BqB05UF_^4kYvDjzg&9{$IVmbi93gEY+B|7tV;X7N5%RiV%oURo0M0L1tC z>8F9u0I`xf_q+fAObQGkme^52JkK;WMxR)98|Ih#+NMb`A(nsJs{pN%6Z$!@P&O_? z&N{nycIKeFPPnNB$5-)$rNo*W0OX_9EC_B2tFL688(m!eG`<{jVNr}+xTw~9t)wKD zY-dxlv1*27I~utaplI1^z8Fkh`~t-%5Q!hVHuo|X*@CAa71N%@*n<*1fHdK3RZ0NU z>h13E<(szDtrx~6q7mR1{;R!hb~e?(P|Pd`<)C1Xo~x$GrOQFR3c(w>i|vlA+S1dB z`K!krIu&Skv)%!>i)p_>uRU^e#YV^KNAyanY&+OzJ1QAp_&Q8Cq_nSEH6!#d5(R6P z&ZpM%q9aoozcO;*F4w_(dOAN@JihpWz$6y0*PGQdYfF`)N>(9#klvQSgEvgL)U?4p z-gnCvgQbA>f`7CCmNrz=-F#aL6G<$#fGhu=gy(k}7=Ag$I<~v(8_yShrfKYMx>bA@ zhsou;33qg4ckbd3(Q-$H{f>Z35EZJQ(QG$?{r88^Gx;)v9jm@ZM4}13i4ll(Q*)$S z$DY@h@{Jc$EDL0{vR(yzSy2TP0)h^x6%OEqaJL|4Z07*W8%M6~6+L2M+O=xBAO|L3 zVN>Q6$En9g&91KyhPPo8dUEbcAc#FAEQ5RC^@Ro@i(Fe3?Z^y4h5MWTtxY|egOLSB zbK%EsEIsJ4Ol}i2&*Cq+%58RIfS<=(U-nILTU7dhvV?1dz8&1y)I!M8)y+(TE4&&& z)1}O$x!?;C$X7qR=YQ{JSFaRqlO0u}0OZk1ODG?++n23zAXCli?tr%`zyMyetI`k& zPK{|@{W#DCDF2Rm)MvHDx1k7JR&x(qTyhCN;fiT@L}ktwF9$blEU7kBJQM60dXDNq znNFJ!hm}E#7~^cY?Af`u_xMg*eEKchhMG3Q-4r&LM;(7uaDN|wpU8gb(X4eYiuK+X z0F`s85JP#tHvKxq21s7sf6nu?T`)3ia!DsJg&$&M{`VvfF|fNP!Y>|xCGGA?-M%{j z;M4P8%1by6EZUy;au@UBcb-*!<;nJmO6aekeee#>V7(mRO)}Q%<*l_bx20Z2CSb{> zvsrS8S3{1G$hqgY02V;})lK0fEcwJc;68yD0juJ9qabwS{afHqC!_OvPCQBqmj*^th==PgSmP$}4Xsa7t(T?D;`GPh$fV>ho?rLD>8E#^7L9!)F<*OOsC;%VEVwu^& z&GVw=TJ;Mhpg2uuVyblO20f@H%J51t_jtYselu$_WWqx~MG*g?jeca)@w{<}@>xBS5`rq~ALN zP$XPzKoxwvD*6U+te+V^Oa^k;dpG8L6IH%S1HTew`{#fFem}uaT z0`~*SWg`Yr@Oyx{-{L6E|hKL z`2V?Gg3*4jE+x$Ue)}*T^v_2Kksgfl{pXM|j(UY~RT}oUoF!n0Tt-h-U;MAn0bY!L z`G4GI_>&j7z(+~?&St=K&3~^v?K*DTFZ|LyBYvQE!`=-2hmS8f9dPUV@#Y6Fj9(FA zh+#av`3fCi63{OD|9rtJRY#`XPJdxmbRfP^(J80VxyCn6`1{gZ*qnt!i07OHn&aLm zlkD8=Qy!L|&CN)w4q2kO!IQS@MjpBh6RZV*1cmZ}Q)9=Rm(_wu;H@oMMkmw& zg{jBkTf68mef_A)5=0%@esS*Uo=GhlaS2;kLTiLjwWZghDJrNV>C`;RwO`j zAfVq+qx;UA;>iit@NXD>myvZlo6o7}k!%`K*t{CNh_QomXWLFFTmj3YIUT`an8uOp z1hauHFyLUO+tYB;?=53C?%-H$P`3I*lg3l|#n_9B+>YSa(w(e#h{Mcg410xL{xoGB zNi~JNK`bBfF4@Z+H?vyE=V;-nWeY0!QrO-qqK$y$7E&}Q#wf?#S`!C%xj+D7o???& zYJH9V@TO+)$oZL=rI@ed6$oehjBm%y$7q|+O;7!^cnw)P7?ZE=YQQyGY7G0T%1~BQ zMsy{si}cP5?3fnN=Z6n*nv)7W9;r&J%KwD6NNa zKngSPaZJv2&zs16QOhdw4M!_*&w#w~N8L*6bfMPK#Sl#+V9|U0f*u4Z1TwTBLyl4h z6MVpdmImy9_b}#1x7_UJv9P*Cgf}fRqY%g*ESOW$0?wFz_~j<}@(ay~*1f4UMiGFo zY^-J%qQg%D12}>X27c=+NhF*}K3i_(b|?K_WT>;D`YCDM1s}neQdGtz`~xxh&Tpud z(KTIC8WLa>{lunyg@P+)Eiqb7J8-MVEZp?>G~jOy%}Smc3Q4RQ464(u?iIZ9Ws>?6 z>2-O}z{BUmmOQ11G~KhMnR@Q*l~sdA;l~9fH7$8l-p5l|x-+3E;+G{*L4cGZ6*-VJ zy?%e2Y~fziG8bs_@&i-ZZ%he}v z;+}L19V;le$loi0lO#7Sqhx+d?cx4?)~E{6^bLDUMzB*1Em7)i2w>0C)3!66FR;LeIk`PTnrm@_Z`Yf1 z|FhZq2mHF;b%NK}W}^++3qMOaOkjGTa*E>$3~o~UK)Cef*NS_aBkAqZpV!bjx2zIk zHB%ChM-#MNkhwu6HPt^%+fYS!D=#9-77sSzw|jm3oGh$>SXprZlP0h{Sj0Vh)8Jgo zVl1mFxfqw&kYGmABi#jzb*5$F(F*S9X40+^;14_?h>MnI(Sf=2Zc5QLm9GM`41;`V zaEg>eGS6cis?j4A;$GSw`X?WPwFRKPz|o4{vLfv+9s5DL>8vjI2(AU#l~ELNgP3wP z8h8@S_nP0&&N^Ccwh% zxW#xg&uX|GR=1xBo>;Hu$)FA0I#b1>o_#r8mXpIhZ6gX{h}FCj7n6qpF>?`5dv}}kXC%a+-(2g!{48|2=NvtUUblZ>SKK8DrslS>o8cwM zddW>ruBg9nctgj7CtvJWHywqr3QR9o5B))oGKHj?2t)wuz0z}i{|)}*0nY@^m1_c0 z`y~d}kS+bFyU|A2bSeS$2Z@kFoL5*a_=C)x76thDe0_y@HJ!jNG0^m1n~6Ti#y;wj$h(y1XP;IDBJw({Gb{_XD5?# zaJgDT66jmL^ocz5bzIaHi~%~c%)$Ya(*b=RJowkpO!4xnL2rECTWK$7ADG)IMG{WN z_>AL}AEn>MN`~uA5mxGXpo^eJrC7l|82C!hW}2#STqa3+2=T)fvdfG|NexgxTN04 ztp1RLGjo2`p&XasF0r6;mm;_J9vszI}ij2I^23~%aNhxW)bnt~xK$X&2!wc`vNU42W;<<(U5X&sY1qO7` z^rvGs>O(I!|Na*&Ob6#ga5y(`y=|#LNl9(ZZZ8MU${xsJbiLK0;46uc`kwVGUS9>t ze05As9LHXM+2Lbo+MQlhG9iZu4Nh(@V7ib-pGpQCacT%>zS7vg7h0bC4<+3n9&kO3S5U3K&7bqoD{7=@@B8rU_}5$a|CI5MFwF*y#Mp+g04wucS^3Q& z@aqN?-cYr_>(AB}Uz!ZVEli6Ca z*c+MBeN|(q2{ZLz7=ibs-6$g0SO3kms&xRLJOhcJYA}NL?KlJAGc-h5%E@aQs=27} zJE(rVYL{qCjdZ5$`)jtQsFP!yT4UoH#8)>*ORnlgL_)dgZreK@`FkET4)wcuik0}^ zRZ(0y3UXN-6s(2pf)9aDqQhGP?*oCQy9*~fcbJ%qE6Va5M2O1V^`RC(vt!M!x?KHe zR<4FOD1D=B{t0>ajc}+x^|rbZkoFcZ6^hH(@{RUgV@ErC?wpOUt|`5QF&8Y0)Q;<^ zeNMdw3`ULp=UiO*04tkB=eV%qv#VULmA$;Pms#vF!-QE&@s8u>Jxx8%Ubr==`FS`Q zkfb$)G!SyP%llkBXJ=;6@>)ve(DJjn1;jSWx15lim5+h>uE*NNfgrV7vEJR+%Y9;d z=2l@D=0>2r|M$}v&)MbWLZ&%@$lehbaT5?UFAUEYCiX_bI}sWcuXtBS&fPU+xe~4T zY*c0=#5Vi0_f1-ff8R*g2gpm8li zB>mg!(Ibb$Zq;s1EW6mr`GEneAI8(gjjsKZ_ckNo-MqC7%>szwn4Jv`d=}sFV9c8~ zWIvn$9`{AE9C~Ol+QYXTI=5K3=dz-@R}tjYtGP$WnfUS;RJ3VLh~_1>KX zU82;Uvi8W0SMq$AXW!yyI<#KeH=D){r3v=vma|qFgzv!d_nE<(t#?!|S6e}tBEJlEw9YK*(clU6b0{284;)8oG-qd3~}v4zqOdMf`lbSD8QZ zxF&>j4TNG3*cBYBdFfVrkO}y1PsU)IIv$W{e@(E4wwfi|N5K2|?q1wH(f>H`X88_yy+lwpx>vERj-Q9{tGaPEWwx7g>Hv+AG@BLPq%#{kSVu)R#W*5Id7 z-Q@g>*dn9=f)3p4V8HRuDQ@vdwcVyVQ~4N|J(D$Fn%15%_6mQ#IBO9-?f)M=q)b0>DZeD z6G&~L1a=r)lFdGmSnN3oy>>Si3Z+APfvp<(_=;pZQbzC#qA2^}3Nox7?iC>)Llk$3 zuH&qUUmfQ{c>UjO+Uzv%HZ<^g9zy$yDGaYa)XfDoFo8g3W^vJk2NdbjE}X&x$fX|V=CE4JbHcv-cJ7DWHyNw z+tt#?+DEp^>=M1yG-uu>;?^U(kA0neH`1K_D^|rT&b&#cZnV1m{Z3Ocu(;){&jB~y8DWIn^v5{qRB9Otv4QaeKuFx@@4s;fr|S1 zF{RUo&sMl@a_nTgL@ibUlQlhDO-zdM8{si{>24Y>?Udu}CfYh|!8T91?p`{L4xhC; z&%c#-V7a>Zrt=ZFaycx5ln|^E=X%G6Dj?|TaxJ( z=PR6Yc)*0t#q3+j(xeg zom-GI;;(JK24Ef54;h+(C$CWjiZz5pG{1S+(hhgWf*c~nmj$=?AQFj^Z{`>bNGg&T zt%&=Q`tf>ErMH2arlzXq`X#oNytH??Xuk5;Xst;se8ZM{?)0?}x5aI#p0g@?kw`3w zq$LAB=!^-U?FKqM0|q0^z7-3!qU6+PhMr)_Ve3-8$XC4JoTN5|NGsUgv*nzl2uxWji4|-`U6G;$lZ1C8XSaC4rz_V|^e=qeFM|2raf)td1*C4D z%-J$MHQhXU;)9v=$^+uF-|Wt?stu9mXk^!fNwnZ+-}pt2ofXrrhlb}jwkS&Q*_lB! z5xbcqn350(%c)&oW*vZ+bqb%J*7+&+j+cA+IeYbA5xI}7yWd6xTtxhgljtctFuXIH zx3&t@S$0a|{VK(o4$W@3v0*;Wm8qGEbO%vNO)_yF9#_;V-gK6#)KpF z05ye@WF2bKD>8D?Xt(`zUBA`Ru*pL`{V{CH3a0c(l44Z);%;iH7ESc0CSNP{Do~h1(HNVyY-=Q)DHF6f;Ug?>= z;63V*@c)QMz!_&fwUC!_7Dx-il$0Mt3WqeS5Tqv5FW6@Xn~4Rq(kI;gOPB+bQ5_)iEbvbI0FAE8T=_F8 z+mbd^po_cKU=GUDnDM(=K9L245}!eHR=S1rHD_#-vvx1d3xN;#H$_>5yzCv~9#8On z1#HK4IY1T-T==88a7L(>_Y0syKA-2t86E*-%Rw)BYZrt*#jcVK3-&H-QR>n}B+aYu zQtp3;wU-`DP93ZQH5=;abQ##-m7av4SGzWwA6JuBI`*7Z7PqWNjK2dK4kgH%Ay{W^ z$Yk@_GI)!#-O`qtm~6&&{3wDY#LRz1Ly*dMH)PGLS8i~yA7=peqXb;kJv9k>H5*==iV)J;LYyQ zmFHLIhVdA6XvcCHOIVNQUYKWn8SMH<{c^O{IPN0}5aea7L2ZYMp4%WTzax^q$3m)I z$~D!i^8~x9Km)?JhnSfV{-LB}qh;lRk#_#)(k$V%p?S=*o{Mx(E0FsiQB=dgpJk&zOAPl8@NA@?ES2HG-ZXN?mthx&sKSd=mIMuhI2K!aRm8 zAS_@n?5(eu_^bwcz=1X#Ta#rS)$a$u=qtf33vCLL@|Qzj?TXMT!dC44dp{Ki*v#A5 znSQ`Vo}wYH2w2DSZ3mE3@+CK1a%uSAWcv>dX{@}ktKhk7bj*9d7}4Z0z~ZyRn{WAM z9s|Utj*}*m>H_g*skk|%Bwtu!X0g&Wgi@S=CXI*c5)f1qjC_ArxX3L;R8jdE+hInl zx|(HoN*V?mMZSamg|SX48t-yN*{h<~gQ{`RRZvX@ofSFeYfh82hw2v^+^cHwY4otm zmcfsgN$%lGzLi{hzh$_7P!1K^7zOACM22^EnlRQ7l5*Jt_7TG`Sxq$!?siz-PjHs+ zy{*zoN__2l&kTyqWS$s&oP%;svii(Q2xaFFD6cTsHK5J=#{_BSVRN+1kqZvoOtVf8 z{@73li>GUK3-_9++s*}mYQRdWP1KE53AE~a-|hY{g9da&3A30ZlwUn!81@U1I|8%i z&)Eb^@$0bH?RM$vn7;%P-HG*QF=~f$f5bB+@Y@q6r_=?a&3@G8yT(e3iz8Ddi!0Tt z`|dqYHS0IjQoChezT))!@x%QR!S&E+Ea#6;m=EpACZBh#dN~{*(%1f2Vh!B}aY@aI zRluVF7L8$N*Up|DHF#)d49gwSzH>%OR$MJ{==P?mf}5C|>o0RH#q(soD}`+v=u~s8 zD;~rnd?!nfF!&VqQ-!A}mUmmvUUdAY+@A_)K$%bW&y6lHH)*;izm-5#0gLRs(d?F; z)7r<`{+nD=*V;^tH?WnD{WO%Ul@qdrTb`J&=iHmCbs86(e-;p1dXOnuu-8sU8#qR3 z&ZCvlDT1m}38hd~l!WVu4X$8puLN^M+S^p*z~4gud#7Xs{QoZ6fP$Z}@=j~URwtcCXJZrrBA-Re|{Kk@+Y#M$aZhh3-8KQ{NXs5cOG ze4)LTfwpN@^KM^1)q?NnVZ$hw9yB5_ozO9$P>LT`!~0cs8A8m@X`qjWJESQAymK})TKqBOc88P$ zed)p)aY$gg992%K+?$7wz`%Rmn7dH!;&&6!MDby@H2+tG9-vVMNpS>U7=e=EWpaYG z-`aj3mD0nPYsPoKpTYnQu9;AA-{0~mCFG${iDYfz(}O!RUwle3XX8SrK0H;8x3eGo z;WC{EnrxzKe9&DHc;77U_gnr@LF}#9!b3m)qXmHJBHl_H0dkCmwybRa-fClSXB$If z?-t;1?~h;PGP~hx$i-}{-VlocKchDzj}4lK$7jUzX?nPt(hOz zSOtmS54#q^z+w#4Dn5B8!$U&)=A}{e*-cwFZ+&H&hUk^AYmdP+iey5DEnONI2V%yQ zE#9n6Q1ns9cOP{D)I-aKNHnv8mUA8=M1Qk(w~HPu~F!G3k_n`PG!XQUN3$GO>$kG!o7v_6*|(Xg8}KK4{(!nW zv`gwC`#2*nVh52Xp0)L@M33uIs+ZP23&VG(+P*z0Urvk`F$4C^F+5{G=mWKh_mycE zPaU;%@yA)z$aK@%fg=h%5-5rcMbs_u-BYPxdfd`--jqJ@Zx2qofH&pwJ@EavT$AB% z^>iF4Z#$ep@>+MKJ}T!9KhMxXcx#FIdrnFq>heUR-d2QO7JFA(=;4E>3kZtq8XS?b z%lOtPl+-0fX22vbmm3|-C?8D-`VltN7S;s!*52A@qn1@B zodL9ziDg1A=t#RYQwF_d;BZ~c`j&hE>LYU<-ONL`!w^%H>U)Ml4)a^?F-+JSOzX?W zy-HY%fbRqe?Ok5Qv1DYA3*o6$8;H6({rH^7Ufzki227%rM$iO7qN?kr2Xw!0upxT! zaR_P09ig@igu{CZQ=Ib$wvT{c%gLVfh5;-yC> zsBtl0c&>Ch%>2pj!@UL0yTAsYjIMtIlR<}*Z`5p-;%8zO04uG$8RKWF`3m_Yq&%=I zKTvMZM|o0zMsex!y)1f?VTWJ4_I`J;@ws_%WzYl2VtLyEYg(nxn?5pM8k3+|kL|T( zcL_=pX2A%z4_y7|nuL5;Q~r|`o9Vl4u9XhHbZhgz*uD3vts z-^}Rn13^auWz`CVuORvWDI-9oSW_AU$}>`ZB~Q@rQMSfZH#pw8{knO1lXY=9PZU6! z53a1239DKK#EjpdnUQpU^VBrQd_q1L@i`{?0Nl-!Z@Eg4-VCXx0)tb!nEwfCD}WlF zDE|5jWA~J=O8x#XA=F*=XLaxCczrw7At=@44R8bh!@#NT7*|I{@30peTtHU&9 zB?DsyVO}Ql{QhC6X}2VHZGGRjov;uOTk#ASq`83SPR}Pn6j!5rRS(gWiFdgnnw~Qm zytUZ!Hs?s>gFvhe71D96u44S7*|6$AtQiAT42Mv=uA}O#7qYcKYnV4O!VWU!f z|GGDJdj9vK(dec_jta0P6KU<&B-E_;a(!PY?bF|*bEuK9-N%l5G$Yj|a7%j=-5E&Y z08WHuVW-THa&YE>XDA&-Ik;4W$X)f&ysIMMcJ;mLZjN=fykSibNjkmMu3N?ZTNsgaqHjOZ} z>vx-^Woy-Sg8}rZTsX*7j(bz*5!ON1O>^tqh@s{ac~Q*0M2QcQAoQ3ihnDdCS_px?aK@rYD> zuZYS?_!f|K?X~&dP*stl)>i@Z19{sF&aTjv-^hG)Zw7c21?Af~xwU=vG=16AlR-eO zyI2`q{W*K31T0Jxnfx1q?EE+K+*h^_ zouOzhpu3+R%3WuCfH))Iip_Amj0H>*P#6Hn)5=bno1la7<~q%i^Rf>7?mfc-=K^pV!oTwf+h;GkR&w5fUAZSWCi zKp*iZvL~9vQC{y$J^(-t<~zcXCR@`iyIh-4K)KcnST63L=o!2uPI1x4Iw!Sl4=qs7 zFXC7jnvj3yvGj6B?GsnaYJe4o{EA^7n2dnmRDLV}JX(N{+jLheCeOn~F*#vkSSHCV zyL9HZ#hb*yJj3|*-(@EZFB+W866PD@%ZlzBZvj) za29cMe-|GseVFYjaEm{7XBqk?-n$IU&tUANU#zqSXOiO`xGl9m*K3>ixpj++AL90` zk3e=wxgG<~!B-+=Dxm%E=QHASWK z*w<^CedOLVA=XsS_^fKaC~lo}iYTR`)2y6xyS#@UyFF(_e~qzN!Lb0I@ag>g>>>Xc zs0&lenyLZ|Ft1GTPmoE_jX>1BCRC9Rnjv|xoZ4#eCsOsV=^V1ZCRPA`TxDF6A;hCz z`=+4*yTG}whdzrp-r+I=2`(vzB^IJy07y;kuHskYDaY3=f3 zd*<(m$kX5kuVtI5z%%-9gaId=y{`Z&6VI;p_T;iM2bIq~xU8dGK9Z;5eCVuioC)nr zpr^(?5h#S}*CF*WZ+7=v;E9}dXz#$jFJ8(tRT|Jeb%#2% z3CJ5rjHb-R@H2SasJ5tV@YsbsK~H-Gp{niSr6~1IL(-(QZ=q>mWYy>Z|Ibi$dU^7qtD^ z+ZC_wt&=!$s1UHX)5?8_+o*FHvZ`73dM58iF4*w%ocJY#ws?w5)#H=tlt>|xf@{JskO`)9;iOy-0}-a(z?kZsX7y9;O`_gw5+k($ZBrj#vTJnHq?`IknhV^M>U>TP`~>kh zZQl<9)W9H`O%;9VBS)%9Xw(f2Aai+2nR)YB0}#BfqS@9RShB9JuBo6Fm;oz=8L(iC zU-ZUusr@GoZ-$n)ah;~Lx@CJMR;D5&OnZ7671=+kkx&0bV*zB0jyPwo{c4`*G_b)5 z-gf~dAbD0w&qwfAMKwDkIS(5NcnH(!*qkqyUJsv)ift0V|e!B(lVyX{rbM*eze|0qC zIjt8!a)=uG)%V|HGqe%W1z%X{b~LE*X47r*JBIkwmbx0;lX;740iZUMMU&)FExVd8 z)UuC9T=>&g6u8azl*j9r8xaaCd+Xct=zroFON^z@peDd}YjLT$ z2bs|X|5d6+3>a>J-1wD;CZTQ!lUc)?m4GulTDRC*WE5~07#>ROm>`kNn1~e0GBx&H z1C7-#sRb~!jOT|wY%ziy4}95cW(>`?UE7_+oQ;9*UbW4R(xtBgoz09oi`j=3wPi~F;BN~ z)8n}DjKg+&epRBGMDvuGfutegSt4;tjA0~FMcxx z+>~`+;>h20^9;Uq-}WU8pVN=v67;&H*Z|MG*2h+)}<9D{_7kO)qgWmm12^dFsvZwZDVrR;qDiNbZLt+2m1HkFtqn3BT zyw~{gBOb96xNv`Jz;q2lAr&4YZ1Sp@5{clCl~d}yyh~K1J6r$HiRhXm4a(>>y##ht zSXdZcOJU4xv;@XE5?`?9MebY~uK`*DIo5pxY1~Ze0pwK@$qg+fxz}4gpT_}A&sY}a ze-ToTe}^}$dFnv}7b;KX?G)>Jr$_|}(13vvRB$Z^FfI*g$-Mw)d0lYz4dku`EQR7u>uTW67y3l8b^^VNgTIWmK ztKKOOt?^JUi$q#k?QKmW>2^DOxaQOLx|I9o+QAxf5{U$*o#c9zW=1I>Wo7^_12@Ep zwZGI5x5My&saAQy{$R`(b)x;l)i=hBL8dbFleZDE^kOr#W~49<*>-j85MZr=+b4lh zWxzvd-%O5Cc~mfmlL~#=Z6~byF!6-Cd4A2Fn)0<2@WL(l5xK z(FS^^w_oi$I7dj`{4@X<##4IF%>R>>=r%tm6W=mVJ!BsUstH0Dg8!YL!0FrJ1Zf}_ z1rQk^LE#}DP}@FfgO>*yuqOg~OoBw#pHTU3jt3G@Q+O~8;Rf4~u6f9-*M z|CS&?bMwCd^?OAjbx9^OG|3yE-GDJcTYUFnGRhWLgow9#(Y$1T(Ml3>os4UyHA?kjF*!doNgt0BB zMB(k-!`~@8gGqV;tc4osyr(L}#r+iF7tCx-MSw~X^XbxBP}z#~d7X0vqu%6e$FGO4 z6(SS$NCcgke2$-T75%~*V0d@d-khl#>YOdLC7B<<<4yo!ky;j`Z0gP-643ahO_KZt zMPEfd5dXEtGdzQ9Aw;L6Ww1{&ql3ZDLx zr))#Hy*^n-S^-5q=9kAQ8?lp%hPI=Ym;BNiUwZgVZ57p+6=YO28wasR5|-sq4~t=@ zCVow1LB)O1%*!3+_myiYjc*u1#h z?gjY!E%WtFju?U%t(Ed$9Vnxs1$3Zl^Y}lU@rfp(fcfldF8D8c&|Uz0$vi{#u$~@L z83Je0$2?++NVeS-aoT(MAMhDr;2AU_wg+dFr%=-TLFAL%Me3OZQB!~ zv_~MHViXj?-^$j`+{!^@$Uedj>Q}Ge2FMM6gn*WXc_y!PHJAnylMR~fT_^#y@o%hP zdIFe&Nu(ubaKl`3HPZKC*bj&6?DC3m{2 zg%x0(iOAoBhuWljfYgNk5}2|;xBi#dUC!UrlS|xzdrA&*f&OJ;@jig(!QL>12JzoL zUww7YHgjdJ$s}m%`Jm#e9Q^nFdt=2Tfu~5yDGTvphQ?v|SvTv^5grPw!mb#ZH?{-VJ}m;Y&_6?`Gm_b>PB#JD46}K6&v(2jqj$>Xl97iegeyx z^??C1fUsn|{9mL&BU)x^enm*5BkTQm8+$h{&zLW?c>Ei9KAlc6_C^@YVy?tKd?PKtWN+pNyfN=*DqqRw_-9N&kkZ0FM%2)Oigaks%u(nHjX#lfm-+qgGHY6FJw+G~#`D@v& zytNuZ6~R^F0Pdm+bAhk=UJSp)>B?iYIqC1QyYToxHpxY}YB0MMtM>Mm6*jAt!o%C! zG@|*REXRG`%!JMrrddFis1`EIy2Z#*-r-FhaA6`dK6dW-g8n9N}W$>ttO=FzFiF|a_VGCZH`oWru8%{VbRex&xn(iVD|?n_F?iP#!U={(eC0E49d935SqVEX30d_=GR%=% z)O;ymyVf>RZOW#Bh;wHlx)%sucH zW!{KWNX4DzAe8lG5hvQQJY_G$IXESB5D8*_qZh&$E64(RSnC{7H!5>CzIY!RcAYV;c|qpE1j= zIC^aDV=0mQU$!H^vT8PmjEUvs(2?#sr0{iUYD-sJs|hHa43HInUyNfb%NAzP0fY< z%cglT_T%@eoCY_<($OlNJASwMTfSuZYFX+*t4HNzC4A5J$W0(l8;3c5I+$c1b}9RNh8IsLE0v|-DHtHcuzLPeW#dr` z@!)o%;sa}`_r10*$ z$K)ZOi_pla2cuyefq1=ZDeHd~;{96%V$<`K4ylWji`7=Cx!IIP-qxflm`cI75K zXzIbb9F?JsP#qgKoCCeZd_pV*e^)hi|1*lrRT+LncCH{C@*?rMW0!hy-Yep}JF}*p zqpQhhB<_EE_LF1Sl5rFo5?U;qx;WS*s`oY?g^O8@YQJ?*%T%f#reE&jY!BU1C?A$M_$Wr zKj2v#bgbaZyc>bI+%It%K0cQagS7FBN4?`X=PdRe4?FlZND%E0Ui{J@QRciOS>_T# zoogm?c19QRv3X+kYdnGYkqtDS8izp3U$T$*cTmB{D}PcQ(LSfedFRFSQNGNfjbdXB z-BJBO&n(oLi)Abt_E7pcin9@C66yi=esgBPdB9_${ zK`;2Jb-Ed+hkMr5=z-89Il{fi#<&NXYo>~=WqF3qS8K6J+awntQkr%4TJ0W^gjOEn zF!D9h38f(~hYdqfcRjZaQ?9d*44keLo}V4?LxVyfx}2stw+~*>1E`_6fa9p4!#wyD zVSMYReZJz8-I9>;I-7x;96)O{KHyjX^K~8mZe2!EAZwjzig%C+xz3sNG|(mN{-^&! zK`GZICBYGlTgO^6r zgN+8qv-iPv`e-m$qM?h$zYE6GhE|O|ll1jK#|X(9T4h+5nVqVLDG@N&X&YVJ<#Sf- zscoBt3`Fi(uEF@*)6RiC4>mJOWx&U{&L2Yj{uf0V&dONpYrj2?GV5|3@V=0HdNbnr zOIEV$B44;u{S;*UWU$s%<)=sRDTR^~8a}@K*MdopaGT$|HEUgtUaotd4ZI`h1>0|9 zd2t--BTX11Q5xtRFy#O|ny?jlyJ#^2~o1@MR{aEo1u7w&fbQ+ue zch0YuwUR|5uSMSIl9w6!a(@0O^-szQk04fhDnB)Fd=OfDfyCIk%+xtudm^jB2s<1< zVIyypEepH(&v7VEo3Uo9mNC@OgOW0mkp#c*eUrCN^ta=An8%-mh0On6aIWPkHdAeqV2X7LHP`$ zJq5EsC*;r?yHE-78~`Z(GcA^aZ;H*lLLEVlnO3O=j%VfpgJ*i^S9yTeniK+hr>$WG1X!IwAKKLkP#B=K8>U=%$BfwT{wH8lc@cj?^wEGXhM~X&m zN`z|Ly`lEsnT%adlm1zj#m{B;vi5?rcg)ZwquDlyWEl#Y6W}XGS#S#D0Y(RgvS_PP zz57l8byn8EK#xS9cP;qyM{1wVEPZh!W^l5q=`W*MFAkll#IK?J7X{_c2lQj}?+AgT zvy-$bJ}42)6UOUUqETM(EBZc7CI=`4vps@7_{h6`??8ok0ccg)E!D#7t<7l@4;Wf8 z(>B?krGJ_y=ksN`@66mOdIH#eV-K$KoLl&{+FR+?k`A9c8y>RPcsnD|E>N+w^RH1~ zc~4F^vqa7eCi$87as$x7H1=)32Dpi2>*=VyFmL|#Lde3xoBZ+jDq_XmuduWSmkhP7 zUTk$)37r-($hcv{PR{~7v3W=6suXS2*X2|4Le8>Hm4#v*IPdToK~c^GxbIb;KMa9x z6u~Md0!M>Ay~)Es(DQwX{Fre&WzHn0w5+l z%f4@ZRr4?)T^2oNwc(9_(&&HK4czX#IW|y-6LVwA5xR}K_<$&5^itr}rY+sqRup%+!4 zFZZ(Y`#7Os*RW5A$G0EHpFt8S)XE~)#7G!}Z~K(nvo7V=IG(tU>O9e*RY`AnoL!dD zYDF?(KWd=p?rAG_bRCdFVI7KRSx@%*nf{wWee~SU9lI(Br$WZ{=>DysVvVG63-s^x zVbT3v^FW{HGz_k+glMPBok;;1OoqO0Tav?&2EXdJYYL_Re;qiz$GEMLMa5AwYK}>c zwuMA#pIxKmAA?}k$*MW^(GlEqrdFN1L$by;%`do6w~9$1N>3rQckcC|`xQsL8Hbrq zv4&8zJ)47VoQ@sEDa>D1Z`ed;<7ctwwohG1l*CNFJ1=uw-b_iOEN}dI2t<8Sl#d2J zWpJ$k0UQP>2EW~M!aG9TR zLG72Q@&jN`d`;5oJCx1m>Gk&?@75XwP<0UnD=`7Hp75_bPTq1!Af2B0AZN)n%S+@_a+BAI?23? zfcPGtt(<*`Sh~Q3Zg{e@_?SK)hrf*9aOnrDuN9yWmIZ+Qjsc7_ILCs}D-Mg7e3y{h zs*8XKecap!_5|)8FfYL})IzyZB?V}YC(+;Pg3bWU?;pGlw7_WVi3-{ca>_y$+DvpW;qVe(H zZDfHa(`|FBM~M)P=Z^Wm%ArL$)})y6`Dm0yrw?{}A6G*9u~ZPkySS=qMBn-`G2&u- z-sQ(^05IX8W_H>Mq$cM3Q0s9py(kWq_CLJaKGcY=zHD>UbavVksr7{+b4bmx0fH~nVI?I=xeejtHu(9_)x6H;p2+uj_gD7eRmdm zI;Kwy#*9h${&lvItO4&TthH?B%?i~yn~?)_nm9&Ba?WpDqgIfeL(_50xe0j@mY-2) zt1J8Aq|Bqzq+FFRE&`tw7Ja-Y(%u3FYn_|{j+3o^!~Z<`-^SuUY4&AcoeZQn>J#{? zmsr1QC7maw6YAF0jGsExla0xv2umI98MgnFv${9GH@QG^sK7uuBu)L-HdTFGf(Pw6sR^_Rl`w z)-@f9_aKW{fZE$13+`Snv`LQQCUSbM^jcVMMA0m8V|5#fE!xE`@x5riDP(&ikfK}v zKrfp8j{xA7Aq_RD>kQ`tnqY-TxOBRrX`jadaMg;jaIo=35CUGaUD5$X1Z`uw$=#$* z>y}5NSp+t56~i*>W0@8HyiE-OWT-g`^1~>#a$a6&9eb^R2)g5UCk6TTt{$9OYI3a+ z_l+63*c!~sm3NMzgynIErf<7fp?Z`DBk~(S06Osxb}PAKpOZybA(~AZIt%6wURzJi z`NTm9@-s|Lg|4TJZsSu37(83^$f8~5{ z&0`T|OJ zped)BPAkvQPn^RBRkDh2HOR4< zIc&%$@ZOW|njbRTs8m44ara#0>o_1ci` zBw}X^?F?5v-Kdtc)#`*6GItaFf@Bib`bYjlD*|RO;aN2Q3kWJ-DlU}BmUjR{WV3(z zTx`LXBn2Z4!|m+ex>)CrtH;Vm6-lmluqidI=)2=RHTd$AItU-4$ELOzX+pIwmefcEm-23=pGsD)Dz_8DYwdMk!6hsHGV6x@7xg-*5J1d zaq~)0Cf(IjV3AJnKwZ8G=ILbfoXQXB1XLgyI+PIxLuM_$W$TQf1-H+hRz<#3)6)zy zdjNwyjJ(sfn0^9xQj=L~0f;(0Bms+r9B~zE&^eV+ey-4~zQhW>eKq)$mtd;^M)KyZ zETb*qz|qxcjQie#bcV3AP}#fgkZZ8Wk^`l!kSZ{N!2YpqGAWrf_OQgxl+<@NU_}4r z%(f`OqBBXjbz}qIaCt<`u$9`rVOW8mN4PD22GGZyPbY{+9?30MFy+%P+|JYe;XizU zdSJ2!Oq)I}81$E$HQ$^TzD)+`6fxv~m|=eYV}JBDo-xW?>fDuwE>=ER1*QXHmtixd zjj)F^`D-^HZq?Qd8p{3l55>6F*G;s;EBEd)`*|8~wflG4rQSRTH9Nk_L5vsuv?4G zm`sJOyxZgVZ??*;2ovvUff|U-l|2nZ0jZ)CE7lGAqn7%rM@PDJ`2feR;`ZCO|Mw1# zOdE%l85e5h1BsACv(hRm0MT7e!`FY2`Sadj(^9x{);U#Vsj1D4C7RQ;gyFBHZJ_?F zy#s-jDIt8O&tmDmF(|KTCIX>E!a^O2X|~!#3i4%O>Li6qWRCO!Yp(9f5$8=Xj`onz ztlKCNuojfI3Bnd&+fXNJH*HyWWNd3f zH^bq{nMvRy3GN0DJFTA-@GZpCZadFcK^U#a(dX-Lq||y#h``on23LbHCFY@=m6K#@LMuGs#wOW0H0kyfg}*Db8^i{gHob%xIBmUrbHnLekWXcIS!S+#*%joXoVr_r?BKW7@Ffrd#*BOMVV8%L17fL}}Nl zd;o}6sxE{4LfNi!yyaCX4ZCwN%vDMZ^AOeC)?{$125%4-;Iq@O91^qg;CGqfh6JX7 zGSN#)<9)ixVuZv?@@U2%4qC3BR1IYR+flRd-h+}+9^jb;&=TPQX{dY=SQVKCl;tTB z{Q?lt8~w(8b@ro5Ty`;+7K?RSi+9T=gO$IVjSb9P4}x}e9#_W?=?_0OhgVHblf8o1 z^RsNmo3S9CRw|R>z|{==TeN@|!DznnER$^626SbBV$y99v&8~d_ZU`Ebb&=pXIlt> zAjDy>GGd^2h=82(=>`Gyi7T5Zm)W@Q-~%}FE5I9y_{O6=?ks~D{-KEKfbqJ-9+c-5 zOr|2RAuf^k zd(7N{tu>}_Lm~d=mwW&`f(`1gc~#wtJ~!!EXuD)O2G{<>Ca2$?L1g8L=UDG>XK;&R z=ep#1L>HT9ErW(&jK*i9S2l0Mccx|iG#$scMiG4o#B@KWZR$NaaePE(Qgy58H>^6f z_%nbEWShvW5ff*ei^byS6i|}{35-AD`=aazPXaM|Sn`D@tnEsW$N0wqwJ(U_)gOip z7(v&FYw`sG%Mp}0pqBC%gDSV6TTtijLm7$!z_114OBIsm&lXlje^zOcZrb;4rlvXW zV9uou;9=J0r$&^ho1OSeNRMg!RK^A6i&-U=p*NF-2e{!+a>Deu;PE&NI|9RuXKzhl zLFbXV^PR1p)S3A||5=XQW&yqrzn6tDnwG!-LWqDnBwhL$5AsAJTwNp5Hpz&$np-&( zYI_GTDP7u;F6~<PE!F8`Xo0M;? z2;B(3lD=ombmh&&p!qD_b>)}jn((k>Ieu$bIXvsAo zYH9$T2;{NKL1+8r{&zPN-N5GdqjTKZ`Cy0L7x`ahd4?mO&vT>1ALGKG%ctyYCtzVD zjSP_0HMCyXnf>=wLY`M)mL38UmvPFu6}!&{ebyj0eN39#b4{A0`|Qe}CY>vrwKta? zJL-tOMMYkHnIhn&AGcd?v!7@lm1~M5a=++`Y%=^ool0{&>5bmZ`F`+t5Qh&t3HOIv z8`rtUKu=R5iHV7sKwWjDnd((EE`8u9*+i=6_|>v~hw>#8lYNpR*wuFE3b>*U{BaEG z3iy;MK80GmxP03b5O;h@cK#clkfDv#v(n$MmF_?B`JeiTGY9Z=lc{5+eLX38YyK4q z@EC!~m374)N(ghwR_b#vI7z?E8w~?6U@EKT>y`n5Xw>lcG$wk3q zTy<4Tg~p%%oFpWt><)^@F%-_?yS0iZCL$cUfoI;9Q`gQ#zJM{>n6#5fb*q`4s;z|5 zQBfI?t=thUqNR&7ZKW#WcRK^di0TjmT#l{(8qw(8ThqoJS~3a|SP#k3=<o6`jtMzP7VzAd&~>9?&*_Vj;{5D0wiP zlE*1&=}Gn~T{KykYg_~)v{iIH{J8@DN+J0mtk?QzaIy}ds{M`8E^P1~*x<_s!#vS$ zhH;@S4?Ag`b&^O~hhbpgG%0P0!`RTw7gytKh0Ekuw&c`LRYc!UK8QjaTh>>dSoSgndA+>qIT!b9j*PV&c~%I z?7A!hWv8dL3Z!P1^w+o5VmFRq0R9^GEMYq+YId6&Y|0v7@)W^WbrC<6dsI3kf!PBa z(790pQgZiS`gK?rmUgkyP#aj|sf+6lOz(j39Gk zJ`f%{pQ&Rk5q@q`B^qI*)cy^vJghUYTy44D^lOG%L7S~F>${w%BGF6fXMZg(@BAD~}N(e}> zB;I1ndHHeyRjuKOY)gDH!F|EOw5b*=tAw~OefFI`d%Br=JEwOuiuhpDa0#u1XzCEN z%}_8RJPO$p{7NH`M~5A}-GpABn+3cVdY#8^#V>!3#v~J?t2IlM_j4@^eb=*k#lQ9S zEB=O4rEl4KnWMG+>+aw#YOI^cZ7o24R}KyKP&-pMgWr76B*y zn!$FhuBu9A?a?bc{Q1)-!M<`Ri#odv^)gY?lUbxKHjUvB@kF2>0Ax^J4&}NyEU@8v zr(y^u+h1M|swhUJVpQ1@=D2p#vBM3+(fD-QJ(Ck;QwOc{^!c|hUcc^(d6UstxbLf* z^S=6bBH(9wK|(Uip)9M6xIG~D*jk>x;?5gG9Vja3Mx@!#r;p|yC-QR5b+E~urn-aj zrolYuHEI5@yY=)*WlsKh?dQ)A-WPOEzhp?usxRh=|X!e zDz>e?2{|6Un>kc8Q2br;X6O9uE8=k3nV)4LzV$^7a_2v$!;~=*3yZ#Orq}C`LE6^6 z2PvkOaP>Pc&E@4LlC({&8utX+$DoF61atE5Ve!Jti3M+^83!m**Q!~T8F8C*1p#2= zlkU&gN!Qcoa|9G#R)?(9EPj-G1=u6*kFIPCA9<+ej;V zX(f;93rvkjs|?IahY+FfNY+j7*hSo!48%`U(uVkW0%kwK*6;B8i1nnMKn^?6J-?jVUk#Ma;q%UD}fqgEYX zX}$B4Yrj7Aw)Y~w$f5i0k(Fa`p=QU6Uf8)F$NKaKQR9OZFEUer9CKV?V{u)SoMod` z<1+vsv*N~#6E1~VL$pI6qq!GRv4S6x-V|K?bjq1L{oZ27mz;JJ$tAN?-3x=C^l92` zk)W==pl-_;R3Zw2-I+B|C>>Zdnv!rNSgNKcfwJesF>3eXZZaNwA-@S8kp-~|9`!5NZmT`2x&lXl zA@D;AASCqG3__xn&0?i9AN0-9VxvsCQrPDObneaJeA=XcHQcH;7zcZtJku&0YGoPO z(@XZF0Gp(aZG5Dl=Abw8oX1bhQO;G}tMe4!zVP9c!iMgf&j~ZOaP_|YEU5u}@z`Fw z;`1%ZC4T3Y(EgHTCETZV2iV zt7^c<(kd*vKR*k76;K@5r>!paBTz_P8gz~*-$#FVtKKv8iutI)O^17x*`I6AE^#%A zfaNeNnS1@t&%u|&%T(Q&1wk5f_t&21ftnsJ+$^_nI1C@HWEU{FvA@-Bqc4Ap$L56t zz9-BxUuZQ>_qL4Hx4sO(crXSrD3@Q(lK~a6s{!5RT#Bg5V*Y4MTIq{R>;bhF>{ZJj zlS$&0l_BY6;1u_*PrL{(Z=8N`GkU<65QRV{(^eY13{X<7~`5o&M3G zhF>7HDo995&*^hOeMh{!(NJrdsB!sVxh782?OXQa*q+pYafm47`ds1HfJ+djob=6S>>HRxp?5LVbfK--q zzGN`7luLmjq&bEJSPGl%*8I4~-<{bt&rqFgv;a3iFd^Y9Jcz(g5wvsZ4A{#{(-zfT z6*Tbb`Uuz4$lqa`B|6VtPJLE*Rs3-B(+FgoBJZA6ocp4tt)QllZZt zW=o0d>HQcSBHz<6dyXBF6_YhtQ=K4@96A5`Ipn&po^pZD41DJg_*YtOJ%Zt=gcu<) zbLS)acGKM%OJ?D~Q#>m~Tc-=@Z*~Fa4puWd)zBnvTGqWraZz1FU)3VezqUb=HdN&# zDU1HT^GgoA?&>Dky=0>~JhEj})dd&Z;lS7kc_D-vx?Po+k&A6XAA|?d1DIE!fy+yV zx#aWl*m7)j-Y>l^U3T}Ss2~I{_griF*cgaFK$fO~*^DD85ZVqdsbBe*CC{+Q2Q&~C z1v@J8Y1fibznt-=HHm5-SvdRE0X=3;q%`{s4#MhMw2LqJ&rCy4_6Yhw@VV?JGPD*pai^ar5uYlS*_A|!r)ua~v z^+Kgir*hSUfsjFHwC^?Mn;|5V3TA<}CA#|Y<=!*25=LoUiw=g#Ao+VPVZrQ84BOMF z7Kr~l>)A|JwK4lh%~Z%X78$CM!bWvtrjQ+DLmw^Kq0I0`mKa{;EYMjmXTcV^e>j{s zMXlmOED?6@ut`a)KOYy@%HYA#E(68JhyCrw^N)>RwcR*o&WeL-4ILP($&Mv{9HbY` zLCZ^S@z&gJV-A{#crKUd16qESm82(!nSws-`?Tl>jE(v2ND<6U_@`)Vv?1Uhb$nM# zUL3sZihzl>NQMrO`gt8ZBSOQ`><3UY4RnSjSTuY1bor zcGNOg1C%jX$`f$}*Aq9jNy;m29H9=yAYksWhdx{*^lw`0pZ;Y4*b-|M$qMK~{m_p$ zcvSq|esMoSmS}sL_axKr#{8@y8TxckYH>?fJ@ZXGt+vXpars&Pm*3kvEMrPr={3{E zuV26R<)2pwFj_2oaZ6n?l4hZqJ{$snB)=?VohbXZ zyBZ>M3@%bw4Y(FXj4ten`Cpg*=r71n1 z@Uu54zXD;Z*L6S(z`Mp>d33%nTd}*n6;6lUkCB{9`9W2}al^DG4y5s-u_U^}6=;@f zizj({G{sC}{wKHvWGZN7W*vfodV-HPO1$BVuU>X%SLOop)I zamRWLWc^wQJ`cymX3)g<&&j zP9!$Td0p8)ma;8JA`)q>^Q{K#dsrT3v}mCo?)>A7yrF|tk2rxv1T*v@Pjr?~{5W1t zig+_=&tWT93DE#XU#0)>oLUo%L0+7#ZSTJz1{oproj7z7vR zVm>7W8$Wu6{cYpMRtt{^dU$EGawRtvmro_aoJDl@1<81DdT)rOb?Qopm=NB8hxb<+ zGdr=htyq?hd)o}9J}by(42maDP~P8p8MnxBUw}mD=jVOe6)k{#SPWfx=x7WkJ0+nf z5p@hd-@G+dA~deug8dvD6j561KHdhXK;A5FUhQgO3uVoS)&PC5HQwn9=pTvh5&5Ep zFTN*h4^WUNS%5_P!A`6lPN6Ouln@xW$f>|9?Ox^vZX};MK zhQ=!BDeV8e7j2hS@W}91@xDf%ot<;iN^E)OBk5?U$q;5+y^+hII`8ETJ1J7YkF!1 zucw>0_rS0MtI0UE^orynlzeW$1un5Ip#*80IJ6Z|gn-Myf#m9Rt zX85y9BF}<;AZ2~y%Fy6-H@a@d8z2~eWDMsHBLzf@xvm_`f9bVXTbQKQ;VT{b_lCn7-#$7enGhj*=93N4dpgWGs%YwQr7b#Qfh3wQ&zs)PeDX z{weq9e88zS`U5YmzU8}&3TNx0JEXVWfRF8GwE@Na^3)Z^juCPanreJ_Ugaq?kjImn zMVjAMabSd}?|pL~$eh>ngvw#vVmn{o{PH$@Aqe=%NdCP4B>hKQsUB+k=;%2Lb+>C1 z<0xn(ZN8kn%T!KEqXo1Kv%}WJ)?t%X7DegqpAP1K^4)#-8Zn!2EI%tgqbZkmeZ`sU<@orC<5c4XPV!8YFC$0| z<*pkXS~Bx}2OMk9OaG=Vb2q+2x)OH!+ftsYJ3Hi%s#}X!42or;N zWg3BPdn;-xhswcTpPX7o0BW%+MZThK`KJL2CDh7NYnR&8YEHZKQe z5<54iPs(s(9MC2%4*4}LmR=Jz{Pj3}GM&MKrTzfM_jZ!5v`}ZKr5-?y2M@NrcyRBn z{8~YNNYPp1*`!?p{W{wT5)o{jEFbTUz6u*&`R*5l!g9^x^_ z9dL5*`|^MgffS`)CFpA(cY-l{-Mm^vN~VVl_1H~w5!HN{h)h2!!(1a6UUx#g=achN z@vOoXg){e`=@`X{s{3q!uGH|SC!{0?3c13S7cL^kjVh0~n)X0nC?QgjG$QQ|6?Bl#H8L(Tcz*K$1JT>wx#@5OV|p#|Q1+D5{X6L|%#;IXU$Ad3N#<^Y z*)-HF;rm5^6;D5#8y4hMR4zD5S%j0Zrjh`mtxd}X)^0qt?xQ&seoI6+W!zk9+lMJx`{Kk;gDcK6a;6$1ZMHN~ z7`V`IQ*?CsG%HU8BdhMVzx+BX7Mhc&4@9qvdECDkg>HOGNlscMPQTjm!gk?y(uXC&$ zc^~sE2n^6vi6uj~8Eb&n6mKV1Y~(A!Y-TBpI*`i;lwI8Q>Z6{KSRVD42S$Z)c#X>1 zefW4_yXv}RT*-ZuJ$%OrQA*%9auUga*BU_h-u@;%maPRm{$?V8I%!_N&>QFVj3U3! zPsRQ5=#2@Ah&TMOFN6hPBEThm@M*sn56fhHuiFm)81&Cm2d6hXkhX54LqBrdN{026 zO6C9Lod>YSrVO3)l5lBzc9Jbo`}TGRZ5CK950`%#W8Lh$E`J5HYswg8Z)7J_;$i^rhOlj;d_vfzhQer&}qT&~M&9tG76y+VtI;g2&D9p`dc7Ah}=5a2am zY8&Oj*<^KF{d$LXEyR6-hMPbesJs=~H$r|Dyzms=od)>&8y4?4*`1%Q{^`Dm zcSpK+D>F8PFq&J022WhO4!x@$q!SjfP7k?*+>*ZxyanIYyDR=ThucAw0X}5v|46P6 z6NAzvl@&^!vPGpV0Oo(sM7lijz$Bo?^Ud(A=3q2BE!?8lZohrv%{OBmxhHV;7|0IK zH=tK2zl~A`=?fYJH6NoaCJAY;W=HBJttNGX+>30{4s6rLFwgHSyv*I%xJ`KzASs#( zIIN)f9D6X1d@N7uMB&3q@0Svb&yC*ZCF$8)-FN%~3kJeY#*G|lQsI-6?`kDzg1 zXaRkH;~`snN{?4%vBGxBHK-Cb&Gp|D_tPnx7kNHAJs>%1yEyQy&LPah-x|d%T`DmB zECVEDotTya><~-{bQN&D*9xRA04S_(81Oa{w2b`ju!dq_53x1kwR)&NxoZC#H*Va$ z`|CAj`%iDU`SwEfi&yUj8VIwfH@N0v;}5`{h*3l~s$isW$kom*nl1bwCRj)c$TaFd zG9hk!m$m^hjMsD+&0;pbxmf%&@OiW-MMO8YU1Xt35BlNXFfG*8Z)SV}Sc(vXvPAg~ z9G?ofz&;>~@LLx0Z@c*Y<5#!w2TkI}hgs&@P8<~Z@z%b`k?hp4h#xLECkXa<1I~NEcg=lj_{S97V2v_vcV&=G;>GP122K&hR}e?p=aKbUErMUIAAmcu2^4LC z-os3v?S&n_13>J^vC)M_J0xfHM~^*&;(T^S14w0ND2{Z@K|}P%c(l=mbF*&8;x7P? ze4LzyD_bTtsK#3Ui%43^ZKoGVrJA{4F@=2o3Zzw--ML@aNl#cqI++Tqx74=2UXGAA zKy5sd&y0I)pzuyLRAP=uBWtG7gt9P=HdkI;O-#?+2JnTQPq;alMNvr*;!ofpZM|1$ z{%J+^!H+<~Il&0~B$@2djQVcw69xbaH?+63hsC2P7I< z2d&A-Bh^nwf4sUFsYhDDTOek^;iwu7Eb~G8qiQ`22c!Han~tX@2@)U z`vLI$KOt|RfGQF|&)e5Emjt646b76-EdanfXRjw92tB|_9Q@toE-skamB^cL|EP^B z(GyioWnZ0Md)wK{kjAfFD-*V|O=IM#1TK3VjqV=GsVS1lJn$^2kuZb6q)bl%fn;E< zw^uLs@K<)BSAfSX%rSNa8dv-ELq5aODv?6)MucSQUyNq=^P`M)TCn{&W^fQsW5k<( z@C^=B$I*>gFx#}zw?oSsEu-?PHx$^8)RAaKIQqjX9jLp*cwPx|Lir9iKKmmPn*F2E zz$ffjA~J~QIU0$R{%}42;<)wy3!R0K6Y9t=_ygLzX7)n_z}-(6M$fYKr-swWc{3Ii4_Vv!29oa566;?&1^hb3y2cQ5@5u_ z(;IdhF)P_6DefYwVKmw|@Y32fw+F9s*Op%(V8Ob7 zZTQI5*P2NHRRyfVOQ0N4Zr=JrIE7!cdj~!dPs}y)WTi&`;lxnOuzl}xlmEqMG0Se>LC%Awm?msaW6)9C5XUjViUr?$)d^WEV;H-G><-Z|n3*F98n z&Y#Sr!~1MF7V75YA;q#M z8s<4*by}#g_m$7Z|9makw`zf2vkO&dYIZ)cXZerY7lt(G+#mQipz#20Q5knZ=#v}= zION-%gR?J(vyHsuBK2R9@WESy5iUi!B`MI-J2YTmH{7C-vTp{mTNs~`kG*DG6U8B5 z0FO)l$ea+nJm`V~8p=Cj0S*%{8D>!}n|=}Xf?+d2U)Cq2uHJ>BA>FfhhCQqPac&M4 z)0LgDOxjI7o@pomkcy!2h3IGNQjYr-P0EAoj?O+l_2IM_KBe}>EkV58dm!@3V>T={ z_F{jZvtc(davOF|nO)yXFke#RfZq`X+=B-t<`Q=I&KH4z)4qWqci9L$Agxyh!XY0p zmrGvv30-$+FNB12%hW^_sqK1i(Ezz?ZfU@|nf2ln2wl3|0Ua7clKVV*44f(7Tp=y()jNg*D#4;qITaMSG(+Qu>D!u>k}fO23>UP=a8T zD?xeWUZ6D9mkh;q2B<14I-JL}OvLu)NU@m+&y%=`^ptgZa@M6ax{f$LC0AhDbJ{Ee za3m+sj^2@wAVc-}IH{*1hP!HedP)D<)!*aQbb~{(P3^^# z-n^0hoO)`0a~jAYbXrVn`DZN4JmAtA7nX{AE_njk_a%ola=lCd7F? zdu!ynlr@LU4h^dMmXMq=61@!=z8fG~fzAC+cw&h@;a((5Kkul9Mq8KUW)}RaZQUCRh5Uu5hx;8z&`+}(Hv|4uMPfNp@uop0U4s%CH;;5Bp_;FP68QT z)^_Xbfio>28&s^XmgcA65JYM#q68PXUy2NGS^GcnLT{l)5A_wB{I}%TIIHP2T)0Q7 zCHLu3CB#+w!&iXw+oC>SCUHA3cG2HhkcEJ=0xUWVyXVbr|T^2Nn$Nj$0g~LonU3fP*6b-`lDCC7CputgszZ) z?B-gj<*(1W1fT?3cfrSlG;uMYf!`CshH zwPcx^Yt5O>EGC`+4$F-s+)ACz`2*qq%KiQKz}5cnXK5S||4(#*9>u4i9*6Lt|GE#C zc6X3TpwQ=Ko+UHjPY!L&2MVnYA_0Q*BH#e&1ybMTGaLV&vT#Q7&_j6Lb(F8)n>T%b z;Tr4Y2U45z?hsnwCjUD)8||;*Zooe zIt2DYxb^-aSr;MW@9HFBJZi|p|M>WOz~NRg{yOv6@eX#yR#1Z8vBkd_d%X>yyF$!# zHeC24jKh%o>rYvL49*YFqy3MjZh0+}?!e1J{*Y_8*33^vsiPY|?3+AvFS+cFEBa)< zz$Is^T;KrF^TJsTHl8_F)vVX_ze&Q2QrEXrKHeIvCY_=abX)RgMhCQ=Q*Keg`Ri5{ zdZ1pY6#Wz*h+V0gW`#Y!VIeka5s)U%b+L2!Jk52 zPbugqHBDNEpg$Oj<^8Nxo|*OTqDa#o7mNKr#{N7W>NV~I#+A}Wl!U@0B2-A(nTnEx zHc81^RQ4tN%(RjvQzXhVsZgO&_AF!HnUH-M`_33+%nW1Zxn_pWIrn}4e$VsI>5t=u z@x8v+_5QrK>(>GpS)&3{ccQeo-rPU()=wgL2!Pgd8!aBEd~w~5Kh3FV-LzgYt!*LW zH1y9YgJNU4Df*FZ=?D0_7ht^8N-J;4t|fMms2(|2S2j9yf~f6bc{?I;#x%adD5>GH zjmw9{jf*T;d+xsEFQRlm~}Ygw4x02%i66Y1S!a0cm_k!{Rgc8teok1=0N$YrKNBciKPWzXIGulY!t3!c(~ z*}_;bN^Z92Ml7C?vYmaPHuIrvnfBmYGMJ6oc7?D*{6(sUJx$L>E$?}sHuO`Oum3H5 zJ3DfL$X`XA#yz#v4%SWq)82FYdF3BhCBg{?Q)r8`%pcjFEbfJfN+LMZV!r9WNT{|5 zB-p1@48I_F;bbEz@H3(QV@_Z)>UoJmv*)rb-0y&RHm$aPWHHCyxKv(Kd1MW2cDL+s zw2H6{n33k8ikL>;`XMTH$OnGwI+Usk*|J}uK}@v8BA<5AExs`1t)irdk3fo!Rl>YR zY31FaL}<55M&P50z-393kT!!d`9vW^TACOIk`ui-HOFUya@#F_WH?~q_N@-H~=jvnO~FUy61^imxAY9x!bH;F%SZ}4VgU<$M4>D-mfNBp72VN(@o>(f)DHf{m5>Jnls25oqM3Vcj`R!wq-^R?` z8!~M9&m@>yLwGv)LKbU3l+tRYhDU>7BdN2md}oZ81Do8COilr^*Hntp$@~TZV;9r` z|2*Ope56vxCd(yLBVD}W+Ch>_cDY#@KB`RsUAA=LJEd*HqXo>u-eohcZ);GI&>wC5 zH98{%wZ0~8Hbdv8(P#>`UrrJplKE1FHrUi^#nI9!P{Za1+Q{Z zeGb+b;cWDVU19;{B;V~2&s2Lg@Inb?1oA1n#VDl%LZPEI{|svY<_fkP47P8HMPv2m zPy5|WU>y@RX2)Gxz%YH}nv=s;u12-dl#a(N9#a}UBt3*Yi-j=R0w%kVVoT%x)AKcY zDb1uPL<)e!MBiI3_Z4-qj)0MR_*QlV(U_-qT1eT=|ALvH+n1&G_y3Ewe1kVRRekbV z0Q1OXe5M^scsZux+6En4z1M47gP&`ZKxEL;T9*U z;JAa)tk6S{r^7A46IB0wyhm>OCm=D9p3D0B!JpXU?KA$_AEFyM27CpC(nDIWPZd|c znvOis0Pw-V>v86EVrx*R@IAm;UXO~r;1Bu%FWmnG!^orV! zDm+YnAq>8mV;?!DD>TUBY-CoXW=X1#43jwyUvlWy5}B>Orv4l}U*m==qHE;sfXT4f z^OVu-3VY5=u(bz#xcx}AAF(UDa-uM}nXP?1ab2qNEr^Ko) zb%MD&neWejJkjY)I|U}PdIdUgn|5LT)N6LQNd7WCbS5a*6bc6;+GyoT_b&@}Exv2B z#fotC)?-3Ch-0+QrqaZ9flyziKKG^m6aAc)npq zILi_Rd={_SJXJ>CFG)UNaw3f(%a&L9mYJo#e@Vy7G*ft0zwyC2#Tw~}XEacN`2sOX zjJx^=p!si1oC@>(MdAmqP|)mQQM2}eq4#e{?9(cTeOfVEALWs&{LJ*etWoX;LvC>W|60b7s{$gL?R2;idjwa(5Oq~J@3qi>y%hi2`p zaM4(aUA?(|*3;mrFC4=Z6^LM}yKtVprCNs=3?`ONgeWTK_5p#Tg?VaSZ;;-%YApr~ zr%(Al;>jxvswEw}VQKSMsjFLObrDpG_m8E68Yc(sjTa0iToEPv94jCS4`T|;?Z=UQ zctkOd5z6<`c6oeRjdS7~fcoq`wsucbxn@l~hlA8jof2%sL(Zoy1ICvU-Jh#Gt)2GS z4u_|XFKMI6o93trNJ-;E2s3}tO00!nep=fzhnehY=;Q2&=z7KFX*PER-PXgm--cW9Y*LvF8?4-o?i+1_yjvS#?gpIl_YT zJyyg@7$%1pF-t`_yx~ZJKXJE3WxvuZe}T>_82X?oqyooQ9G~H8zvpRcp7`>T+qodE z89ov0%qPlZeUL5phIywei9u9wzUN&reI~u+a$5F{iz&@!p)o-2Vfu&y9x6b-cTaAb zsKrg(0<`B@JfWQ8SfL#igq>c=&9VG|J$L3svCvk?6|ky3QR5D;T{mj~7}E0UuMv!GzS{^4HunyA^oF{}{}# zpbs*~Hu0*x$fY0BQ<9NvAL&WT?^h6HG)J9c@usIqT|B5* z^r=zrBe1W1zw@-84sEONmW#&aPOvzvIfy~~5RW5^K*{lzR5L}re9y*kQv|BD*h+J8 zsgo%tkZ(oXmP~nB(enxw9J$HW!zA11$*2|mp<&otmxFSSU57<$2HiB45&o#DT2Ltq zrZ>EO4Ad%JVu&}UGV6NE)?uee5;aC!fAu*ZY|YWZ9LrwY*D98W8*Wv!*qrr(AlD-O zw5bw{3Md*_=^oyjqN5gT%x8v^7!TV&&1v-|-$T0!4R_X_%H}9(#_5Dv=4m6H4ChR& z=xtUiOb_&5x*)HQ1(4piT8Iq37HV>v49nICVSEw7NILiE65Vq>pNTp2etIRvfRE57 z1)w8(cflkkrDX|uVyUk`S@938pm5eO4`}61>bWo4S8yR<71Pgg+G) z>k#yNoIm?;57fUo3F$*y@a8)CAd>&hWGFbe zcZ*QyTsh{!qqf%qP_f)>gEOGzr81Hzu z@6EB__QR(CS&qN-_kKB%S)?jk5)?@DDcp1^{GGnqMRQAVtsZQnJ6=z9UZavMF%AXI zs%#p2J$MoNk9d3_%>{u(U1Sk@RilqPBmx@AZS2UgKIn&oJma8gSr(YGMDrR96rJb5Pl2k4PU4d%` zJ=G_A5a}f@$$0T9gd>PLYIj*w8i2!vi}$u$0g$a;d_93FQZ4&*Jo;*$mmcAjB3y$i zpj!LcjV8vA?hNU(E`1bwYnk zKtZX$YG)j6=9W6IYHc>QaW3A>I(SjTCgAn`ZaRoOxJJLs--Fnu74|7&2w8&muO@hAu-etP9K5%4qi>hYzq?b5eJ4<((r?X#H(ax`ql z{h$3#`qNLEhGV}RNEg(Nubl5N=DgO}9OypZtH6(s2HPI*Hz}iGA*iPJTxSgK!q|c@ z`gzLaKh)T8i_-dJ$b>Q0xRcLfF68eo=jz;nyR(^6GT-xaWNp2D7SWH((KSlco?hX_ zskMIHr4eVQ{u+A9nPg7&t_gF>v4hd!7-`XO|233r7=+`mruY-Y$&}IQH7Oe8)0WVC zGc#!(Ad$wgqJJ2wvQs(~ad9PQ2vn^}6owSpzbep1&Wiq(yEbc=!?Rr0))pHlaxdLI zNXDO*O0ZIk;l~XN)~Q5W5JHO>pw3Du02~&eO@R+%cG2Nsh(do3kdyz~XWVmlU)J>( zsAtq(5Uix=PaJVLsflo}w~Z(~FWzqg7T>4lqhEaLZa=gKsuEK3R?@*!Dxa zz8WrQEe_jb3)3q`M790tCa<-HNzAy`hQF%zV58c$)-&iQMagLy;VA>gytHrj_O@8z zIYOvb{gCTVNzUxNFX}YmSfCVizYiAh!AG_AgmWZQI=i^Em z1v)kBXHMWvwl3Cwv7+oOSlYf=`^Sd5rHbO~QGQ2VCglR;nqgd1QMJ7HF%s6IO?p6#%Srsst0Kfsa5>O*+kmNZcz@^JfcT4G$mr zek@q(Xfg4~Hul_k4EId#;aQ*Ek^CSXC(yU)sPvoiLIk+9%@L;qr30Db57-#ne-$G* ztwI)=`T&p)CF33mR#6hQ(XviS&K74Av?ssCzhNG5G9!80zfV?!^2X7EO|_7^;H0A% z=zM6aCJqS}mY)WxC}cP6f-FUyDa1Ivx1$uA9e&_x+$O1uwUrOYeYpHCNmBcj=I6L- zKXpNA%tq-Hqw3m+5BQm|s7uL3kdY#w?V>HPqq*$%=z_XzeAN5`${_L`iCY4ZWOKXh zrhCo6Y)NU6&jBx@tinx`_^agiZ?l- z|5RY#*NyEdi7!WN`h+X1x|{t`{gd;LZ`l6$Go$BRdEa55(UD85=eIViiuRQ4OFd(% z>AjqWuhx6&|42xao@Y8T7<^X2rjK{^n;2C3jZSeu527ojVkvQX<#ms(i>5vI-V#+t z$|3Fj^9S~&V9KuAm^C=0RsSllWRaFp7Efwq;uNk54F_FLRxMiM@7Z@IS=*y=_T&gM zoibbac1o>Ve>CmRlE>`DFkG%Bd>Q29j$MB1#gGI|Qw;a1Mqs1OtuxX`AGBnPCIAvP z_V^h*4VJ0>aw4`!v*FXW>pu78dS8(D4G?ypQnPD1ENuix1u2@CA2CHl_JE%A-O2Q` z2l?V#*lD6G@87d!%;6_s9Z?RqT7^G&c*ukF&K`pBfUko=Q&5+wbZ&3Tc$K3ey+p`w zztt#+j!dflxyMngV4z3>Zt_M&S~#Q^Oc82rHzWcl>7w!zgwObvf_9>i}tES z-q?Q!CC-4oY!Nr5y~l4|_;&pWs%WC6Q%_DK`@ZzM!hGuy?T>4sahyQ5xz4G7T!c%V zZb9{BG@nY|3JRb9`|(^C3~kR;IjYGdI1;!ag`}e22>iCyiVvmZ;lv0R2MIB_LFq|hNc2b6`t066YjEv-mjwq8%{-hB zVsqd9+Y8|l%?8_P!m*{##k!dC@uul?S@2Tl&J7$T7L^NV zZHKKk>juLgO20wc_LbJ$!-ewYIsS05vB90*Ztp5RsDmLmO)zROKHJZKV|zR7jcxD?8)q_T@^uEKt3e2V54)Eo|V4qNn`a9Dx&ZcOOWYvrt`pEDl|$m?M}K z`N@L5B)?dnnq*75JuLPk+N!ri{zZAI(xR%fbk0z&=1XzxMC{UvIKHt5_?J&w!7M&w z&#^OV8_X_)rl=3S0KzHKZD$>FhXgA~mGj~u(q5_dk4%pxG?vR%EAHs`I)9aPk}I9! zOVzz)L|YwM0FEbddeTxddAaZ!>L~b4*QNSVXVT|;MA^3paqI^vLx13u2KjT35&fY9 z+V8q`?sYf--}d~1_aqGI;5{5R*{Am=o8D2ZW9q$Pq{*~elzS}s9D{J!P-zc$a!0|S z?xAC&s6}pzzA51=bJww3kB;pL@2zX;y@xQlwX-?hOVxm4i~k);$fWh0mw&$BCmpLj z8-kLE^-}V#IQ*h)zW(zk(pmhbacD#N==rp?HnLI!WIo4lj_RQJ?jjEFt)>euZb(mH zCD)xv0Y@WlxTgtPDyg71VlTIS_FaRAR|!Ey2j1aR8g;c`^;!CVv;v?%grGNyel5!4 z5}*zP-V|~OY1_HV+{T?NVE zHD=$AYHjQHx}c|^8P{ljuJ1sSa52gp?kM^=$&so22H9$!iV7R{;9P++GY03aEtIhgWqP-4EikfK}py67`wC z64*kI&a0_KCa|oM<4Fkbtc@3fT7F?yh_fCskl*YKqK6U|zxh5#@0Nbq#r%z!4U~Ei zB;08`pV~Ew8?a+I4LrF2vzP;M+G1l9u78NwGdl}PAvtXas_{&U7Qq-sbOlf-8{o8^ z93Y_fd`rqpMXU?+f8EhgzK^q|lord_Cg5T_XAassB%WKABfMGF;^-X!3Mt36?30hE z1R#&@sG=Q&Nex@p4weI2`30|-vz2CP-jAr9>LdtCTXH^NccD|P-3l6Vcy1Tj`(=-} zGMwWrVw~}32qXk86Oj>DPO@1gDS$1jDYN5GJz9H?2!421ZVqcP@i;+|bhC~W{xGf$ z+IBC6LHNl+AWCtcL*02xij#k>DQyY^p%Y)#8>32hq}zZx4F^pJf$6JPP6sk=u!^8E z-X~9|Lc+;3Hdvfd02FK(Kl~>ZaSv(UIY8Dq`db zRlTY~UgDOS`xjq-GqG9NiMp*WJS^R7a_np0x|YSV?D)hkHd+CD*@vr}Mkd89p1(>S z;`Kj${H3>=c7tuDueVnmZYAL)f~2;(T!k|h8m_J;Rn85&Yt}x-UBmJAgz9NM-5p!` z>BZ%>@!kGx!JyySf}l^Umsobs&EQtg4WYc3HMiN&=8u>-R@0C8^vFQ3;BNHV?lI)B zDh6i`#!9MaFDmzXE$~jV907cPQzADm~;#H!k@F?g+03{DaH97X&BP6^*Tm$~#av96|?kQbTP$iH;;K zCiC&TzRzbU(T;`_A{&N|GTv=**`F+WMt3S904iok0bAI3)8`(?ZQ8b|x?&j1j3}Ct z_x3`HBuIs7$#!?_JtSb*I1jUf+6BCvA9h(iGF44@ zSwc*;$ure6>$Oc;(%QyYIAo`=N{Q!D-1{0(jz8}@J>YFQCaOX88#J>Rj3~Ynh6)X}>fiPOl+-&HgQgNE z3~HWuI8xpmCC_%(IRhC+27N@IDZ>_B2@Esl5)O=@{ZQ4%i$P;$FxA*? zp1VQAVeZ=`MYuIXz+d{9y{iaa2o5^0w0wnPgRnnHzQ_N6+EoRIO>SUM&6%Vn=z<~u zwrh3e8toioiat|<4Q(abxZ4;v;1fnlT)Oc=07(*Mm9Ym{*(xh$j(ko+HW}cwRI}fT zaQ6T^Q1v3U(<3=s5Zn=_&nK~W*jtr5VHID3PgFs0@5YqzKT6P7!Md0!F|RP1u@eQh zOP0(2fPHPDekLnURR}^p@0MRogt7Hhrc}lYmkzJ-r%_H=?608yc#Pu)@CXqo1SQG7 z2e_Lhs;Gfi^zwZ>|HrE#s6*n~6)hvzc5S;JtIaj#=3XUDdYMPAE#!~*4@`vlP6-Wr z4+=CyUQhQ!`Be*H4#GaudNf3SB2o8#=D2ON3r6St@vy{=iq;MBHPGQlMS_O=I`sOh zN#h6_VmYTHVUFxiR^^`%8Sa=bEfxD|^L;nnRN8!@HDD6oHY5_eT>h%g?nG9-Z??ok+0r3jxg$w~rCqbUSr?~)ba zicDIN4@ux3dRh%Q=h;Oyk^2SO<;xpSJs9wQ%iPNbvNT%{R-xIptv5}&X5r6&r)Kyj zIcyaMfbTT*IxV=i8JxaNaGmpadOs;t86S^EZh>dQc-xqQ#|Ld-d<+=_pI5x1bEsK+ zNmr$I7c*eO2jXxyrakW0mS8)oPbp=^P36NSnu}z2sW+1&>#+$&xjJK|0FeT=C|Y{K zCRy3@-_mP#PmvRM?-wtXvFX`rgaYH-i~}ZpKlO5N4e+{y92APNsJCa>yT|5y+K3}? z0_648z^G&><6XZ!WDpyLC&(LKmu2uW=+I(NJt+iTI`d{<%j~c`u9!x^7q4C=0yUN~ z4rOFQ1g}YgY$)P+?p92;jP2|mXRmLgE8vHa5mZAlogv47D9&fufR8z>67lTw+6>3h z;I}`SwAJPNEPa&9^+X5*Ez*k4u|OGw;a)zuXFK3U+#lbD;qMQm6-eo<_4#0ApLu=k z>50DKuLXs5K725ci*LWPia}Y^A7zKXfLaCFs}RlOKANNI%I!Jwn3}LK$i+ej6HNAefK{#p1L2A(CMlXI3Fl7Q~arM>tlr8YFkH!ND z)*|7gU;DH(x!^$v=uA>Hy(YbrnGIc&jMx10n%&hxaxUHtE>{%cYg8kLl~Zq?9Azp& z>V-g-v5LW2I&Rdo?Vehq$XFxD8tu=!$zpy!1TV%lQWp@h&nbV=>kRyX(f?q`7b z1g7<#3m5wbGsi6jfRlr5JN+vN8(Q|HeisGk802NFA0%ATCNsM1RJ4G7E&=Mug~;T=ed8LAmiIUsE*q1#T;V`qaWHM8o8^{uqG-Xw&i2=(Us$s7}?)UoX0eFF;f;V zvqlfA%E2|zNq*tVZ)_VhjN}n+2{Cc9uK`uK5{Rp$Y@-rO<p>=n6CTUdz`(ey@$RuOAArpyF1LScJF)}mV3DulGcp!z~!4i?< zSbx`*_8-G~7M05Ga*Q5Y;qO#F@SMPMyN1N_5;O81WOiq%E*!CCCy;;MJ@UUrqOe1@TXS|ysF?BCf(#1m;eeLfOIZ4 zDgP=8D(^l~5O1YiaHR1i@LG*!3F`Ss26~vQ+s=j$L1nAtgL{;lfkr2q2nhAVpKCD? zHH5lXay%qEiPIr!QfFRHMkYRH%||ETC(sm|b}`6ev;Rr6n~Xbs#-%{XzO5!-52bbu z!AI3GrQFEr9YrO*OX?v^8jw5?+nE-5v434D-m14knhmeq*j8cPl(jTeW0JnxxIuk- zWVHI@$~=0X)x$fL$m&^w9AJj(x4?-As5>jFB>l*ZZfpSJSyl%r2egiYOZN_K#jkkY zKc1OjJ%YZLW^lux_|wXr8cS<)SE#u#_oI9qUaW2pi1+MDebQPz8d<8)VBjhsNZ;OO zx|li-J6`9rV2fEW@*oJALwR1Q$oqQ}G`VuTbg2;(K2T(4y7!&bXvJ9ftj3QA1-XNT zJkfZI%ST?076^tHy)6erpy>^|sZUi@SK;=RFS%wtUdoYK)qGlIva0AOXf*A42jc

JR`4TOjBPJVLk-qU=u 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 diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index 58a87c3be..bedfb3fa4 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -17,13 +17,30 @@ 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 +from gdsfactory.cell import cell +from glayout.flow.spice import Netlist +from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid # My own cell library from reconfig_inv import reconfig_inv import comp_dc -#@cell -def short_channel_tg( +def tg_netlist(pmos: Component, nmos: Component) -> Netlist: + # A: tg.input, i.e. PMOS & NMOS source + # Y: tg.output, i.e. PMOS & NMOS drain + # C: connected to tg.nmos.gate + # CBAR: connected to tg.pmos.gate + # VDD: connected to tg.pmos.body + # VSS: connected to tg.nmos.body + netlist = Netlist(circuit_name='tg', nodes=['VDD', 'VSS', 'A', 'Y', 'C', 'CBAR']) + #netlist.connect_netlist(pmos.info['netlist'], [('D', 'Y'), ('G', 'CBAR'), ('S', 'A'), ('PB', 'VDD')]) + #netlist.connect_netlist(nmos.info['netlist'], [('D', 'Y'), ('G', 'C'), ('S', 'A'), ('NB', 'VSS')]) + netlist.connect_netlist(pmos.info['netlist'], [('D', 'Y'), ('G', 'CBAR'), ('S', 'A')]) + netlist.connect_netlist(nmos.info['netlist'], [('D', 'Y'), ('G', 'C'), ('S', 'A')]) + return netlist + +@cell +def short_width_tg( pdk: MappedPDK, component_name: str, orientation_config: @@ -35,6 +52,7 @@ def short_channel_tg( add_pin: bool = True, # For LVS **kwargs ) -> Component: + # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS # 2) NMOS @@ -96,14 +114,15 @@ def short_channel_tg( comp_ref = align_comp_to_port(comp, prt, alignment=alignment) top_level.add(comp_ref) - return top_level + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + component.info['netlist'] = tg_netlist(pmos=pfet, nmos=nfet) + return component + -#@cell -def long_channel_tg( +@cell +def long_width_tg( pdk: MappedPDK, component_name: str, - orientation_config: - dict[str, Union[int, str]], pmos_width, pmos_length, nmos_width, @@ -112,111 +131,94 @@ def long_channel_tg( **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 + finger_num = math.ceil(pmos_width / comp_dc.tg_fet_width_base) + mos_width = comp_dc.tg_fet_width_base # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS # 2) NMOS 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) pfet_ref = prec_ref_center(pfet) nfet_ref = prec_ref_center(nfet) top_level.add(pfet_ref) top_level.add(nfet_ref) - # Placement + # Placement.step_1: + # a) To vertically flip the NMOS such that the its gate point toward the PMOS's gate + # b) To move the PMOS above the NMOS 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"]) - rename_ports_by_orientation(nfet_ref.mirror_y()) # To vertically flip the NMOS such that the its gate point toward the PMOS's gate + rename_ports_by_orientation(nfet_ref.mirror_y()) # pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) + # Placement.step_2: instantiation of the stacked vias to the source of every PMOS's finger + fet_source_finger_num = math.ceil((finger_num+1) / 2) + fet_drain_finger_num = finger_num+1-fet_source_finger_num + fet_source_fingerL_num = (fet_source_finger_num-1)/2 # excluding the centered one + fet_drain_fingerL_num = fet_drain_finger_num/2 + finger_col_num = fet_source_finger_num # A half of the fingers belongs to drain + finger_row_num = math.floor((mos_width*0.5) / (2*pdk.get_grule("met2")["min_width"]))-1 # To pave the stacked vias over all bottom half + print(f"finger_row_num: {finger_row_num}, finger_col_num: {finger_col_num}") + pmos_source_sdvias = list() + nmos_source_sdvias = list() + pmos_source_sdvias_ref = list() + nmos_source_sdvias_ref = list() + sdvias_row = [via_stack(pdk=pdk, glayer1="met2", glayer2="met3", fullbottom=True, fulltop=True) for i in range(finger_col_num)] + for row in range(finger_row_num): + pmos_source_sdvias.append(sdvias_row) + nmos_source_sdvias.append(sdvias_row) + + pmos_temp_ref = list() + nmos_temp_ref = list() + for col in range(finger_col_num): + temp_ref = prec_ref_center(pmos_source_sdvias[row][col]) + pmos_temp_ref.append(temp_ref) + temp_ref = prec_ref_center(nmos_source_sdvias[row][col]) + nmos_temp_ref.append(temp_ref) + + pmos_source_sdvias_ref.append(pmos_temp_ref) + nmos_source_sdvias_ref.append(nmos_temp_ref) + top_level.add(pmos_source_sdvias_ref[row][col] for col in range(finger_col_num)) + top_level.add(nmos_source_sdvias_ref[row][col] for col in range(finger_col_num)) + + # Placement.step_3: moving the all the stacked vias associated with the PMOS's source such that + # they are connected to the PMOS's source + centroid_index = math.floor(fet_source_finger_num/2) + y_offset = pdk.get_grule("met3")["min_separation"]+pdk.get_grule("met3")["min_width"] + x_s2d_offset = abs(pfet_ref.ports["multiplier_0_leftsd_array_row0_col0_bottom_via_S"].center[0]-pfet_ref.ports["multiplier_0_row0_col0_rightsd_array_row0_col0_bottom_via_S"].center[0]) + x_offset = x_s2d_offset*2 # Distance between one soure finger to another source finger at its left-/right-hand side is (S-to-D distance)*2 + for row in range(finger_row_num): + x_spacing = x_offset*centroid_index # initial value + for col in range(finger_col_num): + # Moving the positions of the stacked vias associated with the PMOS + pmos_source_sdvias_ref[row][col].movey(evaluate_bbox(nfet)[1]+mos_spacing-(y_offset*row)) + pmos_source_sdvias_ref[row][col].movex(x_spacing) + + # Moving the positions fo the stacked vias associated with NMOS + nmos_source_sdvias_ref[row][col].movey(y_offset*row) # In NMOS, the row_0 is exactly placed at the center position (0, 0), + # thereby no need for moving the stacked vias of row_0, i.e. movey by 0 + nmos_source_sdvias_ref[row][col].movex(x_spacing) + + x_spacing = x_spacing-x_offset - 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( + # 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 by placing a large MET2-layered rectangle + # b) PMOS.drain connected to NMOS.drain + source_connection = Component() + source_connection.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 + (nmos_source_sdvias_ref[0][finger_col_num-1].xmin, nmos_source_sdvias_ref[0][finger_col_num-1].ymin),#leftBottom_pos + (pmos_source_sdvias_ref[0][finger_col_num-1].xmin, pmos_source_sdvias_ref[0][finger_col_num-1].ymax),#leftTop_pos + (pmos_source_sdvias_ref[0][0].xmax, pmos_source_sdvias_ref[0][0].ymax),#rightTop_pos + (nmos_source_sdvias_ref[0][0].xmax, nmos_source_sdvias_ref[0][0].ymin) #rightBottom_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 + source_connection = top_level.add_ref(source_connection) 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_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") @@ -250,104 +252,11 @@ def long_channel_tg( alignment = ('c', 'b') if alignment is None else alignment comp_ref = align_comp_to_port(comp, prt, alignment=alignment) top_level.add(comp_ref) - - return top_level - -#@cell -def tg_with_ctrl( - pdk: MappedPDK, - component_name: str, - pmos_width, - pmos_length, - nmos_width, - nmos_length, - add_pin: bool = True, # For LVS - **kwargs -) -> Component: - # To prepare all necessary cells to construct a transmission gate, i.e. - # 1) transmission gate - # 2) Inverter - tg = tg_cell( - pdk=pdk, - component_name="tg", - orientation_config={"degree": 270}, - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length, - add_pin=False - ) - inv = reconfig_inv( - pdk=pdk, - component_name="gate_ctrl_inv", - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length, - orientation="horizontal", - add_pin=False - ) - - # Instantiation of the essential cells - top_level = Component(name=component_name) - tg_ref = prec_ref_center(tg) - inv_ref = prec_ref_center(inv) - top_level.add(tg_ref) - top_level.add(inv_ref) - - # Placement - mos_spacing = pdk.util_max_metal_seperation() - nwell_min_spacing = pdk.get_grule("nwell")["min_separation"] - inv_cell_width = inv_ref.xsize # or = evaluate_bbox(inv)[0] - tg_ref.movex(inv_cell_width + nwell_min_spacing) - - # Routing - # 1) PMOS of the TG is switched on/off by the inverter's output - # 2) NMOS of the TG is switched on/off by an external control signal connected to inverter's input port as well - top_level << smart_route(pdk, inv_ref.ports["pmos_multiplier_0_drain_E"], tg_ref.ports["pmos_multiplier_0_gate_W"]) - top_level << straight_route(pdk, inv_ref.ports["nmos_multiplier_0_gate_S"], tg_ref.ports["nmos_multiplier_0_gate_S"], glayer1="met3") - - # Adding the ports - top_level.add_ports(tg_ref.get_ports_list(), prefix="tg_") - top_level.add_ports(inv_ref.get_ports_list(), prefix="inv_") - if add_pin == True: - # Add pins w/ labels for LVS - top_level.unlock() - pin_info = list() # list that contains all port and component information - met1_pin=(pdk.get_glayer("met1")[0], 20) - met1_label=(pdk.get_glayer("met1")[0], 5) - port_size = (0.24, 0.24) - # --- 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"tg_nmos_drain_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"tg_pmos_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) - pin_info.append((C_pin, top_level.ports.get(f"inv_nmos_gate_N"), None)) - # --- Port: VDD - VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VDD_pin.add_label(text="VDD", layer=met1_label) - pin_info.append((VDD_pin, top_level.ports.get(f"inv_pmos_drain_E"), None)) - # --- Port: VSS - VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VSS_pin.add_label(text="VSS", layer=met1_label) - pin_info.append((VSS_pin, top_level.ports.get(f"inv_nmos_source_W"), ('r', 't'))) - - # Move everythin to position - for comp, prt, alignment in pin_info: - alignment = ('c', 'b') if alignment is None else alignment - comp_ref = align_comp_to_port(comp, prt, alignment=alignment) - top_level.add(comp_ref) - - return top_level + component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + component.info['netlist'] = tg_netlist(pmos=pfet, nmos=nfet) + return component -#@cell def reconfig_tg( pdk: MappedPDK, component_name, @@ -360,19 +269,20 @@ 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 >= comp_dc.tg_channel_width_base: # Long-channel PMOS and NMOS - tg = long_channel_tg( + elif (pmos_width % comp_dc.tg_fet_width_factor) != 0: + raise ValueError(f"PCell constraint: the widths of PMOS and NMOS must be multiple of {comp_dc.tg_fet_width_factor} (the given width: {pmos_width})") + elif pmos_width >= comp_dc.tg_fet_width_base: # Long-width PMOS and NMOS + tg = long_width_tg( pdk=pdk, component_name=component_name, - orientation_config={"nmos_degree": 180, "pmos_degree": 0}, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, add_pin=True ) - else: # Short-channel PMOS and NMOS - tg = short_channel_tg( + else: # Short-width PMOS and NMOS + tg = short_width_tg( pdk=pdk, component_name=component_name, orientation_config={"degree": 270}, From 6d7956460cacff5441fb39e3befd3d905809aeed Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sat, 23 Nov 2024 10:05:06 +0000 Subject: [PATCH 20/21] Modify the netlist gen for the transmission gate --- .../transmission_gate_saltychip/eval.py | 4 +- .../transmission_gate.py | 46 ++++++++++++++++++- 2 files changed, 47 insertions(+), 3 deletions(-) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py index 601503473..004737730 100644 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py @@ -32,14 +32,14 @@ def basic_tg_eval(): magic_drc_result = sky130.drc_magic( layout=tg_dut, design_name=tg_dut.name, - output_file=f"{DRC_RPT_DIR}/{tg_dut.name}_drc.rpt" + output_file=f"{DRC_RPT_DIR}/{tg_dut.name}_2_drc.rpt" ) print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result) print("--------------------------------------") netgen_lvs_result = sky130.lvs_netgen( layout=tg_dut, design_name=tg_dut.name, - output_file_path=f"{LVS_RPT_DIR}/{tg_dut.name}_lvs.rpt", + output_file_path=f"{LVS_RPT_DIR}/{tg_dut.name}_2_lvs.rpt", copy_intermediate_files=True ) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py index bedfb3fa4..4f6414e2f 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py @@ -25,6 +25,7 @@ from reconfig_inv import reconfig_inv import comp_dc +''' def tg_netlist(pmos: Component, nmos: Component) -> Netlist: # A: tg.input, i.e. PMOS & NMOS source # Y: tg.output, i.e. PMOS & NMOS drain @@ -38,6 +39,43 @@ def tg_netlist(pmos: Component, nmos: Component) -> Netlist: netlist.connect_netlist(pmos.info['netlist'], [('D', 'Y'), ('G', 'CBAR'), ('S', 'A')]) netlist.connect_netlist(nmos.info['netlist'], [('D', 'Y'), ('G', 'C'), ('S', 'A')]) return netlist +''' + +def transmission_gate_netlist( + pdk: MappedPDK, + width: float, + multipliers: int, + length: float, + subckt_only: Optional[bool] = False +) -> Netlist: + if length is None: + length = pdk.get_grule('poly')['min_width'] + if width is None: + width = 3 + mtop = multipliers if subckt_only else 1 + model_pmos = pdk.models['pfet'] + model_nmos = pdk.models['nfet'] + print(f"model_pmos: {model_pmos}") + source_netlist = """.subckt {circuit_name} {nodes} """ + f'l={length} w={width} m={mtop} ' + """ +XM1 Y CBAR A {model_pmos} l={{l}} w={{w}} m={{m}} +XM2 Y C A {model_nmos} l={{l}} w={{w}} m={{m}}""" + source_netlist += "\n.ends {circuit_name}" + + instance_format = "X{name} {nodes} {circuit_name} l={length} w={width} m={mult}" + + return Netlist( + circuit_name='tg', + nodes=['Y', 'C', 'CBAR', 'A'], + source_netlist=source_netlist, + instance_format=instance_format, + parameters={ + 'model_pmos': model_pmos, + 'model_nmos': model_nmos, + 'width': width, + 'length': length, + 'mult': multipliers + } + ) @cell def short_width_tg( @@ -254,7 +292,13 @@ def long_width_tg( top_level.add(comp_ref) component = component_snap_to_grid(rename_ports_by_orientation(top_level)) - component.info['netlist'] = tg_netlist(pmos=pfet, nmos=nfet) + + component.info['netlist'] = transmission_gate_netlist( + pdk, + width=kwargs.get('width', pmos_width), length=kwargs.get('length', pmos_length), multipliers=1, + subckt_only=True + ) + #component.info['netlist'] = tg_netlist(pmos=pfet, nmos=nfet) return component def reconfig_tg( From 0fcd05adeefd41ebbed945483b1cb5e3edcf9cf1 Mon Sep 17 00:00:00 2001 From: tsengs0 Date: Sun, 24 Nov 2024 19:20:06 +0000 Subject: [PATCH 21/21] Contributor: Team SaltyChip, Chipathon 2024 Add the directory of building the layout of transmission-gate PCell with GDS, Magic DRC and LVS results --- .../elementary/transmission_gate/README.md | 186 ++++++++ .../elementary/transmission_gate/__init__.py | 4 + .../elementary/transmission_gate/eval.py | 57 +++ .../gds/tg_cell_471429cf.gds | Bin 0 -> 77596 bytes .../tg_cell_471429cf_20241124185925_drc.rpt} | 2 +- .../tg_cell_471429cf_20241124185925_lvs.rpt} | 34 +- .../transmission_gate}/transmission_gate.py | 282 +++++++---- .../transmission_gate_saltychip/README.md | 36 -- .../transmission_gate_saltychip/__init__.py | 4 - .../transmission_gate_saltychip/comp_dc.py | 5 - .../transmission_gate_saltychip/eval.py | 92 ---- .../mimcap_array.py | 451 ------------------ .../reconfig_inv.py | 202 -------- 13 files changed, 446 insertions(+), 909 deletions(-) create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/README.md create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/__init__.py create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/eval.py create mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/gds/tg_cell_471429cf.gds rename openfasoc/generators/glayout/glayout/flow/blocks/{transmission_gate_saltychip/regression/drc/long_width_tg_3f598baa_drc.rpt => elementary/transmission_gate/regression/drc/tg_cell_471429cf_20241124185925_drc.rpt} (57%) rename openfasoc/generators/glayout/glayout/flow/blocks/{transmission_gate_saltychip/regression/lvs/long_width_tg_3f598baa_lvs.rpt => elementary/transmission_gate/regression/lvs/tg_cell_471429cf_20241124185925_lvs.rpt} (65%) rename openfasoc/generators/glayout/glayout/flow/blocks/{transmission_gate_saltychip => elementary/transmission_gate}/transmission_gate.py (53%) delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py delete mode 100644 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py delete mode 100755 openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/README.md new file mode 100644 index 000000000..489f1e42e --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/README.md @@ -0,0 +1,186 @@ + +# PCell of transmission gate +- Contributor: Team SaltyChip (from Chipathon 2024) + + +## Glayout Source codes (1) + +- **Function:** short_width_tg +- **Description/Purpose:** to build a layout of the transmission gate without multifinger transistors +- **Source file:** transmission_gate.py + +``` +def short_width_tg( + pdk: MappedPDK, + component_name: str = "tg", + with_substrate_tap: bool = False, + fet_min_width: float = 3, + pmos_width: float = 3, + pmos_length: float = 0.15, + nmos_width: float = 3, + nmos_length: float = 0.15, + add_pin: bool = True, # For LVS + **kwargs +) -> Component: +``` +| Parameter | Type | Description | Default | Constraint/Limit | +| --- | --- | --- | --- | --- | +| pdk | MappedPDK | To select the target PDK | | sky130 or gf180mcu | +| component_name | string | The component name of the instantiated PCell | tg | | +| fet_min_width | float | A constraint to specify the mimimum width of each PMOS/NMOS inside the PCell | 3 (unit: um) | fet_min_width >= 2 | +| pmos_width | float | Width of the PMOS in the underlying PCell | 3 (unit: um) | pmos_width = fet_min_width | +| pmos_length | float | Length of the PMOS in the underlying PCell | 0.15 (unit: um) | pmos_length = 0.15 | +| nmos_width | float |Width of the NMOS in the underlying PCell | 3 (unit: um) | float | nmos_width = fet_min_width | +| nmos_length | float | Length of the NMOS in the underlying PCell | 0.15 (unit: um) | nmos_length = 0.15 | +| with_substrate_tap | bool | To add substrate tap surrounding the top level of the PCell if it is set True | False | | +| add_pin | bool | To add the pins with labels for the top level of the PCell (for the LVS) if it is set True | True | | + +--- + +## Glayout Source codes (2) + +- **Function:** long_width_tg +- **Description/Purpose:** to build an interdigitized layout of the transmission gate when the width of the underlying trasistors is relatively long +- **Source file:** transmission_gate.py + +``` +def long_width_tg( + pdk: MappedPDK, + component_name: str = "tg", + fet_min_width: float = 3, + pmos_width: float = 12, + pmos_length: float = 0.15, + nmos_width: float = 12, + nmos_length: float = 0.15, + with_substrate_tap: bool = True, + add_pin: bool = True, # For LVS + **kwargs +) -> Component: +``` +| Parameter | Type | Description | Default | Constraint/Limit | +| --- | --- | --- | --- | --- | +| pdk | MappedPDK | To select the target PDK | | sky130 or gf180mcu | +| component_name | string | The component name of the instantiated PCell | tg | | +| fet_min_width | float | A constraint to specify the mimimum width of each PMOS/NMOS inside the PCell | 3 (unit: um) | fet_min_width >= 2 | +| pmos_width | float | Width of the PMOS in the underlying PCell | 12 (unit: um) | **pmos_width** must be a multiple of **fet_min_width*4** | +| pmos_length | float | Length of the PMOS in the underlying PCell | 0.15 (unit: um) | pmos_length = 0.15 | +| nmos_width | float |Width of the NMOS in the underlying PCell | 12 (unit: um) | **nmos_width** must be a multiple of **fet_min_width*4** | +| nmos_length | float | Length of the NMOS in the underlying PCell | 0.15 (unit: um) | nmos_length = 0.15 | +| add_pin | bool | To add the pins with labels for the top level of the PCell (for the LVS) if it is set True | True | | +| with_substrate_tap | bool | To add substrate tap surrounding the top level of the PCell if it is set True | False | | + +--- + +## Glayout Source codes (3) + +- **Function:** tg_cell +- **Description/Purpose:** a generic function to build a layout of the transmission gate in an either single-finger or multifinger fashion depeending on the specified widht of PMOS/NMOS +- **Source file:** transmission_gate.py + +``` +def tg_cell( + pdk: MappedPDK, + component_name: str = "tg", + fet_min_width: float = 3, + pmos_width: float = 6, + pmos_length: float = 0.15, + nmos_width: float = 6, + nmos_length: float = 0.15, + add_pin: bool = True, # For LVS + with_substrate_tap: bool = True, + **kwargs +) -> Component: +``` +| Parameter | Type | Description | Default | Constraint/Limit | +| --- | --- | --- | --- | --- | +| pdk | MappedPDK | To select the target PDK | | sky130 or gf180mcu | +| component_name | string | The component name of the instantiated PCell | tg | | +| fet_min_width | float | A constraint to specify the mimimum width of each PMOS/NMOS inside the PCell | 3 (unit: um) | fet_min_width >= 2 | +| pmos_width | float | Width of the PMOS in the underlying PCell | 12 (unit: um) | **pmos_width** must be equal to **fet_min_width** or a multiple of **fet_min_width*4** | +| pmos_length | float | Length of the PMOS in the underlying PCell | 0.15 (unit: um) | pmos_length = 0.15 | +| nmos_width | float |Width of the NMOS in the underlying PCell | 12 (unit: um) | **nmos_width** must be equal to **fet_min_width** or a multiple of **fet_min_width*4** | +| nmos_length | float | Length of the NMOS in the underlying PCell | 0.15 (unit: um) | nmos_length = 0.15 | +| add_pin | bool | To add the pins with labels for the top level of the PCell (for the LVS) if it is set True | True | | +| with_substrate_tap | bool | To add substrate tap surrounding the top level of the PCell if it is set True | False | | + +--- + +## Example code of evaluating the PCell + +In this example, a Python file, **eval.py** created under the directory **transmission_gate**, is wrote as follow which diplays the GDS and the check the DRC and LVS results. + +``` +from datetime import datetime +import subprocess +#from glayout.flow.pdk.gf180_mapped import gf180 +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 +import transmission_gate as tg + +TARGET_PDK = sky130 +PWD_OUTPUT = subprocess.run(['pwd'], capture_output=True, text=True) +GDS_DIR = PWD_OUTPUT.stdout.strip() + "/gds" +DRC_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/drc" +LVS_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/lvs" + +pmos_width = 12 +pmos_length = 0.15 +nmos_width = 12 +nmos_length = 0.15 +fet_min_width = 3 + +def basic_tg_eval(): + tg_dut = tg.tg_cell( + pdk=TARGET_PDK, + component_name="tg", + fet_min_width=fet_min_width, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + with_substrate_tap=True, + add_pin=True + ) + + tg_dut.show() + print(tg_dut.info["netlist"].generate_netlist()) + tg_dut.write_gds(f"{GDS_DIR}/{tg_dut.name}.gds") + + now = datetime.now() # Get the current date and time + regression_id = now.strftime('%Y%m%d%H%M%S') # Format the date and time without spaces + + magic_drc_result = sky130.drc_magic( + layout=tg_dut, + design_name=tg_dut.name, + output_file=f"{DRC_RPT_DIR}/{tg_dut.name}_{regression_id}_drc.rpt" + ) + print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result) + print("--------------------------------------") + netgen_lvs_result = sky130.lvs_netgen( + layout=tg_dut, + design_name=tg_dut.name, + output_file_path=f"{LVS_RPT_DIR}/{tg_dut.name}_{regression_id}_lvs.rpt", + copy_intermediate_files=True + ) + +def main(): + basic_tg_eval() + +if __name__ == "__main__": + main() +``` + +--- + +## Progress (until 24/11/2024) + +- ToDo list +- Transmission gate + - [x] Layout + - [x] Add ports w/ labels onto the layout (for the subsequent LVS) + - [x] DRC of the layout w/o error (Magic) + - [ ] DRC of the layout w/o error (Klayout) + - [x] Create the baseline schematic of the created component + - [ ] LVS w/o error + - [x] Document about the PCell specification + - [ ] PEX and create the testbench + - [ ] Verification gets passed \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/__init__.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/__init__.py new file mode 100644 index 000000000..2e5c967f8 --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/__init__.py @@ -0,0 +1,4 @@ +from glayout.flow.blocks.elementary.transmission_gate.transmission_gate import transmission_gate_netlist +from glayout.flow.blocks.elementary.transmission_gate.transmission_gate import short_width_tg +from glayout.flow.blocks.elementary.transmission_gate.transmission_gate import long_width_tg +from glayout.flow.blocks.elementary.transmission_gate.transmission_gate import tg_cell \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/eval.py new file mode 100644 index 000000000..e3ab98b8e --- /dev/null +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/eval.py @@ -0,0 +1,57 @@ +from datetime import datetime +import subprocess +#from glayout.flow.pdk.gf180_mapped import gf180 +from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 +import transmission_gate as tg + +TARGET_PDK = sky130 +PWD_OUTPUT = subprocess.run(['pwd'], capture_output=True, text=True) +GDS_DIR = PWD_OUTPUT.stdout.strip() + "/gds" +DRC_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/drc" +LVS_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/lvs" + +pmos_width = 12 +pmos_length = 0.15 +nmos_width = 12 +nmos_length = 0.15 +fet_min_width = 3 + +def basic_tg_eval(): + tg_dut = tg.tg_cell( + pdk=TARGET_PDK, + component_name="tg", + fet_min_width=fet_min_width, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + with_substrate_tap=True, + add_pin=True + ) + + tg_dut.show() + print(tg_dut.info["netlist"].generate_netlist()) + tg_dut.write_gds(f"{GDS_DIR}/{tg_dut.name}.gds") + + now = datetime.now() # Get the current date and time + regression_id = now.strftime('%Y%m%d%H%M%S') # Format the date and time without spaces + + magic_drc_result = sky130.drc_magic( + layout=tg_dut, + design_name=tg_dut.name, + output_file=f"{DRC_RPT_DIR}/{tg_dut.name}_{regression_id}_drc.rpt" + ) + print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result) + print("--------------------------------------") + netgen_lvs_result = sky130.lvs_netgen( + layout=tg_dut, + design_name=tg_dut.name, + output_file_path=f"{LVS_RPT_DIR}/{tg_dut.name}_{regression_id}_lvs.rpt", + copy_intermediate_files=True + ) + +def main(): + basic_tg_eval() + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/gds/tg_cell_471429cf.gds b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/gds/tg_cell_471429cf.gds new file mode 100644 index 0000000000000000000000000000000000000000..5723b19f9ff50124190d2f8776f1dfaf7bc87714 GIT binary patch literal 77596 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 |sky130_fd_pr__pfet_01v8 (8->1) -sky130_fd_pr__nfet_01v8 (4->1) |sky130_fd_pr__nfet_01v8 (8->1) -Number of devices: 2 |Number of devices: 2 -Number of nets: 6 **Mismatch** |Number of nets: 5 **Mismatch** +sky130_fd_pr__pfet_01v8 (6->3) |sky130_fd_pr__pfet_01v8 (4->1) **Mismatch* +sky130_fd_pr__nfet_01v8 (6->3) |sky130_fd_pr__nfet_01v8 (4->1) **Mismatch* +Number of devices: 6 **Mismatch** |Number of devices: 2 **Mismatch** +Number of nets: 10 **Mismatch** |Number of nets: 6 **Mismatch** --------------------------------------------------------------------------------------- NET mismatches: Class fragments follow (with fanout counts): -Circuit 1: long_width_tg_3f598baa |Circuit 2: long_width_tg_3f598baa +Circuit 1: tg_cell_471429cf |Circuit 2: tg_cell_471429cf --------------------------------------------------------------------------------------- -Net: w_n697_603# |Net: B - sky130_fd_pr__pfet_01v8/4 = 1 | sky130_fd_pr__pfet_01v8/4 = 1 - | sky130_fd_pr__nfet_01v8/4 = 1 +Net: w_n715_603# |Net: VDD + sky130_fd_pr__pfet_01v8/4 = 3 | sky130_fd_pr__pfet_01v8/4 = 1 | -Net: (no pins) |(no matching net) - sky130_fd_pr__nfet_01v8/4 = 1 | +Net: a_n877_n684# |Net: VSS + sky130_fd_pr__nfet_01v8/4 = 3 | sky130_fd_pr__nfet_01v8/4 = 1 --------------------------------------------------------------------------------------- Netlists do not match. Subcircuit pins: -Circuit 1: long_width_tg_3f598baa |Circuit 2: long_width_tg_3f598baa +Circuit 1: tg_cell_471429cf |Circuit 2: tg_cell_471429cf -------------------------------------------|------------------------------------------- Cell pin lists are equivalent. -Device classes long_width_tg_3f598baa and long_width_tg_3f598baa are equivalent. +Device classes tg_cell_471429cf and tg_cell_471429cf are equivalent. Final result: Netlists do not match. diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py similarity index 53% rename from openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py rename to openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py index 4f6414e2f..f70a86aaa 100755 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/transmission_gate.py +++ b/openfasoc/generators/glayout/glayout/flow/blocks/elementary/transmission_gate/transmission_gate.py @@ -20,26 +20,7 @@ from gdsfactory.cell import cell from glayout.flow.spice import Netlist from glayout.flow.pdk.util.snap_to_grid import component_snap_to_grid - -# My own cell library -from reconfig_inv import reconfig_inv -import comp_dc - -''' -def tg_netlist(pmos: Component, nmos: Component) -> Netlist: - # A: tg.input, i.e. PMOS & NMOS source - # Y: tg.output, i.e. PMOS & NMOS drain - # C: connected to tg.nmos.gate - # CBAR: connected to tg.pmos.gate - # VDD: connected to tg.pmos.body - # VSS: connected to tg.nmos.body - netlist = Netlist(circuit_name='tg', nodes=['VDD', 'VSS', 'A', 'Y', 'C', 'CBAR']) - #netlist.connect_netlist(pmos.info['netlist'], [('D', 'Y'), ('G', 'CBAR'), ('S', 'A'), ('PB', 'VDD')]) - #netlist.connect_netlist(nmos.info['netlist'], [('D', 'Y'), ('G', 'C'), ('S', 'A'), ('NB', 'VSS')]) - netlist.connect_netlist(pmos.info['netlist'], [('D', 'Y'), ('G', 'CBAR'), ('S', 'A')]) - netlist.connect_netlist(nmos.info['netlist'], [('D', 'Y'), ('G', 'C'), ('S', 'A')]) - return netlist -''' +from glayout.flow.primitives.guardring import tapring def transmission_gate_netlist( pdk: MappedPDK, @@ -57,8 +38,8 @@ def transmission_gate_netlist( model_nmos = pdk.models['nfet'] print(f"model_pmos: {model_pmos}") source_netlist = """.subckt {circuit_name} {nodes} """ + f'l={length} w={width} m={mtop} ' + """ -XM1 Y CBAR A {model_pmos} l={{l}} w={{w}} m={{m}} -XM2 Y C A {model_nmos} l={{l}} w={{w}} m={{m}}""" +XM1 Y C A VDD {model_pmos} l={{l}} w={{w}} m={{m}} +XM2 Y CBAR A VSS {model_nmos} l={{l}} w={{w}} m={{m}}""" source_netlist += "\n.ends {circuit_name}" instance_format = "X{name} {nodes} {circuit_name} l={length} w={width} m={mult}" @@ -77,16 +58,16 @@ def transmission_gate_netlist( } ) -@cell +#@cell def short_width_tg( pdk: MappedPDK, - component_name: str, - orientation_config: - dict[str, Union[int, str]], - pmos_width, - pmos_length, - nmos_width, - nmos_length, + component_name: str = "tg", + with_substrate_tap: bool = False, + fet_min_width: float = 3, + pmos_width: float = 3, + pmos_length: float = 0.15, + nmos_width: float = 3, + nmos_length: float = 0.15, add_pin: bool = True, # For LVS **kwargs ) -> Component: @@ -94,36 +75,117 @@ def short_width_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_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 + pfet = pmos(pdk=pdk, gate_rmult=1, with_tie=False, with_substrate_tap=False, with_dummy=(True, True), width=pmos_width, length=pmos_length) + nfet = nmos(pdk=pdk, gate_rmult=1, with_tie=False, with_dnwell=False, with_substrate_tap=False, with_dummy=(True, True), width=nmos_width, length=nmos_length) top_level = Component(name=component_name) pfet_ref = prec_ref_center(pfet) nfet_ref = prec_ref_center(nfet) top_level.add(pfet_ref) top_level.add(nfet_ref) - # Placement + # Placement (1) + # a) To vertically flip the NMOS such that the its gate point toward the PMOS's gate + # b) To move the PMOS above the NMOS mos_spacing = pdk.util_max_metal_seperation() - if orientation_config["degree"] != None: - pfet_ref.rotate(orientation_config["degree"]) - nfet_ref.rotate(orientation_config["degree"]) + rename_ports_by_orientation(nfet_ref.mirror_y()) pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) - # 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_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met2") # "in" of the TG - top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_source_E"], glayer1="met2") # "out" of the TG - # Add the ports aligned with the basic PMOS and NMOS top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + + # Placement (2): + # a) Add a bunch of met1-to-met2 vias attached to the mcron-layered points inside the source of PMOS/NMOS + # b) Add a bunch of met1-to-met2 vias attached to the mcron-layered points inside the drain of PMOS/NMOS + fet_source_finger_num = 1 + fet_drain_finger_num = 1 + finger_col_num = 1 + finger_row_num = math.floor((fet_min_width*0.5) / (2*pdk.get_grule("met2")["min_width"]))-1 # To pave the stacked vias over all bottom half + pmos_source_sdvias = list() + nmos_source_sdvias = list() + pmos_drain_sdvias = list() + nmos_drain_sdvias = list() + pmos_source_sdvias_ref = list() + nmos_source_sdvias_ref = list() + pmos_drain_sdvias_ref = list() + nmos_drain_sdvias_ref = list() + sdvias_row = [via_stack(pdk=pdk, glayer1="met2", glayer2="met3", fullbottom=True, fulltop=True) for i in range(finger_col_num)] + for row in range(finger_row_num): + pmos_source_sdvias.append(sdvias_row) + nmos_source_sdvias.append(sdvias_row) + pmos_drain_sdvias.append(sdvias_row) + nmos_drain_sdvias.append(sdvias_row) + + pmos_source_cols_ref = list() + nmos_source_cols_ref = list() + pmos_drain_cols_ref = list() + nmos_drain_cols_ref = list() + for col in range(finger_col_num): + # For source terminals of the PMOS and NMOS + temp_ref = prec_ref_center(pmos_source_sdvias[row][col]) + pmos_source_cols_ref.append(temp_ref) + temp_ref = prec_ref_center(nmos_source_sdvias[row][col]) + nmos_source_cols_ref.append(temp_ref) + # For drain terminals of the PMOS and NMOS + temp_ref = prec_ref_center(pmos_drain_sdvias[row][col]) + pmos_drain_cols_ref.append(temp_ref) + temp_ref = prec_ref_center(nmos_drain_sdvias[row][col]) + nmos_drain_cols_ref.append(temp_ref) + + pmos_source_sdvias_ref.append(pmos_source_cols_ref) + nmos_source_sdvias_ref.append(nmos_source_cols_ref) + pmos_drain_sdvias_ref.append(pmos_drain_cols_ref) + nmos_drain_sdvias_ref.append(nmos_drain_cols_ref) + top_level.add(pmos_source_sdvias_ref[row][col] for col in range(finger_col_num)) + top_level.add(nmos_source_sdvias_ref[row][col] for col in range(finger_col_num)) + top_level.add(pmos_drain_sdvias_ref[row][col] for col in range(finger_col_num)) + top_level.add(nmos_drain_sdvias_ref[row][col] for col in range(finger_col_num)) + # Placement (3): + # a) Move all the a part of particular stacked vias such that they are connected to the source of PMOS/NMOS + # b) Move all the a part of particular stacked vias such that they are connected to the drain of PMOS/NMOS + y_offset = pdk.get_grule("met3")["min_separation"]+pdk.get_grule("met3")["min_width"] + x_offset = abs(top_level.ports["pmos_multiplier_0_leftsd_array_row0_col0_bottom_via_N"].center[0]-pfet_ref.center[0]) + for row in range(finger_row_num): + # Moving the positions of the stacked vias associated with the PMOS + pmos_source_sdvias_ref[row][0].movex(-x_offset) + pmos_source_sdvias_ref[row][0].movey(evaluate_bbox(nfet)[1]+mos_spacing-(y_offset*row)) + pmos_drain_sdvias_ref[row][0].movex(x_offset) + pmos_drain_sdvias_ref[row][0].movey(evaluate_bbox(nfet)[1]+mos_spacing-(y_offset*row)) + + # Moving the positions fo the stacked vias associated with NMOS + nmos_source_sdvias_ref[row][0].movex(-x_offset) + nmos_source_sdvias_ref[row][0].movey(y_offset*row) + nmos_drain_sdvias_ref[row][0].movex(x_offset) + nmos_drain_sdvias_ref[row][0].movey(y_offset*row) + + # Routing + # a) PMOS.source connected to NMOS.source by placing a large MET2-layered rectangle + # b) PMOS.drain connected to NMOS.drain by placing a large MET2-layered rectangle + print("nmos_source_sdvias_ref.len: ", nmos_source_sdvias_ref) + sdvias_connection = Component() + sdvias_connection.add_polygon( + [ + (nmos_source_sdvias_ref[0][finger_col_num-1].xmin, nmos_source_sdvias_ref[0][finger_col_num-1].ymin),#leftBottom_pos + (pmos_source_sdvias_ref[0][finger_col_num-1].xmin, pmos_source_sdvias_ref[0][finger_col_num-1].ymax),#leftTop_pos + (pmos_source_sdvias_ref[0][0].xmax, pmos_source_sdvias_ref[0][0].ymax),#rightTop_pos + (nmos_source_sdvias_ref[0][0].xmax, nmos_source_sdvias_ref[0][0].ymin) #rightBottom_pos + ], + layer=pdk.get_glayer("met3") + ) + sdvias_connection.add_polygon( + [ + (nmos_drain_sdvias_ref[0][finger_col_num-1].xmin, nmos_drain_sdvias_ref[0][finger_col_num-1].ymin),#leftBottom_pos + (pmos_drain_sdvias_ref[0][finger_col_num-1].xmin, pmos_drain_sdvias_ref[0][finger_col_num-1].ymax),#leftTop_pos + (pmos_drain_sdvias_ref[0][0].xmax, pmos_drain_sdvias_ref[0][0].ymax),#rightTop_pos + (nmos_drain_sdvias_ref[0][0].xmax, nmos_drain_sdvias_ref[0][0].ymin) #rightBottom_pos + ], + layer=pdk.get_glayer("met3") + ) + sdvias_connection_ref = top_level.add_ref(sdvias_connection) + + # Add pins w/ labels for LVS if add_pin == True: - # Add pins w/ labels for LVS top_level.unlock() pin_info = list() # list that contains all port and component information met1_pin=(pdk.get_glayer("met1")[0], 20) @@ -132,15 +194,15 @@ def short_width_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_W"), ('r', 't'))) # --- 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"pmos_drain_S"), None)) + pin_info.append((Y_pin, top_level.ports.get(f"nmos_drain_E"), ('l', 't'))) # --- 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) - pin_info.append((C_pin, top_level.ports.get(f"nmos_gate_N"), None)) + pin_info.append((C_pin, top_level.ports.get(f"nmos_gate_S"), None)) # --- Port: CBAR, i.e. gate control to the PMOS CBAR_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() CBAR_pin.add_label(text="CBAR", layer=met1_label) @@ -152,52 +214,65 @@ def short_width_tg( comp_ref = align_comp_to_port(comp, prt, alignment=alignment) top_level.add(comp_ref) - component = component_snap_to_grid(rename_ports_by_orientation(top_level)) - component.info['netlist'] = tg_netlist(pmos=pfet, nmos=nfet) - return component + # Add substrate tap + if with_substrate_tap: + substrate_tap = tapring(pdk, enclosed_rectangle=pdk.snap_to_2xgrid(evaluate_bbox(top_level.flatten(),padding=pdk.util_max_metal_seperation()))) + substrate_tap_ref = top_level << movey(substrate_tap,destination=pdk.snap_to_2xgrid(top_level.flatten().center[1],snap4=True)) + top_level.add_ports(substrate_tap_ref.get_ports_list(),prefix="substratetap_") + top_level = component_snap_to_grid(rename_ports_by_orientation(top_level)) + top_level.info['netlist'] = transmission_gate_netlist( + pdk, + width=kwargs.get('width', pmos_width), length=kwargs.get('length', pmos_length), multipliers=1, + subckt_only=True + ) + top_level.info['netlist'].generate_netlist() + return top_level -@cell + +#@cell def long_width_tg( pdk: MappedPDK, - component_name: str, - pmos_width, - pmos_length, - nmos_width, - nmos_length, + component_name: str = "tg", + fet_min_width: float = 3, + pmos_width: float = 12, + pmos_length: float = 0.15, + nmos_width: float = 12, + nmos_length: float = 0.15, + with_substrate_tap: bool = True, 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_fet_width_base) - mos_width = comp_dc.tg_fet_width_base + finger_num = math.ceil(pmos_width / fet_min_width) # To prepare all necessary cells to construct a transmission gate, i.e. # 1) PMOS # 2) NMOS - 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) + pfet = pmos(pdk=pdk, multipliers=1, fingers=finger_num, interfinger_rmult=1, gate_rmult=1, with_tie=False, with_substrate_tap=False, with_dummy=(True, True), width=fet_min_width, length=pmos_length) + nfet = nmos(pdk=pdk, multipliers=1, fingers=finger_num, interfinger_rmult=1, gate_rmult=1, with_tie=False, with_dnwell=False, with_substrate_tap=False, with_dummy=(True, True), width=fet_min_width, length=nmos_length) top_level = Component(name=component_name) pfet_ref = prec_ref_center(pfet) nfet_ref = prec_ref_center(nfet) top_level.add(pfet_ref) top_level.add(nfet_ref) - # Placement.step_1: - # a) To vertically flip the NMOS such that the its gate point toward the PMOS's gate - # b) To move the PMOS above the NMOS + # Placement (1) + # a) To vertically flip the NMOS such that the its gate point toward the PMOS's gate + # b) To move the PMOS above the NMOS mos_spacing = pdk.util_max_metal_seperation() rename_ports_by_orientation(nfet_ref.mirror_y()) # pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) - # Placement.step_2: instantiation of the stacked vias to the source of every PMOS's finger + # Placement (2): + # a) Add a bunch of met1-to-met2 vias attached to the mcron-layered points inside the source of PMOS/NMOS fet_source_finger_num = math.ceil((finger_num+1) / 2) fet_drain_finger_num = finger_num+1-fet_source_finger_num fet_source_fingerL_num = (fet_source_finger_num-1)/2 # excluding the centered one fet_drain_fingerL_num = fet_drain_finger_num/2 finger_col_num = fet_source_finger_num # A half of the fingers belongs to drain - finger_row_num = math.floor((mos_width*0.5) / (2*pdk.get_grule("met2")["min_width"]))-1 # To pave the stacked vias over all bottom half - print(f"finger_row_num: {finger_row_num}, finger_col_num: {finger_col_num}") + finger_row_num = math.floor((fet_min_width*0.5) / (2*pdk.get_grule("met2")["min_width"]))-1 # To pave the stacked vias over all bottom half +# print(f"finger_row_num: {finger_row_num}, finger_col_num: {finger_col_num}") pmos_source_sdvias = list() nmos_source_sdvias = list() pmos_source_sdvias_ref = list() @@ -220,8 +295,8 @@ def long_width_tg( top_level.add(pmos_source_sdvias_ref[row][col] for col in range(finger_col_num)) top_level.add(nmos_source_sdvias_ref[row][col] for col in range(finger_col_num)) - # Placement.step_3: moving the all the stacked vias associated with the PMOS's source such that - # they are connected to the PMOS's source + # Placement (3): + # a) Move all the a part of particular stacked vias such that they are connected to the source of PMOS/NMOS centroid_index = math.floor(fet_source_finger_num/2) y_offset = pdk.get_grule("met3")["min_separation"]+pdk.get_grule("met3")["min_width"] x_s2d_offset = abs(pfet_ref.ports["multiplier_0_leftsd_array_row0_col0_bottom_via_S"].center[0]-pfet_ref.ports["multiplier_0_row0_col0_rightsd_array_row0_col0_bottom_via_S"].center[0]) @@ -261,8 +336,8 @@ def long_width_tg( top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") + # Add pins w/ labels for LVS if add_pin == True: - # Add pins w/ labels for LVS top_level.unlock() pin_info = list() # list that contains all port and component information met1_pin=(pdk.get_glayer("met1")[0], 20) @@ -279,7 +354,7 @@ def long_width_tg( # --- 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) - pin_info.append((C_pin, top_level.ports.get(f"nmos_gate_N"), None)) + pin_info.append((C_pin, top_level.ports.get(f"nmos_gate_S"), None)) # --- Port: CBAR, i.e. gate control to the PMOS CBAR_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() CBAR_pin.add_label(text="CBAR", layer=met1_label) @@ -290,50 +365,63 @@ def long_width_tg( alignment = ('c', 'b') if alignment is None else alignment comp_ref = align_comp_to_port(comp, prt, alignment=alignment) top_level.add(comp_ref) - - component = component_snap_to_grid(rename_ports_by_orientation(top_level)) + + # Add substrate tap + if with_substrate_tap: + substrate_tap = tapring(pdk, enclosed_rectangle=pdk.snap_to_2xgrid(evaluate_bbox(top_level.flatten(),padding=pdk.util_max_metal_seperation()))) + substrate_tap_ref = top_level << movey(substrate_tap,destination=pdk.snap_to_2xgrid(top_level.flatten().center[1],snap4=True)) + top_level.add_ports(substrate_tap_ref.get_ports_list(),prefix="substratetap_") - component.info['netlist'] = transmission_gate_netlist( + top_level = component_snap_to_grid(rename_ports_by_orientation(top_level)) + top_level.info['netlist'] = transmission_gate_netlist( pdk, - width=kwargs.get('width', pmos_width), length=kwargs.get('length', pmos_length), multipliers=1, + width=kwargs.get('width', pmos_width), length=kwargs.get('length', pmos_length), multipliers=finger_num, subckt_only=True ) - #component.info['netlist'] = tg_netlist(pmos=pfet, nmos=nfet) - return component + top_level.info['netlist'].generate_netlist() -def reconfig_tg( + return top_level + +@cell +def tg_cell( pdk: MappedPDK, - component_name, - pmos_width, - pmos_length, - nmos_width, - nmos_length, + component_name: str = "tg", + fet_min_width: float = 3, + pmos_width: float = 12, + pmos_length: float = 0.15, + nmos_width: float = 12, + nmos_length: float = 0.15, add_pin: bool = True, # For LVS + with_substrate_tap: bool = True, **kwargs ) -> Component: if pmos_width != nmos_width: raise ValueError("PCell constraint: the widths of PMOS and NMOS must be identical") - elif (pmos_width % comp_dc.tg_fet_width_factor) != 0: - raise ValueError(f"PCell constraint: the widths of PMOS and NMOS must be multiple of {comp_dc.tg_fet_width_factor} (the given width: {pmos_width})") - elif pmos_width >= comp_dc.tg_fet_width_base: # Long-width PMOS and NMOS - tg = long_width_tg( - pdk=pdk, - component_name=component_name, - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length, - add_pin=True - ) + elif pmos_width > fet_min_width: # Long-width PMOS and NMOS + if (pmos_width % (fet_min_width*4)) != 0: + raise ValueError(f"PCell constraint: the widths of PMOS and NMOS must be a multiple of {fet_min_width*4} um, however the given width is {pmos_width} um") + else: + tg = long_width_tg( + pdk=pdk, + component_name=component_name, + fet_min_width=fet_min_width, + pmos_width=pmos_width, + pmos_length=pmos_length, + nmos_width=nmos_width, + nmos_length=nmos_length, + with_substrate_tap=True, + add_pin=True + ) else: # Short-width PMOS and NMOS tg = short_width_tg( pdk=pdk, component_name=component_name, - orientation_config={"degree": 270}, + fet_min_width=fet_min_width, pmos_width=pmos_width, pmos_length=pmos_length, nmos_width=nmos_width, nmos_length=nmos_length, + with_substrate_tap=True, add_pin=True ) diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md deleted file mode 100644 index 22bafe394..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# Transmission gate block for SAR A/D converter -- Team: SaltyChip -- Design (our target): DAC for 6-bit A/D converter -- Progress: ongoing, 03/11/2024 - -| Design File | Description | Remark | -| --- | --- | --- | -| inv_lib.py | Layout generation of inverter for controlling the transmission gate's PMOS and NMOS | | -| transmission_gate.py | Layout generation of a transmission gate | The layout is still under construction | -| mimcap_array.py | Layout generation of a 8x8 MIM capacitor array | Transmission gate combined with a MIM capacitor array is the aim in this project | - ---- - -Submission of PR Draft (deadline: 24/11/2024) - -- ToDo list -- Transmission gate - - [x] Layout - - [ ] Add ports w/ labels onto the layout (for the subsequent LVS) - - [ ] DRC of the layout w/o error (Magic) - - [ ] DRC of the layout w/o error (Klayout) - - [ ] Create the baseline schematic of the created component - - [ ] LVS w/o error - - [ ] Document about the PCell specification - - [ ] PEX and create the testbench - - [ ] Verification gets passed -- MIMI capacitor array - - [x] Layout - - [ ] Add ports w/ labels onto the layout (for the subsequent LVS) - - [ ] DRC of the layout w/o error (Magic) - - [ ] DRC of the layout w/o error (Klayout) - - [ ] Create the baseline schematic of the created component - - [ ] LVS w/o error - - [ ] Document about the PCell specification - - [ ] PEX and create the testbench - - [ ] Verification gets passed \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py deleted file mode 100644 index 813e096a6..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/__init__.py +++ /dev/null @@ -1,4 +0,0 @@ -from glayout.flow.blocks.transmission_gate_saltychip.inv_lib import reconfig_inv -from glayout.flow.blocks.transmission_gate_saltychip.transmission_gate import tg_with_inv -from glayout.flow.blocks.transmission_gate_saltychip.cell_config import add_port_lvs -from glayout.flow.blocks.transmission_gate_saltychip.eval import main diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py deleted file mode 100644 index 5b9a59b20..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/comp_dc.py +++ /dev/null @@ -1,5 +0,0 @@ -def initialise(): - global inv_fet_width_base, tg_fet_width_base, tg_fet_width_factor - inv_fet_width_base = 3.0 - tg_fet_width_base = 3.0 - tg_fet_width_factor = tg_fet_width_base*4 \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py deleted file mode 100644 index 004737730..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/eval.py +++ /dev/null @@ -1,92 +0,0 @@ -import subprocess -#from glayout.flow.pdk.gf180_mapped import gf180 -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" -DRC_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/drc" -LVS_RPT_DIR = PWD_OUTPUT.stdout.strip() + "/regression/lvs" - -pmos_width = 12.0*1 -pmos_length = 0.15 -nmos_width = 12.0*1 -nmos_length = 0.15 - -def basic_tg_eval(): - tg_dut = tg.reconfig_tg( - pdk=TARGET_PDK, - component_name="tg", - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length, - add_pin=True - ) - - 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"{DRC_RPT_DIR}/{tg_dut.name}_2_drc.rpt" - ) - print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result) - print("--------------------------------------") - netgen_lvs_result = sky130.lvs_netgen( - layout=tg_dut, - design_name=tg_dut.name, - output_file_path=f"{LVS_RPT_DIR}/{tg_dut.name}_2_lvs.rpt", - copy_intermediate_files=True - ) - -def gate_ctrl_inv_eval(): - gate_ctrl_inv = reconfig_inv.reconfig_inv( - pdk=TARGET_PDK, - component_name="gate_ctrl_inv", - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length, - add_pin=True - ) - gate_ctrl_inv.show() - gate_ctrl_inv.write_gds(f"{GDS_DIR}/{gate_ctrl_inv.name}.gds") - magic_drc_result = sky130.drc_magic( - layout=gate_ctrl_inv, - design_name=gate_ctrl_inv.name#, - #output_file=f"{absolute_path}/{gate_ctrl_inv.name}.rpt" - ) - print(f"Magic DRC result ({gate_ctrl_inv.name}): \n", magic_drc_result) - print("--------------------------------------") - -def tg_with_ctrl_eval(): - tg_dut = tg.tg_with_ctrl( - pdk=TARGET_PDK, - component_name="tg_with_ctrl", - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length - ) - 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_dut.name}.rpt" - ) - print(f"Magic DRC result ({tg_dut.name}): \n", magic_drc_result) - print("--------------------------------------") - -def main(): - basic_tg_eval() - #gate_ctrl_inv_eval() - #tg_with_ctrl_eval() - -if __name__ == "__main__": - comp_dc.initialise() - main() \ No newline at end of file diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py deleted file mode 100644 index 0b87f2310..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/mimcap_array.py +++ /dev/null @@ -1,451 +0,0 @@ -# Primitives -from glayout.flow.primitives.mimcap import mimcap -from glayout.flow.primitives.mimcap import mimcap_array -from glayout.flow.primitives.via_gen import via_stack, via_array - -# Standard -from glayout.flow.pdk.mappedpdk import MappedPDK -from glayout.flow.pdk.sky130_mapped import sky130_mapped_pdk as sky130 - -# gdsfactory -from gdsfactory import Component -from gdsfactory.cell import cell -from gdsfactory.components.rectangle import rectangle - -# Utility -from glayout.flow.pdk.util.comp_utils import evaluate_bbox, prec_center, prec_array, align_comp_to_port - -# Routing -from glayout.flow.routing.straight_route import straight_route -from glayout.flow.routing.c_route import c_route - -import copy - -def get_mimcap_layerconstruction_info(pdk: MappedPDK) -> tuple[str,str]: - """returns the glayer metal below and glayer metal above capmet - args: pdk - """ - capmettop = pdk.layer_to_glayer(pdk.get_grule("capmet")["capmettop"]) - capmetbottom = pdk.layer_to_glayer(pdk.get_grule("capmet")["capmetbottom"]) - pdk.has_required_glayers(["capmet",capmettop,capmetbottom]) - pdk.activate() - return capmettop, capmetbottom - -def create_6bit_dac_mimcap_array(pdk: MappedPDK): - """ - Creates a 6-bit DAC using an 8x8 MIM capacitor array with binary weighting. - """ - # Create the top-level component - dac_mim_cap = Component("6bit_DAC_MIMCAP_Array") - - ''' - # Define unit capacitor size (for example, 2x2 microns) - unit_size = [5.0, 5.0] - unit_mimcap = mimcap(pdk, size=unit_size) - - # Define bit weights for binary weighted capacitors - bit_weights = [32, 16, 8, 4, 2, 1] # From MSB to LSB - total_units = sum(bit_weights) - total_caps = 64 # 8x8 array - dummy_units = total_caps - total_units # Extra units as dummy - - # Generate common centroid indices for optimal matching - cap_indices = [(i, j) for i in range(8) for j in range(8)] - ''' - - # metal and via layers - met2 = pdk.get_glayer('met3') - met3_capmetbottom = pdk.get_glayer('met4') - met4_capmettop = pdk.get_glayer('met5') - via3 = pdk.get_glayer('via4') - mimcap_arr = Component("mimcap_arr") - #test_cap << rectangle(size=(1, 1), layer=via3) - mimcap_single_size = 5 - mimcap_single = mimcap(pdk, size=(mimcap_single_size,mimcap_single_size)) - rows_num = 8 - columns_num = 8 - mimcap_space = 10*pdk.get_grule("capmet")["min_separation"] - met4_width = pdk.get_grule("met5")["min_width"] - array_ref = mimcap_arr << prec_array(mimcap_single, rows=rows_num, columns=columns_num, spacing=2*[mimcap_space]) - mimcap_arr.add_ports(array_ref.get_ports_list()) - mim_metal_space = mimcap_space/9 - ##################### - port_pairs = list() - port_sides_pairs = list() - via_refs = list() - for rownum in range(rows_num): - for colnum in range(columns_num): - base_mimcap = f"row{rownum}_col{colnum}_" - right_mimcap = f"row{rownum}_col{colnum+1}_" - up_mimcap = f"row{rownum+1}_col{colnum}_" - capmetbottom = "met4" - capmettop = "met5" - - # Bottom Metal - level = "bottom_met_" - layer = capmetbottom - base_east_port = mimcap_arr.ports.get(base_mimcap+level+"E") - right_west_port = mimcap_arr.ports.get(right_mimcap+level+"W") - base_north_port = mimcap_arr.ports.get(base_mimcap+level+"N") - up_south_port = mimcap_arr.ports.get(up_mimcap+level+"S") - if rownum == rows_num-1 and colnum == columns_num-1: - pass #continue - elif rownum == rows_num-1: - port_pairs.append((base_east_port,right_west_port,layer)) - elif colnum == columns_num-1: - port_pairs.append((base_north_port,up_south_port,layer)) - else: - port_pairs.append((base_east_port,right_west_port,layer)) - port_pairs.append((base_north_port,up_south_port,layer)) - - # Top metal - level = "top_met_" - position_up = "up_" - position_down = "down_" - position_right = "right_" - position_left = "left_" - layer = capmettop - base_east_port = mimcap_arr.ports.get(base_mimcap+level+"E") - met4_distance_from_center = base_east_port.width/2 - pdk.get_grule(layer)["min_width"] - if base_east_port is not None: - base_east_port_up = base_east_port.copy() - base_east_port_up.name = base_mimcap+position_up+level+"E" - base_east_port_up.center[1] += met4_distance_from_center #(base_east_port_up.width/2 - pdk.get_grule(layer)["min_width"]) - base_east_port_up_space1 = base_east_port_up.copy() - base_east_port_up_space1.name = base_mimcap+position_up+level+"W" - base_east_port_up_space1.center[0] += mim_metal_space*1 - base_east_port_up_space4 = base_east_port_up.copy() - base_east_port_up_space4.name = base_mimcap+position_up+level+"W" - base_east_port_up_space4.center[0] += mim_metal_space*4 - base_east_port_down = base_east_port.copy() - base_east_port_down.name = base_mimcap+position_down+level+"E" - base_east_port_down.center[1] -= met4_distance_from_center #(base_north_port.width/2 - pdk.get_grule(layer)["min_width"]) - base_east_port_down_space1 = base_east_port_down.copy() - base_east_port_down_space1.name = base_mimcap+position_down+level+"W" - base_east_port_down_space1.center[0] += mim_metal_space*1 - base_east_port_down_space4 = base_east_port_down.copy() - base_east_port_down_space4.name = base_mimcap+position_down+level+"W" - base_east_port_down_space4.center[0] += mim_metal_space*4 - right_west_port = mimcap_arr.ports.get(right_mimcap+level+"W") - if right_west_port is not None: - right_west_port_up = right_west_port.copy() - right_west_port_up.name = right_mimcap+position_up+level+"W" - right_west_port_up.center[1] += met4_distance_from_center #(right_west_port_up.width/2 - pdk.get_grule(layer)["min_width"]) - right_west_port_up_space3 = right_west_port_up.copy() - right_west_port_up_space3.name = right_mimcap+position_up+level+"E" - right_west_port_up_space3.center[0] -= mim_metal_space*3 - right_west_port_up_space4 = right_west_port_up.copy() - right_west_port_up_space4.name = right_mimcap+position_up+level+"E" - right_west_port_up_space4.center[0] -= mim_metal_space*4 - right_west_port_up_space7 = right_west_port_up.copy() - right_west_port_up_space7.name = right_mimcap+position_up+level+"E" - right_west_port_up_space7.center[0] -= mim_metal_space*7 - right_west_port_down = right_west_port.copy() - right_west_port_down.name = right_mimcap+position_down+level+"W" - right_west_port_down.center[1] -= met4_distance_from_center #(right_west_port_down.width/2 - pdk.get_grule(layer)["min_width"]) - right_west_port_down_space3 = right_west_port_down.copy() - right_west_port_down_space3.name = right_mimcap+position_down+level+"E" - right_west_port_down_space3.center[0] -= mim_metal_space*3 - right_west_port_down_space4 = right_west_port_down.copy() - right_west_port_down_space4.name = right_mimcap+position_down+level+"E" - right_west_port_down_space4.center[0] -= mim_metal_space*4 - right_west_port_down_space7 = right_west_port_down.copy() - right_west_port_down_space7.name = right_mimcap+position_down+level+"E" - right_west_port_down_space7.center[0] -= mim_metal_space*7 - base_north_port = mimcap_arr.ports.get(base_mimcap+level+"N") - if base_north_port is not None: - base_north_port_right = base_north_port.copy() - base_north_port_right.name = base_mimcap+position_right+level+"N" - base_north_port_right.center[0] += met4_distance_from_center #(base_north_port_right.width/2 - pdk.get_grule(layer)["min_width"]) - base_north_port_right_space = base_north_port_right.copy() - base_north_port_right_space.name = base_mimcap+position_right+level+"S" - base_north_port_right_space.center[1] += mim_metal_space*4 - base_north_port_left = base_north_port.copy() - base_north_port_left.name = base_mimcap+position_left+level+"N" - base_north_port_left.center[0] -= met4_distance_from_center #(base_north_port_left.width/2 - pdk.get_grule(layer)["min_width"]) - base_north_port_left_space = base_north_port_left.copy() - base_north_port_left_space.name = base_mimcap+position_left+level+"S" - base_north_port_left_space.center[1] += mim_metal_space*4 - up_south_port = mimcap_arr.ports.get(up_mimcap+level+"S") - if up_south_port is not None: - up_south_port_right = up_south_port.copy() - up_south_port_right.name = base_mimcap+position_right+level+"S" - up_south_port_right.center[0] += met4_distance_from_center #(up_south_port_right.width/2 - pdk.get_grule(layer)["min_width"]) - up_south_port_right_space = up_south_port_right.copy() - up_south_port_right_space.name = base_mimcap+position_right+level+"N" - up_south_port_right_space.center[1] -= mim_metal_space*4 - up_south_port_left = up_south_port.copy() - up_south_port_left.name = base_mimcap+position_left+level+"S" - up_south_port_left.center[0] -= met4_distance_from_center #(up_south_port_left.width/2 - pdk.get_grule(layer)["min_width"]) - up_south_port_left_space = up_south_port_left.copy() - up_south_port_left_space.name = base_mimcap+position_left+level+"N" - up_south_port_left_space.center[1] -= mim_metal_space*4 - - ''' - if rownum in (0,1,2,4): - if colnum == 0: - base_west_side_port = mimcap_arr.ports.get(base_mimcap+level+"W") - base_west_side_port.name = base_mimcap+level+"westside_"+"W" - base_west_side_port.center - += met4_distance_from_center - else: - if colnum == 7: - ''' - - if rownum == 0: - # North and South - if colnum in (2,3,5,6): - port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) - port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) - port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) - port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) - else: - port_pairs.append((base_north_port_left,up_south_port_left,layer)) - port_pairs.append((base_north_port_right,up_south_port_right,layer)) - # West and East - if colnum in (5,6): #(1,7) - port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) - via_mimcap = via_stack(pdk, "met3", capmettop) - #via_mimcap = via_array(pdk, "met3", capmettop, size=(met4_width,met4_width), num_vias=(2,2), fullbottom=False) - via_refs.append(align_comp_to_port(via_mimcap, right_west_port_up_space7, ("c", "c"))) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - elif rownum == 1: - # North and South - if colnum in (1,2,4,5): - port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) - port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) - port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) - port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) - else: - port_pairs.append((base_north_port_left,up_south_port_left,layer)) - port_pairs.append((base_north_port_right,up_south_port_right,layer)) - # West and East - if colnum in (0,2,3,5): #(4,4) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) - elif colnum in (1,6): #(1,7) - port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) - elif colnum == 4: #(4,3) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - elif rownum == 2: - # North and South - if colnum in (0,1,2,3,4,5,7): - port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) - port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) - port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) - port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) - else: - port_pairs.append((base_north_port_left,up_south_port_left,layer)) - port_pairs.append((base_north_port_right,up_south_port_right,layer)) - # West and East - if colnum in (4,5): #(4,4) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) - elif colnum in (0,6): #(1,7) - port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) - elif colnum == 3: #(4,3) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - elif rownum == 3: - # North and South - if colnum in (0,1,2,3,5,6,7): - port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) - port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) - port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) - port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) - else: - port_pairs.append((base_north_port_left,up_south_port_left,layer)) - port_pairs.append((base_north_port_right,up_south_port_right,layer)) - # West and East - if colnum in (0,1,2,3): #(4,4) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - elif rownum == 4: - # North and South - if colnum in (0,2,3,4,5,6,7): - port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) - port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) - port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) - port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) - else: - port_pairs.append((base_north_port_left,up_south_port_left,layer)) - port_pairs.append((base_north_port_right,up_south_port_right,layer)) - # West and East - if colnum in (2,3): #(4,4) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) - elif colnum in (5,6): #(1,7) - port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) - elif colnum == 4: #(4,3) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - elif rownum == 5: - # North and South - if colnum in (2,3,5,6): - port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) - port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) - port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) - port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) - else: - port_pairs.append((base_north_port_left,up_south_port_left,layer)) - port_pairs.append((base_north_port_right,up_south_port_right,layer)) - # West and East - if colnum in (2,3,6): #(4,4) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) - elif colnum == 1: #(1,7) - port_pairs.append((base_east_port_up,base_east_port_up_space1,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space1,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space7,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space7,layer)) - elif colnum == 0: #(4,3) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - elif rownum == 6: - # North and South - if colnum in (1,2,4,5): - port_pairs.append((base_north_port_right,base_north_port_right_space,layer)) - port_pairs.append((base_north_port_left,base_north_port_left_space,layer)) - port_pairs.append((up_south_port_right,up_south_port_right_space,layer)) - port_pairs.append((up_south_port_left,up_south_port_left_space,layer)) - else: - port_pairs.append((base_north_port_left,up_south_port_left,layer)) - port_pairs.append((base_north_port_right,up_south_port_right,layer)) - # West and East - if colnum in (1,2,3,4,5,6): #(4,4) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) - elif colnum == 0: #(4,3) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - elif rownum == 7: - # West and East - if colnum == 1: #(4,4) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space4,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space4,layer)) - elif colnum == 0: #(4,3) - port_pairs.append((base_east_port_up,base_east_port_up_space4,layer)) - port_pairs.append((base_east_port_down,base_east_port_down_space4,layer)) - port_pairs.append((right_west_port_up,right_west_port_up_space3,layer)) - port_pairs.append((right_west_port_down,right_west_port_down_space3,layer)) - elif colnum == columns_num-1: - pass #continue - else: - port_pairs.append((base_east_port_up,right_west_port_up,layer)) - port_pairs.append((base_east_port_down,right_west_port_down,layer)) - - # metal2 - layer = "met3" - base_east_port_metal2_up = mimcap_arr.ports.get(base_mimcap+level+"E") - base_east_port_metal2_up.name = base_mimcap+"east_metal2_up" - base_east_port_metal2_up.center[0] += mim_metal_space*3 - base_east_port_metal2_up.center[1] += (met4_distance_from_center + met4_width/2) - base_east_port_metal2_up.orientation = 270 - base_east_port_metal2_up.layer = met2 - base_east_port_metal2_down = base_east_port_metal2_up.copy() - base_east_port_metal2_down.name = base_mimcap+"east_metal2_down" - if colnum == 4: - base_east_port_metal2_down.center[1] -= (mimcap_single_size*15/2 + mimcap_space*8) - else: - base_east_port_metal2_down.center[1] -= (mimcap_single_size*17/2 + mimcap_space*8) - port_pairs.append((base_east_port_metal2_up,base_east_port_metal2_down,layer)) - base_west_port_metal2_up = mimcap_arr.ports.get(base_mimcap+level+"W") - base_west_port_metal2_up.name = base_mimcap+"west_metal2_up" - base_west_port_metal2_up.center[0] -= mim_metal_space*3 - base_west_port_metal2_up.center[1] += (met4_distance_from_center + met4_width/2) - base_west_port_metal2_up.orientation = 270 - base_west_port_metal2_up.layer = met2 - base_west_port_metal2_down = base_west_port_metal2_up.copy() - base_west_port_metal2_down.name = base_mimcap+"west_metal2_down" - if colnum in (1,2,6,7): - base_west_port_metal2_down.center[1] -= (mimcap_single_size*15/2 + mimcap_space*8) - else: - base_west_port_metal2_down.center[1] -= (mimcap_single_size*17/2 + mimcap_space*8) - port_pairs.append((base_west_port_metal2_up,base_west_port_metal2_down,layer)) - - for port_pair in port_pairs: - mimcap_arr << straight_route(pdk, port_pair[0], port_pair[1], width=met4_width) - for via_ref in via_refs: - mimcap_arr.add(via_refs) - - cap_ref = dac_mim_cap.add_ref(mimcap_arr) - #cap_ref.movey(-30) - - - return dac_mim_cap - - - -# Create and show the DAC MIM capacitor array layout -dac_mimcap_component = create_6bit_dac_mimcap_array(sky130).show() diff --git a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py b/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py deleted file mode 100755 index 97ab884af..000000000 --- a/openfasoc/generators/glayout/glayout/flow/blocks/transmission_gate_saltychip/reconfig_inv.py +++ /dev/null @@ -1,202 +0,0 @@ -from typing import ClassVar, Optional, Any, Union, Literal, Iterable, TypedDict -#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 prec_ref_center, movex, movey, evaluate_bbox, align_comp_to_port -from gdsfactory import Component -from gdsfactory.components import rectangle -from glayout.flow.primitives.fet import pmos -from glayout.flow.primitives.fet import nmos -from glayout.flow.routing.straight_route import straight_route -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 - -import comp_dc - -#@cell -def short_channel_inv( - pdk: MappedPDK, - component_name, - pmos_width, - pmos_length, - nmos_width, - nmos_length, - orientation, - add_pin: bool = True, # For LVS - **kwargs -) -> Component: - # Create a top level component - top_level = Component(component_name) - # To prepare one PMOS and one NMOS for the subsequent inverter cell construction - pfet = pmos(pdk=pdk, gate_rmult=2, with_substrate_tap=False, with_dummy=(False, True), width=pmos_width, length=pmos_length) - nfet = nmos(pdk=pdk, gate_rmult=2, with_dnwell=False, with_substrate_tap=False, with_dummy=(True, False), width=nmos_width, length=nmos_length) - pfet.name="pmos" - nfet.name="nmos" - - # Instantiation of above PMOS and NMOS under the top level - pfet_ref = prec_ref_center(pfet) - nfet_ref = prec_ref_center(nfet) - top_level.add(pfet_ref) - top_level.add(nfet_ref) - - # Placement (relative move) - mos_spacing = pdk.util_max_metal_seperation(metal_levels=("met1", "met2", "met3", "met4", "met5")) - if(orientation=="horizontal"): - pfet_ref.rotate(90) - nfet_ref.rotate(90) - else: - pass - pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) - - # Routing - top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_E"], glayer1="met2") # connected by li1 - input_route = top_level << straight_route(pdk, pfet_ref.ports["multiplier_0_gate_W"], nfet_ref.ports["multiplier_0_gate_W"] , glayer1="met2") # connected by li1 - - # To add the ports - top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") - top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - - if add_pin == True: - # Add pins w/ labels for LVS - top_level.unlock() - pin_info = list() # list that contains all port and component information - met1_pin=(pdk.get_glayer("met1")[0], 20) - met1_label=(pdk.get_glayer("met1")[0], 5) - port_size = (0.24, 0.24) - # --- Port: A, i.e. input of the inverter - 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_gate_E"), None)) - # --- Port: Y, i.e. output of the inverver - 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_E"), None)) - # --- Port: VDD - VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VDD_pin.add_label(text="VDD", layer=met1_label) - pin_info.append((VDD_pin, top_level.ports.get(f"pmos_drain_E"), None)) - # --- Port: VSS - VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VSS_pin.add_label(text="VSS", layer=met1_label) - pin_info.append((VSS_pin, top_level.ports.get(f"nmos_source_W"), ('r', 't'))) - - # Move everythin to position - for comp, prt, alignment in pin_info: - alignment = ('c', 'b') if alignment is None else alignment - comp_ref = align_comp_to_port(comp, prt, alignment=alignment) - top_level.add(comp_ref) - - return top_level - -#@cell -def long_channel_inv( - pdk: MappedPDK, - component_name, - pmos_width, - pmos_length, - nmos_width, - nmos_length, - orientation_config: dict[str, Union[int, str]], - add_pin: bool = True, # For LVS - **kwargs -) -> Component: - # Create a top level component - top_level = Component(component_name) - # To prepare one PMOS and one NMOS for the subsequent inverter cell construction - pfet = pmos(pdk=pdk, gate_rmult=1, with_substrate_tap=False, with_dummy=(False, False), width=pmos_width, length=pmos_length) - nfet = nmos(pdk=pdk, gate_rmult=1, with_dnwell=False, with_substrate_tap=False, with_dummy=(False, False), width=nmos_width, length=nmos_length) - pfet.name="pmos" - nfet.name="nmos" - - # Instantiation of above PMOS and NMOS under the top level - pfet_ref = prec_ref_center(pfet) - nfet_ref = prec_ref_center(nfet) - top_level.add(pfet_ref) - top_level.add(nfet_ref) - - # Placement (relative move) - mos_spacing = pdk.util_max_metal_seperation(metal_levels=("met1", "met2", "met3", "met4", "met5")) - 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"]) - pfet_ref.movey(evaluate_bbox(nfet)[1] + mos_spacing) - - # Routing - top_level << c_route(pdk, pfet_ref.ports["multiplier_0_drain_E"], nfet_ref.ports["multiplier_0_drain_W"], cglayer="met3") # connected by li1 - top_level << smart_route(pdk, pfet_ref.ports["multiplier_0_gate_S"], nfet_ref.ports["multiplier_0_gate_S"]) # connected by li1 - - # To add the ports - top_level.add_ports(pfet_ref.get_ports_list(), prefix="pmos_") - top_level.add_ports(nfet_ref.get_ports_list(), prefix="nmos_") - - if add_pin == True: - # Add pins w/ labels for LVS - top_level.unlock() - pin_info = list() # list that contains all port and component information - met1_pin=(pdk.get_glayer("met1")[0], 20) - met1_label=(pdk.get_glayer("met1")[0], 5) - port_size = (0.24, 0.24) - # --- Port: A, i.e. input of the inverter - 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_gate_S"), None)) - # --- Port: Y, i.e. output of the inverver - 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_E"), None)) - # --- Port: VDD - VDD_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VDD_pin.add_label(text="VDD", layer=met1_label) - pin_info.append((VDD_pin, top_level.ports.get(f"pmos_drain_E"), None)) - # --- Port: VSS - VSS_pin=rectangle(layer=met1_pin, size=port_size, centered=True).copy() - VSS_pin.add_label(text="VSS", layer=met1_label) - pin_info.append((VSS_pin, top_level.ports.get(f"nmos_source_W"), ('r', 't'))) - - # Move everythin to position - for comp, prt, alignment in pin_info: - alignment = ('c', 'b') if alignment is None else alignment - comp_ref = align_comp_to_port(comp, prt, alignment=alignment) - top_level.add(comp_ref) - - return top_level - -#@cell -def reconfig_inv( - pdk, - component_name, - pmos_width, - pmos_length, - nmos_width, - nmos_length, - add_pin: bool = True, # For LVS - **kwargs -) -> Component: - if pmos_width != nmos_width: - raise ValueError("PCell constraint: the widths of PMOS and NMOS must be identical") - elif pmos_width >= comp_dc.inv_fet_width_base: # Long-channel PMOS and NMOS - inv = long_channel_inv( - pdk=pdk, - component_name=component_name, - orientation_config={"pmos_degree":0, "nmos_degree":180}, - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length, - add_pin=True - ) - else: # Short-channel PMOS and NMOS - inv = short_channel_inv( - pdk=pdk, - component_name=component_name, - orientation="horizontal", - pmos_width=pmos_width, - pmos_length=pmos_length, - nmos_width=nmos_width, - nmos_length=nmos_length, - add_pin=True - ) - - return inv \ No newline at end of file